diff --git a/packages/core/src/tracing/index.ts b/packages/core/src/tracing/index.ts index cd9ca5ea6351..7cc86ae76531 100644 --- a/packages/core/src/tracing/index.ts +++ b/packages/core/src/tracing/index.ts @@ -1,3 +1,4 @@ +export { setCapturedScopesOnSpan, getCapturedScopesOnSpan } from './utils'; export { addTracingExtensions } from './hubextensions'; export { startIdleSpan, TRACING_DEFAULTS } from './idleSpan'; export { SentrySpan } from './sentrySpan'; diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index c01b6dcf871b..1c7c9bc8842e 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -4,7 +4,16 @@ import { SpanKind } from '@opentelemetry/api'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -import { addBreadcrumb, defineIntegration, getIsolationScope, isSentryRequestUrl, spanToJSON } from '@sentry/core'; +import { + addBreadcrumb, + defineIntegration, + getCapturedScopesOnSpan, + getCurrentScope, + getIsolationScope, + isSentryRequestUrl, + setCapturedScopesOnSpan, + spanToJSON, +} from '@sentry/core'; import { _INTERNAL, getClient, getSpanKind } from '@sentry/opentelemetry'; import type { IntegrationFn } from '@sentry/types'; @@ -88,8 +97,12 @@ const _httpIntegration = ((options: HttpOptions = {}) => { return; } + const scopes = getCapturedScopesOnSpan(span); + // Update the isolation scope, isolate this request - const isolationScope = getIsolationScope().clone(); + const isolationScope = (scopes.isolationScope || getIsolationScope()).clone(); + const scope = scopes.scope || getCurrentScope(); + isolationScope.setSDKProcessingMetadata({ request: req }); const client = getClient(); @@ -97,6 +110,7 @@ const _httpIntegration = ((options: HttpOptions = {}) => { isolationScope.setRequestSession({ status: 'ok' }); } setIsolationScope(isolationScope); + setCapturedScopesOnSpan(span, scope, isolationScope); // attempt to update the scope's `transactionName` based on the request URL // Ideally, framework instrumentations coming after the HttpInstrumentation diff --git a/packages/node/test/integration/scope.test.ts b/packages/node/test/integration/scope.test.ts index db3f61d251ba..ed9f20cf2b6c 100644 --- a/packages/node/test/integration/scope.test.ts +++ b/packages/node/test/integration/scope.test.ts @@ -1,5 +1,5 @@ -import { getCurrentScope } from '@sentry/core'; -import { getClient, getSpanScopes } from '@sentry/opentelemetry'; +import { getCapturedScopesOnSpan, getCurrentScope } from '@sentry/core'; +import { getClient } from '@sentry/opentelemetry'; import { clearGlobalScope } from '../../../core/test/lib/clear-global-scope'; import * as Sentry from '../../src/'; @@ -42,7 +42,7 @@ describe('Integration | Scope', () => { scope2.setTag('tag3', 'val3'); Sentry.startSpan({ name: 'outer' }, span => { - expect(getSpanScopes(span)?.scope).toBe(enableTracing ? scope2 : undefined); + expect(getCapturedScopesOnSpan(span)?.scope).toBe(enableTracing ? scope2 : undefined); spanId = span.spanContext().spanId; traceId = span.spanContext().traceId; diff --git a/packages/opentelemetry/src/index.ts b/packages/opentelemetry/src/index.ts index 8cae9b317837..776dd8c50d0c 100644 --- a/packages/opentelemetry/src/index.ts +++ b/packages/opentelemetry/src/index.ts @@ -4,7 +4,6 @@ export type { OpenTelemetryClient } from './types'; export { wrapClientClass } from './custom/client'; export { getSpanKind } from './utils/getSpanKind'; -export { getSpanScopes } from './utils/spanData'; export { getScopesFromContext } from './utils/contextData'; diff --git a/packages/opentelemetry/src/spanExporter.ts b/packages/opentelemetry/src/spanExporter.ts index a2603fe91718..bdebb8e2f6e0 100644 --- a/packages/opentelemetry/src/spanExporter.ts +++ b/packages/opentelemetry/src/spanExporter.ts @@ -2,7 +2,12 @@ import type { Span } from '@opentelemetry/api'; import { SpanKind } from '@opentelemetry/api'; import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; -import { captureEvent, getMetricSummaryJsonForSpan, timedEventsToMeasurements } from '@sentry/core'; +import { + captureEvent, + getCapturedScopesOnSpan, + getMetricSummaryJsonForSpan, + timedEventsToMeasurements, +} from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, @@ -23,7 +28,6 @@ import { getLocalParentId } from './utils/groupSpansWithParents'; import { groupSpansWithParents } from './utils/groupSpansWithParents'; import { mapStatus } from './utils/mapStatus'; import { parseSpanDescription } from './utils/parseSpanDescription'; -import { getSpanScopes } from './utils/spanData'; type SpanNodeCompleted = SpanNode & { span: ReadableSpan }; @@ -176,7 +180,7 @@ function parseSpan(span: ReadableSpan): { op?: string; origin?: SpanOrigin; sour function createTransactionForOtelSpan(span: ReadableSpan): TransactionEvent { const { op, description, data, origin = 'manual', source } = getSpanData(span); - const capturedSpanScopes = getSpanScopes(span); + const capturedSpanScopes = getCapturedScopesOnSpan(span as unknown as Span); const sampleRate = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] as number | undefined; @@ -220,8 +224,8 @@ function createTransactionForOtelSpan(span: ReadableSpan): TransactionEvent { type: 'transaction', sdkProcessingMetadata: { ...dropUndefinedKeys({ - capturedSpanScope: capturedSpanScopes?.scope, - capturedSpanIsolationScope: capturedSpanScopes?.isolationScope, + capturedSpanScope: capturedSpanScopes.scope, + capturedSpanIsolationScope: capturedSpanScopes.isolationScope, sampleRate, dynamicSamplingContext: getDynamicSamplingContextFromSpan(span), }), diff --git a/packages/opentelemetry/src/spanProcessor.ts b/packages/opentelemetry/src/spanProcessor.ts index 740afc2cc6fa..e3f604cab64b 100644 --- a/packages/opentelemetry/src/spanProcessor.ts +++ b/packages/opentelemetry/src/spanProcessor.ts @@ -8,12 +8,12 @@ import { getDefaultIsolationScope, logSpanEnd, logSpanStart, + setCapturedScopesOnSpan, } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE } from './semanticAttributes'; import { SentrySpanExporter } from './spanExporter'; import { getScopesFromContext } from './utils/contextData'; import { setIsSetup } from './utils/setupCheck'; -import { setSpanScopes } from './utils/spanData'; function onSpanStart(span: Span, parentContext: Context): void { // This is a reliable way to get the parent span - because this is exactly how the parent is identified in the OTEL SDK @@ -42,7 +42,7 @@ function onSpanStart(span: Span, parentContext: Context): void { // We need the scope at time of span creation in order to apply it to the event when the span is finished if (scopes) { - setSpanScopes(span, scopes); + setCapturedScopesOnSpan(span, scopes.scope, scopes.isolationScope); } logSpanStart(span); diff --git a/packages/opentelemetry/src/utils/spanData.ts b/packages/opentelemetry/src/utils/spanData.ts deleted file mode 100644 index 3dc00f043f8a..000000000000 --- a/packages/opentelemetry/src/utils/spanData.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Scope } from '@sentry/types'; -import { addNonEnumerableProperty } from '@sentry/utils'; - -import type { AbstractSpan } from '../types'; - -const SPAN_SCOPES_FIELD = '_spanScopes'; - -/** - * Set the Sentry scope to be used for finishing a given OTEL span. - * This is different from `setCapturedScopesOnSpan`, as that works on _sentry_ spans, - * while here we are basically "caching" this on the otel spans. - */ -export function setSpanScopes( - span: AbstractSpan, - scopes: { - scope: Scope; - isolationScope: Scope; - }, -): void { - addNonEnumerableProperty(span, SPAN_SCOPES_FIELD, scopes); -} - -/** Get the Sentry scopes to use for finishing an OTEL span. */ -export function getSpanScopes(span: AbstractSpan): - | { - scope: Scope; - isolationScope: Scope; - } - | undefined { - return (span as { [SPAN_SCOPES_FIELD]?: { scope: Scope; isolationScope: Scope } })[SPAN_SCOPES_FIELD]; -} diff --git a/packages/opentelemetry/test/integration/scope.test.ts b/packages/opentelemetry/test/integration/scope.test.ts index 7742fcf06767..e17516a9d7bf 100644 --- a/packages/opentelemetry/test/integration/scope.test.ts +++ b/packages/opentelemetry/test/integration/scope.test.ts @@ -1,5 +1,6 @@ import { captureException, + getCapturedScopesOnSpan, getClient, getCurrentScope, getIsolationScope, @@ -9,7 +10,6 @@ import { } from '@sentry/core'; import { startSpan } from '../../src/trace'; -import { getSpanScopes } from '../../src/utils/spanData'; import type { TestClientInterface } from '../helpers/TestClient'; import { cleanupOtel, mockSdkInit } from '../helpers/mockSdkInit'; @@ -49,7 +49,7 @@ describe('Integration | Scope', () => { scope2.setTag('tag3', 'val3'); startSpan({ name: 'outer' }, span => { - expect(getSpanScopes(span)?.scope).toBe(enableTracing ? scope2 : undefined); + expect(getCapturedScopesOnSpan(span)?.scope).toBe(enableTracing ? scope2 : undefined); spanId = span.spanContext().spanId; traceId = span.spanContext().traceId;