From 874246bded216a5f8819b40b04c78ee544a8ddd9 Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Mon, 27 Jul 2026 10:42:19 +0200 Subject: [PATCH] feat(opentelemetry)!: Drop `.prefetch` suffix from inferred HTTP span ops OTel inference fabricated the unregistered `http.client.prefetch` / `http.server.prefetch` ops. Prefetch is request data, not an operation category, and is already on the span as `sentry.http.prefetch`. Ref: JS-3105 Co-Authored-By: Claude Opus 5 (1M context) --- .../src/utils/parseSpanDescription.ts | 29 +++++++++---------- .../test/utils/parseSpanDescription.test.ts | 22 +++++++++++++- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/packages/opentelemetry/src/utils/parseSpanDescription.ts b/packages/opentelemetry/src/utils/parseSpanDescription.ts index f47a0ab5b618..4831b86958c8 100644 --- a/packages/opentelemetry/src/utils/parseSpanDescription.ts +++ b/packages/opentelemetry/src/utils/parseSpanDescription.ts @@ -15,6 +15,11 @@ import { SENTRY_KIND, URL_FULL, } from '@sentry/conventions/attributes'; +import { + WEB_SERVER_HTTP_CLIENT_SPAN_OP, + WEB_SERVER_HTTP_SERVER_SPAN_OP, + WEB_SERVER_HTTP_SPAN_OP, +} from '@sentry/conventions/op'; import type { Span, SpanAttributes, TransactionSource } from '@sentry/core'; import { getSanitizedUrlString, @@ -139,27 +144,19 @@ export function descriptionForHttpMethod( { name, attributes }: { name: string; attributes: Attributes }, httpMethod: AttributeValue, ): SpanDescription { - const opParts = ['http']; const kind = attributes[SENTRY_KIND]; - switch (kind) { - case 'client': - opParts.push('client'); - break; - case 'server': - opParts.push('server'); - break; - } - - // Spans for HTTP requests we have determined to be prefetch requests will have a `.prefetch` postfix in the op - if (attributes['sentry.http.prefetch']) { - opParts.push('prefetch'); - } + const op = + kind === 'client' + ? WEB_SERVER_HTTP_CLIENT_SPAN_OP + : kind === 'server' + ? WEB_SERVER_HTTP_SERVER_SPAN_OP + : WEB_SERVER_HTTP_SPAN_OP; const { urlPath, url, query, fragment, hasRoute } = getSanitizedUrl(attributes); if (!urlPath) { - return { ...getUserUpdatedNameAndSource(name, attributes), op: opParts.join('.') }; + return { ...getUserUpdatedNameAndSource(name, attributes), op }; } const graphqlOperationsAttribute = attributes[SENTRY_GRAPHQL_OPERATION]; @@ -214,7 +211,7 @@ export function descriptionForHttpMethod( : getUserUpdatedNameAndSource(name, attributes); return { - op: opParts.join('.'), + op, description, source, data, diff --git a/packages/opentelemetry/test/utils/parseSpanDescription.test.ts b/packages/opentelemetry/test/utils/parseSpanDescription.test.ts index 46229b90ed9a..89e2d10b5f3c 100644 --- a/packages/opentelemetry/test/utils/parseSpanDescription.test.ts +++ b/packages/opentelemetry/test/utils/parseSpanDescription.test.ts @@ -386,7 +386,7 @@ describe('descriptionForHttpMethod', () => { }, 'test name', { - op: 'http.client.prefetch', + op: 'http.client', description: 'GET https://www.example.com/my-path', data: { url: 'https://www.example.com/my-path', @@ -394,6 +394,26 @@ describe('descriptionForHttpMethod', () => { source: 'url', }, ], + [ + 'works with prefetch server request', + 'GET', + { + [HTTP_METHOD]: 'GET', + [HTTP_URL]: 'https://www.example.com/my-path', + [HTTP_TARGET]: '/my-path', + 'sentry.http.prefetch': true, + [SENTRY_KIND]: 'server', + }, + 'test name', + { + op: 'http.server', + description: 'GET /my-path', + data: { + url: 'https://www.example.com/my-path', + }, + source: 'url', + }, + ], [ 'works with basic server POST', 'POST',