diff --git a/packages/core/src/asyncContext/types.ts b/packages/core/src/asyncContext/types.ts index 3f20eb703a81..8a17aa728852 100644 --- a/packages/core/src/asyncContext/types.ts +++ b/packages/core/src/asyncContext/types.ts @@ -5,7 +5,6 @@ import type { continueTrace, isTracingSuppressed, startInactiveSpan, - startNewTrace, startSpan, startSpanManual, suppressTracing, @@ -100,9 +99,6 @@ export interface AsyncContextStrategy { */ continueTrace?: typeof continueTrace; - /** Start a new trace, ensuring all spans in the callback share the same traceId. */ - startNewTrace?: typeof startNewTrace; - /** Get the runtime store required to bind tracing channels to an active span. */ getTracingChannelBinding?: () => TracingChannelBinding | undefined; } diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index 115f8097b190..e1ecb5ced3bf 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -325,11 +325,6 @@ export function isTracingSuppressed(scope = getCurrentScope()): boolean { * or page will automatically create a new trace. */ export function startNewTrace(callback: () => T): T { - const acs = getAcs(); - if (acs.startNewTrace) { - return acs.startNewTrace(callback); - } - return withScope(scope => { scope.setPropagationContext({ traceId: generateTraceId(), diff --git a/packages/opentelemetry/src/asyncContextStrategy.ts b/packages/opentelemetry/src/asyncContextStrategy.ts index 38b19048f8c1..56c8a6e4833a 100644 --- a/packages/opentelemetry/src/asyncContextStrategy.ts +++ b/packages/opentelemetry/src/asyncContextStrategy.ts @@ -6,7 +6,7 @@ import { SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, } from './constants'; -import { continueTrace, startInactiveSpan, startNewTrace, startSpan, startSpanManual, withActiveSpan } from './trace'; +import { continueTrace, startInactiveSpan, startSpan, startSpanManual, withActiveSpan } from './trace'; import type { CurrentScopes } from './types'; import { getContextFromScope, getScopesFromContext } from './utils/contextData'; import { getActiveSpan } from './utils/getActiveSpan'; @@ -104,7 +104,6 @@ export function setOpenTelemetryContextAsyncContextStrategy(options?: { getActiveSpan, getTraceData, continueTrace, - startNewTrace, // The types here don't fully align, because our own `Span` type is narrower // than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around withActiveSpan: withActiveSpan as typeof defaultWithActiveSpan, diff --git a/packages/opentelemetry/src/trace.ts b/packages/opentelemetry/src/trace.ts index c1b49bb35094..045c871b5e0f 100644 --- a/packages/opentelemetry/src/trace.ts +++ b/packages/opentelemetry/src/trace.ts @@ -11,8 +11,6 @@ import type { } from '@sentry/core'; import { _INTERNAL_safeMathRandom, - generateSpanId, - generateTraceId, getClient, getCurrentScope, getDynamicSamplingContextFromScope, @@ -303,36 +301,6 @@ export function continueTrace(options: Parameters[0 return continueTraceAsRemoteSpan(context.active(), options, callback); } -/** - * Start a new trace with a unique traceId, ensuring all spans created within the callback - * share the same traceId. - * - * This is a custom version of `startNewTrace` for OTEL-powered environments. - * It injects the new traceId as a remote span context into the OTEL context, so that - * `startInactiveSpan` and `startSpan` pick it up correctly. - */ -export function startNewTrace(callback: () => T): T { - const traceId = generateTraceId(); - const spanId = generateSpanId(); - - const spanContext: SpanContext = { - traceId, - spanId, - isRemote: true, - traceFlags: TraceFlags.NONE, - }; - - const ctxWithTrace = trace.setSpanContext(context.active(), spanContext); - - return context.with(ctxWithTrace, () => { - getCurrentScope().setPropagationContext({ - traceId, - sampleRand: _INTERNAL_safeMathRandom(), - }); - return callback(); - }); -} - /** * Get the trace context for a given scope. * We have a custom implementation here because we need an OTEL-specific way to get the span from a scope. diff --git a/packages/opentelemetry/test/trace.test.ts b/packages/opentelemetry/test/trace.test.ts index a6bf138a847c..04f912257a8f 100644 --- a/packages/opentelemetry/test/trace.test.ts +++ b/packages/opentelemetry/test/trace.test.ts @@ -20,7 +20,7 @@ import { withScope, } from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { continueTrace, startInactiveSpan, startNewTrace, startSpan, startSpanManual } from '../src/trace'; +import { continueTrace, startInactiveSpan, startSpan, startSpanManual } from '../src/trace'; import { getActiveSpan } from '../src/utils/getActiveSpan'; import { getSamplingDecision } from '../src/utils/getSamplingDecision'; import { makeTraceState } from '../src/utils/makeTraceState'; @@ -2153,99 +2153,6 @@ describe('span.end() timestamp conversion', () => { }); }); -describe('startNewTrace', () => { - beforeEach(() => { - mockSdkInit({ tracesSampleRate: 1 }); - }); - - afterEach(async () => { - await cleanupOtel(); - }); - - it('sequential startInactiveSpan calls share the same traceId', () => { - startNewTrace(() => { - const propagationContext = getCurrentScope().getPropagationContext(); - - const span1 = startInactiveSpan({ name: 'span-1' }); - const span2 = startInactiveSpan({ name: 'span-2' }); - const span3 = startInactiveSpan({ name: 'span-3' }); - - const traceId1 = span1.spanContext().traceId; - const traceId2 = span2.spanContext().traceId; - const traceId3 = span3.spanContext().traceId; - - expect(traceId1).toBe(propagationContext.traceId); - expect(traceId2).toBe(propagationContext.traceId); - expect(traceId3).toBe(propagationContext.traceId); - - span1.end(); - span2.end(); - span3.end(); - }); - }); - - it('startSpan inside startNewTrace uses the correct traceId', () => { - startNewTrace(() => { - const propagationContext = getCurrentScope().getPropagationContext(); - - startSpan({ name: 'parent-span' }, parentSpan => { - const parentTraceId = parentSpan.spanContext().traceId; - expect(parentTraceId).toBe(propagationContext.traceId); - - const child = startInactiveSpan({ name: 'child-span' }); - expect(child.spanContext().traceId).toBe(propagationContext.traceId); - child.end(); - }); - }); - }); - - it('generates a different traceId than the outer trace', () => { - startSpan({ name: 'outer-span' }, outerSpan => { - const outerTraceId = outerSpan.spanContext().traceId; - - startNewTrace(() => { - const innerSpan = startInactiveSpan({ name: 'inner-span' }); - const innerTraceId = innerSpan.spanContext().traceId; - - expect(innerTraceId).not.toBe(outerTraceId); - - const propagationContext = getCurrentScope().getPropagationContext(); - expect(innerTraceId).toBe(propagationContext.traceId); - - innerSpan.end(); - }); - }); - }); - - it('allows spans to be sampled based on tracesSampleRate', () => { - startNewTrace(() => { - const span = startInactiveSpan({ name: 'sampled-span' }); - // tracesSampleRate is 1 in mockSdkInit, so spans should be sampled - // This verifies that TraceFlags.NONE on the remote span context does not - // cause the sampler to inherit a "not sampled" decision from the parent - expect(spanIsSampled(span)).toBe(true); - span.end(); - }); - }); - - it('does not leak the new traceId to the outer scope', () => { - const outerScope = getCurrentScope(); - const outerTraceId = outerScope.getPropagationContext().traceId; - - startNewTrace(() => { - // Manually set a known traceId on the inner scope to verify it doesn't leak - getCurrentScope().setPropagationContext({ - traceId: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - sampleRand: 0.5, - }); - }); - - const afterTraceId = outerScope.getPropagationContext().traceId; - expect(afterTraceId).toBe(outerTraceId); - expect(afterTraceId).not.toBe('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); - }); -}); - function getSpanName(span: Span): string | undefined { return spanToJSON(span).description; }