diff --git a/packages/google-cloud-serverless/package.json b/packages/google-cloud-serverless/package.json index 31e6a3d823b2..893c6c9b3894 100644 --- a/packages/google-cloud-serverless/package.json +++ b/packages/google-cloud-serverless/package.json @@ -41,6 +41,7 @@ "access": "public" }, "dependencies": { + "@sentry/conventions": "^0.16.0", "@sentry/core": "10.67.0", "@sentry/node": "10.67.0" }, diff --git a/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts b/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts index d3e6fe11655f..0852a53d540c 100644 --- a/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts +++ b/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts @@ -1,9 +1,13 @@ import type * as common from '@google-cloud/common'; +import { HTTP_REQUEST_METHOD, SENTRY_OP, SERVER_ADDRESS, URL_FULL } from '@sentry/conventions/attributes'; +import { WEB_SERVER_HTTP_CLIENT_SPAN_OP } from '@sentry/conventions/op'; import type { Client, IntegrationFn } from '@sentry/core'; import { defineIntegration, fill, getClient, + isURLObjectRelative, + parseStringToURLObject, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, } from '@sentry/core'; @@ -54,9 +58,12 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { ? startInactiveSpan({ name: `${httpMethod} ${reqOpts.uri}`, onlyIfParent: true, - op: `http.client.${identifyService(this.apiEndpoint)}`, attributes: { + [SENTRY_OP]: WEB_SERVER_HTTP_CLIENT_SPAN_OP, [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', + [HTTP_REQUEST_METHOD]: httpMethod, + [SERVER_ADDRESS]: getServerAddress(this.apiEndpoint), + [URL_FULL]: reqOpts.uri, }, }) : new SentryNonRecordingSpan(); @@ -67,8 +74,8 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { }; } -/** Identifies service by its base url */ -function identifyService(apiEndpoint: string): string { - const match = apiEndpoint.match(/^https:\/\/(\w+)\.googleapis.com$/); - return match?.[1] || apiEndpoint.replace(/^(http|https)?:\/\//, ''); +/** Extracts the host of the API endpoint the request is sent to */ +function getServerAddress(apiEndpoint: string): string { + const url = parseStringToURLObject(apiEndpoint); + return url && !isURLObjectRelative(url) ? url.host : apiEndpoint; } diff --git a/packages/google-cloud-serverless/test/integrations/google-cloud-http.test.ts b/packages/google-cloud-serverless/test/integrations/google-cloud-http.test.ts index f569a6980158..5f2e78905b47 100644 --- a/packages/google-cloud-serverless/test/integrations/google-cloud-http.test.ts +++ b/packages/google-cloud-serverless/test/integrations/google-cloud-http.test.ts @@ -1,4 +1,6 @@ import { BigQuery } from '@google-cloud/bigquery'; +import { HTTP_REQUEST_METHOD, SENTRY_OP, SERVER_ADDRESS, URL_FULL } from '@sentry/conventions/attributes'; +import { WEB_SERVER_HTTP_CLIENT_SPAN_OP } from '@sentry/conventions/op'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import { createTransport, NodeClient, setCurrentClient } from '@sentry/node'; import * as fs from 'fs'; @@ -76,19 +78,25 @@ describe('GoogleCloudHttp tracing', () => { const resp = await bigquery.query('SELECT true AS foo'); expect(resp).toEqual([[{ foo: true }]]); expect(mockStartInactiveSpan).toBeCalledWith({ - op: 'http.client.bigquery', name: 'POST /jobs', onlyIfParent: true, attributes: { + [SENTRY_OP]: WEB_SERVER_HTTP_CLIENT_SPAN_OP, [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', + [HTTP_REQUEST_METHOD]: 'POST', + [SERVER_ADDRESS]: 'bigquery.googleapis.com', + [URL_FULL]: '/jobs', }, }); expect(mockStartInactiveSpan).toBeCalledWith({ - op: 'http.client.bigquery', name: expect.stringMatching(/^GET \/queries\/.+/), onlyIfParent: true, attributes: { + [SENTRY_OP]: WEB_SERVER_HTTP_CLIENT_SPAN_OP, [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', + [HTTP_REQUEST_METHOD]: 'GET', + [SERVER_ADDRESS]: 'bigquery.googleapis.com', + [URL_FULL]: expect.stringMatching(/^\/queries\/.+/), }, }); });