From 092217ce2e38b200cda5d48b1ca7bf120a53f91d Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Mon, 27 Jul 2026 10:30:41 +0200 Subject: [PATCH 1/4] feat(google-cloud-serverless)!: Use `http.client` span op for GCP HTTP requests The endpoint-derived suffix fragmented grouping and was unbounded for non-`googleapis.com` endpoints. Service identity moves to the `server.address` attribute; `http.request.method` is now set as well. Ref: JS-3105 Co-Authored-By: Claude Opus 5 (1M context) --- packages/google-cloud-serverless/package.json | 1 + .../src/integrations/google-cloud-http.ts | 16 +++++++++++----- .../test/integrations/google-cloud-http.test.ts | 8 ++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) 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..6ca17effde0a 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, SERVER_ADDRESS } 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,11 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { ? startInactiveSpan({ name: `${httpMethod} ${reqOpts.uri}`, onlyIfParent: true, - op: `http.client.${identifyService(this.apiEndpoint)}`, + op: WEB_SERVER_HTTP_CLIENT_SPAN_OP, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', + [HTTP_REQUEST_METHOD]: httpMethod, + [SERVER_ADDRESS]: getServerAddress(this.apiEndpoint), }, }) : new SentryNonRecordingSpan(); @@ -67,8 +73,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..85ad5106e520 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 @@ -76,19 +76,23 @@ describe('GoogleCloudHttp tracing', () => { const resp = await bigquery.query('SELECT true AS foo'); expect(resp).toEqual([[{ foo: true }]]); expect(mockStartInactiveSpan).toBeCalledWith({ - op: 'http.client.bigquery', + op: 'http.client', name: 'POST /jobs', onlyIfParent: true, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', + 'http.request.method': 'POST', + 'server.address': 'bigquery.googleapis.com', }, }); expect(mockStartInactiveSpan).toBeCalledWith({ - op: 'http.client.bigquery', + op: 'http.client', name: expect.stringMatching(/^GET \/queries\/.+/), onlyIfParent: true, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', + 'http.request.method': 'GET', + 'server.address': 'bigquery.googleapis.com', }, }); }); From 7a82c493ed382100be4686c5c8d9b16c50bca859 Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Tue, 28 Jul 2026 13:09:53 +0200 Subject: [PATCH 2/4] use sentry.op --- .../src/integrations/google-cloud-http.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6ca17effde0a..b467a2da5e4a 100644 --- a/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts +++ b/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts @@ -1,5 +1,5 @@ import type * as common from '@google-cloud/common'; -import { HTTP_REQUEST_METHOD, SERVER_ADDRESS } from '@sentry/conventions/attributes'; +import { HTTP_REQUEST_METHOD, SENTRY_OP, SERVER_ADDRESS } from '@sentry/conventions/attributes'; import { WEB_SERVER_HTTP_CLIENT_SPAN_OP } from '@sentry/conventions/op'; import type { Client, IntegrationFn } from '@sentry/core'; import { @@ -58,8 +58,8 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { ? startInactiveSpan({ name: `${httpMethod} ${reqOpts.uri}`, onlyIfParent: true, - op: WEB_SERVER_HTTP_CLIENT_SPAN_OP, 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), From 006b1d0d0e0e548b43abcbf228b292e0d1b69de4 Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Tue, 28 Jul 2026 13:29:26 +0200 Subject: [PATCH 3/4] fix test --- .../test/integrations/google-cloud-http.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 85ad5106e520..8e347f982028 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 } 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,23 +78,23 @@ describe('GoogleCloudHttp tracing', () => { const resp = await bigquery.query('SELECT true AS foo'); expect(resp).toEqual([[{ foo: true }]]); expect(mockStartInactiveSpan).toBeCalledWith({ - op: 'http.client', 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', + [HTTP_REQUEST_METHOD]: 'POST', + [SERVER_ADDRESS]: 'bigquery.googleapis.com', }, }); expect(mockStartInactiveSpan).toBeCalledWith({ - op: 'http.client', 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', + [HTTP_REQUEST_METHOD]: 'GET', + [SERVER_ADDRESS]: 'bigquery.googleapis.com', }, }); }); From 75e0096cdec5736be785b4f2aefa924f538aef1e Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Tue, 28 Jul 2026 16:43:10 +0200 Subject: [PATCH 4/4] add url.full --- .../src/integrations/google-cloud-http.ts | 3 ++- .../test/integrations/google-cloud-http.test.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) 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 b467a2da5e4a..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,5 +1,5 @@ import type * as common from '@google-cloud/common'; -import { HTTP_REQUEST_METHOD, SENTRY_OP, SERVER_ADDRESS } from '@sentry/conventions/attributes'; +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 { @@ -63,6 +63,7 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', [HTTP_REQUEST_METHOD]: httpMethod, [SERVER_ADDRESS]: getServerAddress(this.apiEndpoint), + [URL_FULL]: reqOpts.uri, }, }) : new SentryNonRecordingSpan(); 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 8e347f982028..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,5 +1,5 @@ import { BigQuery } from '@google-cloud/bigquery'; -import { HTTP_REQUEST_METHOD, SENTRY_OP, SERVER_ADDRESS } from '@sentry/conventions/attributes'; +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'; @@ -85,6 +85,7 @@ describe('GoogleCloudHttp tracing', () => { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', [HTTP_REQUEST_METHOD]: 'POST', [SERVER_ADDRESS]: 'bigquery.googleapis.com', + [URL_FULL]: '/jobs', }, }); expect(mockStartInactiveSpan).toBeCalledWith({ @@ -95,6 +96,7 @@ describe('GoogleCloudHttp tracing', () => { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless', [HTTP_REQUEST_METHOD]: 'GET', [SERVER_ADDRESS]: 'bigquery.googleapis.com', + [URL_FULL]: expect.stringMatching(/^\/queries\/.+/), }, }); });