diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 9880e0ffb28e..8e4fd27370da 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -69,7 +69,7 @@ }, "dependencies": { "@opentelemetry/instrumentation-http": "0.53.0", - "@opentelemetry/semantic-conventions": "^1.25.1", + "@opentelemetry/semantic-conventions": "^1.27.0", "@rollup/plugin-commonjs": "26.0.1", "@sentry/core": "8.29.0", "@sentry/node": "8.29.0", diff --git a/packages/nextjs/src/server/index.ts b/packages/nextjs/src/server/index.ts index 1132a6e1eed2..cccbea7a1fa0 100644 --- a/packages/nextjs/src/server/index.ts +++ b/packages/nextjs/src/server/index.ts @@ -10,7 +10,12 @@ import { getDefaultIntegrations, init as nodeInit } from '@sentry/node'; import type { NodeClient, NodeOptions } from '@sentry/node'; import { GLOBAL_OBJ, logger } from '@sentry/utils'; -import { SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_ROUTE, SEMATTRS_HTTP_TARGET } from '@opentelemetry/semantic-conventions'; +import { + ATTR_HTTP_REQUEST_METHOD, + ATTR_HTTP_ROUTE, + SEMATTRS_HTTP_METHOD, + SEMATTRS_HTTP_TARGET, +} from '@opentelemetry/semantic-conventions'; import type { EventProcessor } from '@sentry/types'; import { DEBUG_BUILD } from '../common/debug-build'; import { devErrorSymbolicationEventProcessor } from '../common/devErrorSymbolicationEventProcessor'; @@ -150,8 +155,11 @@ export function init(options: NodeOptions): NodeClient | undefined { // because we didn't get the chance to do `suppressTracing`, since this happens outside of userland. // We need to drop these spans. if ( + // eslint-disable-next-line deprecation/deprecation typeof spanAttributes[SEMATTRS_HTTP_TARGET] === 'string' && + // eslint-disable-next-line deprecation/deprecation spanAttributes[SEMATTRS_HTTP_TARGET].includes('sentry_key') && + // eslint-disable-next-line deprecation/deprecation spanAttributes[SEMATTRS_HTTP_TARGET].includes('sentry_client') ) { samplingDecision.decision = false; @@ -168,8 +176,12 @@ export function init(options: NodeOptions): NodeClient | undefined { const rootSpanAttributes = spanToJSON(rootSpan).data; // Only hoist the http.route attribute if the transaction doesn't already have it - if (rootSpanAttributes?.[SEMATTRS_HTTP_METHOD] && !rootSpanAttributes?.[SEMATTRS_HTTP_ROUTE]) { - rootSpan.setAttribute(SEMATTRS_HTTP_ROUTE, spanAttributes['next.route']); + if ( + // eslint-disable-next-line deprecation/deprecation + (rootSpanAttributes?.[ATTR_HTTP_REQUEST_METHOD] || rootSpanAttributes?.[SEMATTRS_HTTP_METHOD]) && + !rootSpanAttributes?.[ATTR_HTTP_ROUTE] + ) { + rootSpan.setAttribute(ATTR_HTTP_ROUTE, spanAttributes['next.route']); } } diff --git a/packages/node/package.json b/packages/node/package.json index a77c1b56b215..63c6f719a2d4 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -87,9 +87,9 @@ "@opentelemetry/instrumentation-pg": "0.44.0", "@opentelemetry/instrumentation-redis-4": "0.42.0", "@opentelemetry/instrumentation-undici": "0.6.0", - "@opentelemetry/resources": "^1.25.1", - "@opentelemetry/sdk-trace-base": "^1.25.1", - "@opentelemetry/semantic-conventions": "^1.25.1", + "@opentelemetry/resources": "^1.26.0", + "@opentelemetry/sdk-trace-base": "^1.26.0", + "@opentelemetry/semantic-conventions": "^1.27.0", "@prisma/instrumentation": "5.19.1", "@sentry/core": "8.29.0", "@sentry/opentelemetry": "8.29.0", diff --git a/packages/node/src/integrations/tracing/koa.ts b/packages/node/src/integrations/tracing/koa.ts index 7db0225b6fc8..15ddc4658fa9 100644 --- a/packages/node/src/integrations/tracing/koa.ts +++ b/packages/node/src/integrations/tracing/koa.ts @@ -1,5 +1,5 @@ import { KoaInstrumentation } from '@opentelemetry/instrumentation-koa'; -import { SEMATTRS_HTTP_ROUTE } from '@opentelemetry/semantic-conventions'; +import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, @@ -29,7 +29,7 @@ export const instrumentKoa = generateInstrumentOnce( return; } const attributes = spanToJSON(span).data; - const route = attributes && attributes[SEMATTRS_HTTP_ROUTE]; + const route = attributes && attributes[ATTR_HTTP_ROUTE]; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const method: string = info?.context?.request?.method?.toUpperCase() || 'GET'; if (route) { diff --git a/packages/node/src/sdk/initOtel.ts b/packages/node/src/sdk/initOtel.ts index 37b94ebc439f..c5ec5367f68c 100644 --- a/packages/node/src/sdk/initOtel.ts +++ b/packages/node/src/sdk/initOtel.ts @@ -3,9 +3,9 @@ import { DiagLogLevel, diag } from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; import { - SEMRESATTRS_SERVICE_NAME, + ATTR_SERVICE_NAME, + ATTR_SERVICE_VERSION, SEMRESATTRS_SERVICE_NAMESPACE, - SEMRESATTRS_SERVICE_VERSION, } from '@opentelemetry/semantic-conventions'; import { SDK_VERSION } from '@sentry/core'; import { SentryPropagator, SentrySampler, SentrySpanProcessor } from '@sentry/opentelemetry'; @@ -130,9 +130,10 @@ export function setupOtel(client: NodeClient): BasicTracerProvider { const provider = new BasicTracerProvider({ sampler: new SentrySampler(client), resource: new Resource({ - [SEMRESATTRS_SERVICE_NAME]: 'node', + [ATTR_SERVICE_NAME]: 'node', + // eslint-disable-next-line deprecation/deprecation [SEMRESATTRS_SERVICE_NAMESPACE]: 'sentry', - [SEMRESATTRS_SERVICE_VERSION]: SDK_VERSION, + [ATTR_SERVICE_VERSION]: SDK_VERSION, }), forceFlushTimeoutMillis: 500, }); diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json index 688c5e01f2b6..cedb64423433 100644 --- a/packages/opentelemetry/package.json +++ b/packages/opentelemetry/package.json @@ -47,15 +47,15 @@ "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.25.1", "@opentelemetry/instrumentation": "^0.53.0", - "@opentelemetry/sdk-trace-base": "^1.25.1", - "@opentelemetry/semantic-conventions": "^1.25.1" + "@opentelemetry/sdk-trace-base": "^1.26.0", + "@opentelemetry/semantic-conventions": "^1.27.0" }, "devDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.25.1", "@opentelemetry/core": "^1.25.1", - "@opentelemetry/sdk-trace-base": "^1.25.1", - "@opentelemetry/semantic-conventions": "^1.25.1" + "@opentelemetry/sdk-trace-base": "^1.26.0", + "@opentelemetry/semantic-conventions": "^1.27.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/opentelemetry/src/propagator.ts b/packages/opentelemetry/src/propagator.ts index 4ed5a15532d2..387943cf9cf0 100644 --- a/packages/opentelemetry/src/propagator.ts +++ b/packages/opentelemetry/src/propagator.ts @@ -3,9 +3,8 @@ import { INVALID_TRACEID } from '@opentelemetry/api'; import { context } from '@opentelemetry/api'; import { propagation, trace } from '@opentelemetry/api'; import { W3CBaggagePropagator, isTracingSuppressed } from '@opentelemetry/core'; -import { SEMATTRS_HTTP_URL } from '@opentelemetry/semantic-conventions'; +import { ATTR_URL_FULL, SEMATTRS_HTTP_URL } from '@opentelemetry/semantic-conventions'; import type { continueTrace } from '@sentry/core'; -import { SEMANTIC_ATTRIBUTE_URL_FULL } from '@sentry/core'; import { hasTracingEnabled } from '@sentry/core'; import { getRootSpan } from '@sentry/core'; import { spanToJSON } from '@sentry/core'; @@ -294,7 +293,9 @@ function getExistingBaggage(carrier: unknown): string | undefined { */ function getCurrentURL(span: Span): string | undefined { const spanData = spanToJSON(span).data; - const urlAttribute = spanData?.[SEMATTRS_HTTP_URL] || spanData?.[SEMANTIC_ATTRIBUTE_URL_FULL]; + // `ATTR_URL_FULL` is the new attribute, but we still support the old one, `SEMATTRS_HTTP_URL`, for now. + // eslint-disable-next-line deprecation/deprecation + const urlAttribute = spanData?.[SEMATTRS_HTTP_URL] || spanData?.[ATTR_URL_FULL]; if (urlAttribute) { return urlAttribute; } diff --git a/packages/opentelemetry/src/sampler.ts b/packages/opentelemetry/src/sampler.ts index 03d47989ae1d..3438b4b6bbca 100644 --- a/packages/opentelemetry/src/sampler.ts +++ b/packages/opentelemetry/src/sampler.ts @@ -5,10 +5,8 @@ import { TraceState } from '@opentelemetry/core'; import type { Sampler, SamplingResult } from '@opentelemetry/sdk-trace-base'; import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; import { - SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, - SEMANTIC_ATTRIBUTE_URL_FULL, hasTracingEnabled, sampleSpan, } from '@sentry/core'; @@ -16,7 +14,12 @@ import type { Client, SpanAttributes } from '@sentry/types'; import { logger } from '@sentry/utils'; import { SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, SENTRY_TRACE_STATE_URL } from './constants'; -import { SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_URL } from '@opentelemetry/semantic-conventions'; +import { + ATTR_HTTP_REQUEST_METHOD, + ATTR_URL_FULL, + SEMATTRS_HTTP_METHOD, + SEMATTRS_HTTP_URL, +} from '@opentelemetry/semantic-conventions'; import { DEBUG_BUILD } from './debug-build'; import { getPropagationContextFromSpan } from './propagator'; import { getSamplingDecision } from './utils/getSamplingDecision'; @@ -52,13 +55,13 @@ export class SentrySampler implements Sampler { return wrapSamplingDecision({ decision: undefined, context, spanAttributes }); } + // `ATTR_HTTP_REQUEST_METHOD` is the new attribute, but we still support the old one, `SEMATTRS_HTTP_METHOD`, for now. + // eslint-disable-next-line deprecation/deprecation + const maybeSpanHttpMethod = spanAttributes[SEMATTRS_HTTP_METHOD] || spanAttributes[ATTR_HTTP_REQUEST_METHOD]; + // If we have a http.client span that has no local parent, we never want to sample it // but we want to leave downstream sampling decisions up to the server - if ( - spanKind === SpanKind.CLIENT && - (spanAttributes[SEMATTRS_HTTP_METHOD] || spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]) && - (!parentSpan || parentContext?.isRemote) - ) { + if (spanKind === SpanKind.CLIENT && maybeSpanHttpMethod && (!parentSpan || parentContext?.isRemote)) { return wrapSamplingDecision({ decision: undefined, context, spanAttributes }); } @@ -109,7 +112,7 @@ export class SentrySampler implements Sampler { [SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: sampleRate, }; - const method = `${spanAttributes[SEMATTRS_HTTP_METHOD]}`.toUpperCase(); + const method = `${maybeSpanHttpMethod}`.toUpperCase(); if (method === 'OPTIONS' || method === 'HEAD') { DEBUG_BUILD && logger.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`); @@ -198,7 +201,9 @@ function getBaseTraceState(context: Context, spanAttributes: SpanAttributes): Tr let traceState = parentContext?.traceState || new TraceState(); // We always keep the URL on the trace state, so we can access it in the propagator - const url = spanAttributes[SEMATTRS_HTTP_URL] || spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL]; + // `ATTR_URL_FULL` is the new attribute, but we still support the old one, `ATTR_HTTP_URL`, for now. + // eslint-disable-next-line deprecation/deprecation + const url = spanAttributes[SEMATTRS_HTTP_URL] || spanAttributes[ATTR_URL_FULL]; if (url && typeof url === 'string') { traceState = traceState.set(SENTRY_TRACE_STATE_URL, url); } diff --git a/packages/opentelemetry/src/spanExporter.ts b/packages/opentelemetry/src/spanExporter.ts index 5714a3d93970..d00319ec2c98 100644 --- a/packages/opentelemetry/src/spanExporter.ts +++ b/packages/opentelemetry/src/spanExporter.ts @@ -1,7 +1,7 @@ import type { Span } from '@opentelemetry/api'; import { SpanKind } from '@opentelemetry/api'; import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; -import { SEMATTRS_HTTP_STATUS_CODE } from '@opentelemetry/semantic-conventions'; +import { ATTR_HTTP_RESPONSE_STATUS_CODE, SEMATTRS_HTTP_STATUS_CODE } from '@opentelemetry/semantic-conventions'; import { captureEvent, getCapturedScopesOnSpan, @@ -358,9 +358,10 @@ function getData(span: ReadableSpan): Record { data['otel.kind'] = SpanKind[span.kind]; } - if (attributes[SEMATTRS_HTTP_STATUS_CODE]) { - const statusCode = attributes[SEMATTRS_HTTP_STATUS_CODE] as string; - data['http.response.status_code'] = statusCode; + // eslint-disable-next-line deprecation/deprecation + const maybeHttpStatusCodeAttribute = attributes[SEMATTRS_HTTP_STATUS_CODE]; + if (maybeHttpStatusCodeAttribute) { + data[ATTR_HTTP_RESPONSE_STATUS_CODE] = maybeHttpStatusCodeAttribute as string; } const requestData = getRequestSpanData(span); diff --git a/packages/opentelemetry/src/utils/getRequestSpanData.ts b/packages/opentelemetry/src/utils/getRequestSpanData.ts index 8ce4419c925d..ee723b3ca335 100644 --- a/packages/opentelemetry/src/utils/getRequestSpanData.ts +++ b/packages/opentelemetry/src/utils/getRequestSpanData.ts @@ -1,6 +1,11 @@ import type { Span } from '@opentelemetry/api'; import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; -import { SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_URL } from '@opentelemetry/semantic-conventions'; +import { + ATTR_HTTP_REQUEST_METHOD, + ATTR_URL_FULL, + SEMATTRS_HTTP_METHOD, + SEMATTRS_HTTP_URL, +} from '@opentelemetry/semantic-conventions'; import type { SanitizedRequestData } from '@sentry/types'; import { getSanitizedUrlString, parseUrl } from '@sentry/utils'; @@ -15,9 +20,17 @@ export function getRequestSpanData(span: Span | ReadableSpan): Partial = { - url: span.attributes[SEMATTRS_HTTP_URL] as string | undefined, - 'http.method': span.attributes[SEMATTRS_HTTP_METHOD] as string | undefined, + url: maybeUrlAttribute, + // eslint-disable-next-line deprecation/deprecation + 'http.method': (span.attributes[ATTR_HTTP_REQUEST_METHOD] || span.attributes[SEMATTRS_HTTP_METHOD]) as + | string + | undefined, }; // Default to GET if URL is set but method is not @@ -26,9 +39,8 @@ export function getRequestSpanData(span: Span | ReadableSpan): Partial { [SEMATTRS_HTTP_METHOD]: 'GET', [SEMATTRS_HTTP_URL]: 'https://www.example.com/my-path/123', [SEMATTRS_HTTP_TARGET]: '/my-path/123', - [SEMATTRS_HTTP_ROUTE]: '/my-path/:id', + [ATTR_HTTP_ROUTE]: '/my-path/:id', }, 'test name', SpanKind.CLIENT, @@ -312,7 +313,7 @@ describe('getSanitizedUrl', () => { [SEMATTRS_HTTP_URL]: 'http://example.com/?what=true', [SEMATTRS_HTTP_METHOD]: 'GET', [SEMATTRS_HTTP_TARGET]: '/?what=true', - [SEMATTRS_HTTP_ROUTE]: '/my-route', + [ATTR_HTTP_ROUTE]: '/my-route', [SEMATTRS_HTTP_HOST]: 'example.com:80', [SEMATTRS_HTTP_STATUS_CODE]: 200, }, @@ -384,7 +385,7 @@ describe('getSanitizedUrl', () => { [SEMATTRS_HTTP_URL]: 'http://example.com/?what=true', [SEMATTRS_HTTP_METHOD]: 'GET', [SEMATTRS_HTTP_TARGET]: '/?what=true', - [SEMATTRS_HTTP_ROUTE]: '/my-route', + [ATTR_HTTP_ROUTE]: '/my-route', [SEMATTRS_HTTP_HOST]: 'example.com:80', [SEMATTRS_HTTP_STATUS_CODE]: 200, }, diff --git a/yarn.lock b/yarn.lock index 69c732db9498..22770c583774 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7330,7 +7330,7 @@ "@opentelemetry/core" "1.25.0" "@opentelemetry/semantic-conventions" "1.25.0" -"@opentelemetry/resources@1.25.1", "@opentelemetry/resources@^1.23.0", "@opentelemetry/resources@^1.25.1", "@opentelemetry/resources@^1.8.0": +"@opentelemetry/resources@1.25.1", "@opentelemetry/resources@^1.23.0", "@opentelemetry/resources@^1.8.0": version "1.25.1" resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.25.1.tgz#bb9a674af25a1a6c30840b755bc69da2796fefbb" integrity sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ== @@ -7338,6 +7338,14 @@ "@opentelemetry/core" "1.25.1" "@opentelemetry/semantic-conventions" "1.25.1" +"@opentelemetry/resources@1.26.0", "@opentelemetry/resources@^1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.26.0.tgz#da4c7366018bd8add1f3aa9c91c6ac59fd503cef" + integrity sha512-CPNYchBE7MBecCSVy0HKpUISEeJOniWqcHaAHpmasZ3j9o6V3AyBzhRc90jdmemq0HOxDr6ylhUbDhBqqPpeNw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + "@opentelemetry/resources@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-0.12.0.tgz#5eb287c3032a2bebb2bb9f69b44bd160d2a7d591" @@ -7381,7 +7389,7 @@ "@opentelemetry/resources" "1.23.0" "@opentelemetry/semantic-conventions" "1.23.0" -"@opentelemetry/sdk-trace-base@^1.22", "@opentelemetry/sdk-trace-base@^1.23.0", "@opentelemetry/sdk-trace-base@^1.25.1": +"@opentelemetry/sdk-trace-base@^1.22", "@opentelemetry/sdk-trace-base@^1.23.0": version "1.25.1" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.25.1.tgz#cbc1e60af255655d2020aa14cde17b37bd13df37" integrity sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw== @@ -7390,6 +7398,15 @@ "@opentelemetry/resources" "1.25.1" "@opentelemetry/semantic-conventions" "1.25.1" +"@opentelemetry/sdk-trace-base@^1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.26.0.tgz#0c913bc6d2cfafd901de330e4540952269ae579c" + integrity sha512-olWQldtvbK4v22ymrKLbIcBi9L2SpMO84sCPY54IVsJhP9fRsxJT194C/AVaAuJzLE30EdhhM1VmvVYR7az+cw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + "@opentelemetry/semantic-conventions@1.23.0": version "1.23.0" resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.23.0.tgz#627f2721b960fe586b7f72a07912cb7699f06eef" @@ -7400,7 +7417,7 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.0.tgz#390eb4d42a29c66bdc30066af9035645e9bb7270" integrity sha512-M+kkXKRAIAiAP6qYyesfrC5TOmDpDVtsxuGfPcqd9B/iBrac+E14jYwrgm0yZBUIbIP2OnqC3j+UgkXLm1vxUQ== -"@opentelemetry/semantic-conventions@1.25.1", "@opentelemetry/semantic-conventions@^1.17.0", "@opentelemetry/semantic-conventions@^1.23.0", "@opentelemetry/semantic-conventions@^1.25.1": +"@opentelemetry/semantic-conventions@1.25.1", "@opentelemetry/semantic-conventions@^1.17.0", "@opentelemetry/semantic-conventions@^1.23.0": version "1.25.1" resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz#0deecb386197c5e9c2c28f2f89f51fb8ae9f145e" integrity sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==