Skip to content

Commit c3bf82c

Browse files
msonnbclaude
andcommitted
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) <noreply@anthropic.com>
1 parent a754190 commit c3bf82c

4 files changed

Lines changed: 20 additions & 9 deletions

File tree

MIGRATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ Affected SDKs: All SDKs.
261261
Span operations (`sentry.op`) were aligned with the values defined in `@sentry/conventions`:
262262

263263
- `@sentry/node`: Firebase Functions spans now use `function.gcp` instead of `http.request`. The wrapper instruments all function trigger types (HTTP, Firestore, scheduler, storage), so a fixed HTTP op was wrong. The trigger type remains available on the `faas.trigger` attribute.
264+
- `@sentry/google-cloud-serverless`: `googleCloudHttpIntegration` spans now use `http.client` instead of `http.client.<service>`. The service is now identified by the new `server.address` attribute.
264265

265266
If you reference these operations in dashboards, alerts, or `beforeSendSpan`, update them to the new values.
266267

packages/google-cloud-serverless/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"access": "public"
4242
},
4343
"dependencies": {
44+
"@sentry/conventions": "^0.16.0",
4445
"@sentry/core": "10.67.0",
4546
"@sentry/node": "10.67.0"
4647
},

packages/google-cloud-serverless/src/integrations/google-cloud-http.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import type * as common from '@google-cloud/common';
2+
import { HTTP_REQUEST_METHOD, SENTRY_ORIGIN, SERVER_ADDRESS } from '@sentry/conventions/attributes';
3+
import { WEB_SERVER_HTTP_CLIENT_SPAN_OP } from '@sentry/conventions/op';
24
import type { Client, IntegrationFn } from '@sentry/core';
35
import {
46
defineIntegration,
57
fill,
68
getClient,
7-
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
9+
isURLObjectRelative,
10+
parseStringToURLObject,
811
SentryNonRecordingSpan,
912
} from '@sentry/core';
1013
import { startInactiveSpan } from '@sentry/node';
@@ -54,9 +57,11 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction {
5457
? startInactiveSpan({
5558
name: `${httpMethod} ${reqOpts.uri}`,
5659
onlyIfParent: true,
57-
op: `http.client.${identifyService(this.apiEndpoint)}`,
60+
op: WEB_SERVER_HTTP_CLIENT_SPAN_OP,
5861
attributes: {
59-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless',
62+
[SENTRY_ORIGIN]: 'auto.http.serverless',
63+
[HTTP_REQUEST_METHOD]: httpMethod,
64+
[SERVER_ADDRESS]: getServerAddress(this.apiEndpoint),
6065
},
6166
})
6267
: new SentryNonRecordingSpan();
@@ -67,8 +72,8 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction {
6772
};
6873
}
6974

70-
/** Identifies service by its base url */
71-
function identifyService(apiEndpoint: string): string {
72-
const match = apiEndpoint.match(/^https:\/\/(\w+)\.googleapis.com$/);
73-
return match?.[1] || apiEndpoint.replace(/^(http|https)?:\/\//, '');
75+
/** Extracts the host of the API endpoint the request is sent to */
76+
function getServerAddress(apiEndpoint: string): string {
77+
const url = parseStringToURLObject(apiEndpoint);
78+
return url && !isURLObjectRelative(url) ? url.host : apiEndpoint;
7479
}

packages/google-cloud-serverless/test/integrations/google-cloud-http.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,23 @@ describe('GoogleCloudHttp tracing', () => {
7676
const resp = await bigquery.query('SELECT true AS foo');
7777
expect(resp).toEqual([[{ foo: true }]]);
7878
expect(mockStartInactiveSpan).toBeCalledWith({
79-
op: 'http.client.bigquery',
79+
op: 'http.client',
8080
name: 'POST /jobs',
8181
onlyIfParent: true,
8282
attributes: {
8383
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless',
84+
'http.request.method': 'POST',
85+
'server.address': 'bigquery.googleapis.com',
8486
},
8587
});
8688
expect(mockStartInactiveSpan).toBeCalledWith({
87-
op: 'http.client.bigquery',
89+
op: 'http.client',
8890
name: expect.stringMatching(/^GET \/queries\/.+/),
8991
onlyIfParent: true,
9092
attributes: {
9193
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.serverless',
94+
'http.request.method': 'GET',
95+
'server.address': 'bigquery.googleapis.com',
9296
},
9397
});
9498
});

0 commit comments

Comments
 (0)