8000 fix(core): Use consistent `continueTrace` implementation in core (#14… · mstrokin/sentry-javascript@65531f3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 65531f3

Browse files
authored
fix(core): Use consistent continueTrace implementation in core (getsentry#14813)
We have a different implementation of `continueTrace` for OTEL/Node. Until now we relied on actually using the import from `@sentry/node` vs `@sentry/core` to ensure this. However, this is a footgun, and actually lead to a problem in NextJS because we used the core variant there. Also, it is simply not isomorphic. So to fix this, this PR puts `continueTrace` on the ACS so we can consistently use the core variant in all environments. Fixes getsentry#14787
1 parent b008139 commit 65531f3

File tree

16 files changed

+50
-52
lines changed
  • remix/src
  • solidstart/src
  • sveltekit/src
  • 16 files changed

    +50
    -52
    lines changed

    packages/astro/src/index.types.ts

    Lines changed: 0 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -26,8 +26,6 @@ export declare function flush(timeout?: number | undefined): PromiseLike<boolean
    2626

    2727
    // eslint-disable-next-line deprecation/deprecation
    2828
    export declare const getCurrentHub: typeof clientSdk.getCurrentHub;
    29-
    export declare const getClient: typeof clientSdk.getClient;
    30-
    export declare const continueTrace: typeof clientSdk.continueTrace;
    3129

    3230
    export declare const Span: clientSdk.Span;
    3331

    packages/core/src/asyncContext/types.ts

    Lines changed: 8 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,6 +1,7 @@
    11
    import type { Scope } from '../scope';
    22
    import type { getTraceData } from '../utils/traceData';
    33
    import type {
    4+
    continueTrace,
    45
    startInactiveSpan,
    56
    startSpan,
    67
    startSpanManual,
    @@ -68,4 +69,11 @@ export interface AsyncContextStrategy {
    6869

    6970
    /** Get trace data as serialized string values for propagation via `sentry-trace` and `baggage`. */
    7071
    getTraceData?: typeof getTraceData;
    72+
    73+
    /**
    74+
    * Continue a trace from `sentry-trace` and `baggage` values.
    75+
    * These values can be obtained from incoming request headers, or in the browser from `<meta name="sentry-trace">`
    76+
    * and `<meta name="baggage">` HTML tags.
    77+
    */
    78+
    continueTrace?: typeof continueTrace;
    7179
    }

    packages/core/src/tracing/trace.ts

    Lines changed: 9 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -192,15 +192,20 @@ export function startInactiveSpan(options: StartSpanOptions): Span {
    192192
    * be attached to the incoming trace.
    193193
    */
    194194
    export const continueTrace = <V>(
    195-
    {
    196-
    sentryTrace,
    197-
    baggage,
    198-
    }: {
    195+
    options: {
    199196
    sentryTrace: Parameters<typeof propagationContextFromHeaders>[0];
    200197
    baggage: Parameters<typeof propagationContextFromHeaders>[1];
    201198
    },
    202199
    callback: () => V,
    203200
    ): V => {
    201+
    const carrier = getMainCarrier();
    202+
    const acs = getAsyncContextStrategy(carrier);
    203+
    if (acs.continueTrace) {
    204+
    return acs.continueTrace(options, callback);
    205+
    }
    206+
    207+
    const { sentryTrace, baggage } = options;
    208+
    204209
    return withScope(scope => {
    205210
    const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);
    206211
    scope.setPropagationContext(propagationContext);

    packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts

    Lines changed: 8 additions & 1 deletion
    Original file line nu F438 mberDiff line numberDiff line change
    @@ -3,6 +3,7 @@ import {
    33
    SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
    44
    captureException,
    55
    continueTrace,
    6+
    getActiveSpan,
    67
    httpRequestToRequestData,
    78
    isString,
    89
    logger,
    @@ -59,7 +60,13 @@ export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameteriz
    5960
    req.__withSentry_applied__ = true;
    6061

    6162
    return withIsolationScope(isolationScope => {
    62-
    return continueTrace(
    63+
    // Normally, there is an active span here (from Next.js OTEL) and we just use that as parent
    64+
    // Else, we manually continueTrace from the incoming headers
    65+
    const continueTraceIfNoActiveSpan = getActiveSpan()
    66+
    ? <T>(_opts: unknown, callback: () => T) => callback()
    67+
    : continueTrace;
    68+
    69+
    return continueTraceIfNoActiveSpan(
    6370
    {
    6471
    sentryTrace:
    6572
    req.headers && isString(req.headers['sentry-trace']) ? req.headers['sentry-trace'] : undefined,

    packages/nextjs/src/common/withServerActionInstrumentation.ts

    Lines changed: 8 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1,4 +1,5 @@
    11
    import type { RequestEventData } from '@sentry/core';
    2+
    import { getActiveSpan } from '@sentry/core';
    23
    import {
    34
    SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
    45
    SPAN_STATUS_ERROR,
    @@ -95,7 +96,13 @@ async function withServerActionInstrumentationImplementation<A extends (...args:
    9596
    } satisfies RequestEventData,
    9697
    });
    9798

    98-
    return continueTrace(
    99+
    // Normally, there is an active span here (from Next.js OTEL) and we just use that as parent
    100+
    // Else, we manually continueTrace from the incoming headers
    101+
    const continueTraceIfNoActiveSpan = 10000 getActiveSpan()
    102+
    ? <T>(_opts: unknown, callback: () => T) => callback()
    103+
    : continueTrace;
    104+
    105+
    return continueTraceIfNoActiveSpan(
    99106
    {
    100107
    sentryTrace: sentryTraceHeader,
    101108
    baggage: baggageHeader,

    packages/nextjs/src/index.types.ts

    Lines changed: 0 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -19,10 +19,6 @@ export declare function init(
    1919
    options: Options | clientSdk.BrowserOptions | serverSdk.NodeOptions | edgeSdk.EdgeOptions,
    2020
    ): Client | undefined;
    2121

    22-
    export declare const getClient: typeof clientSdk.getClient;
    23-
    export declare const getRootSpan: typeof serverSdk.getRootSpan;
    24-
    export declare const continueTrace: typeof clientSdk.continueTrace;
    25-
    2622
    export declare const linkedErrorsIntegration: typeof clientSdk.linkedErrorsIntegration;
    2723
    export declare const contextLinesIntegration: typeof clientSdk.contextLinesIntegration;
    2824

    packages/node/src/index.ts

    Lines changed: 1 addition & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -58,9 +58,6 @@ export type { NodeOptions } from './types';
    5858
    export { addRequestDataToEvent, DEFAULT_USER_INCLUDES, extractRequestData } from '@sentry/core';
    5959

    6060
    export {
    61-
    // These are custom variants that need to be used instead of the core one
    62-
    // As they have slightly different implementations
    63-
    continueTrace,
    6461
    // This needs exporting so the NodeClient can be used without calling init
    6562
    setOpenTelemetryContextAsyncContextStrategy as setNodeAsyncContextStrategy,
    6663
    } from '@sentry/opentelemetry';
    @@ -105,6 +102,7 @@ export {
    105102
    getIsolationScope,
    106103
    getTraceData,
    107104
    getTraceMetaTags,
    105+
    continueTrace,
    108106
    withScope,
    109107
    withIsolationScope,
    110108
    captureException,

    packages/nuxt/src/index.types.ts

    Lines changed: 0 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -14,4 +14,3 @@ export declare const linkedErrorsIntegration: typeof clientSdk.linkedErrorsInteg
    1414
    export declare const contextLinesIntegration: typeof clientSdk.contextLinesIntegration;
    1515
    export declare const getDefaultIntegrations: (options: Options) => Integration[];
    1616
    export declare const defaultStackParser: StackParser;
    17-
    export declare const continueTrace: typeof clientSdk.continueTrace;

    packages/opentelemetry/src/asyncContextStrategy.ts

    Lines changed: 2 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -6,7 +6,7 @@ import {
    66
    SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY,
    77
    SENTRY_FORK_SET_SCOPE_CONTEXT_KEY,
    88
    } from './constants';
    9-
    import { startInactiveSpan, startSpan, startSpanManual, withActiveSpan } from './trace';
    9+
    import { continueTrace, startInactiveSpan, startSpan, startSpanManual, withActiveSpan } from './trace';
    1010
    import type { CurrentScopes } from './types';
    1111
    import { getScopesFromContext } from './utils/contextData';
    1212
    import { getActiveSpan } from './utils/getActiveSpan';
    @@ -103,6 +103,7 @@ export function setOpenTelemetryContextAsyncContextStrategy(): void {
    103103
    getActiveSpan,
    104104
    suppressTracing,
    105105
    getTraceData,
    106+
    continueTrace,
    106107
    // The types here don't fully align, because our own `Span` type is narrower
    107108
    // than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around
    108109
    withActiveSpan: withActiveSpan as typeof defaultWithActiveSpan,

    packages/opentelemetry/src/trace.ts

    Lines changed: 9 additions & 5 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,11 +1,17 @@
    11
    import type { Context, Span, SpanContext, SpanOptions, Tracer } from '@opentelemetry/api';
    22
    import { SpanStatusCode, TraceFlags, context, trace } from '@opentelemetry/api';
    33
    import { suppressTracing } from '@opentelemetry/core';
    4-
    import type { Client, DynamicSamplingContext, Scope, Span as SentrySpan, TraceContext } from '@sentry/core';
    4+
    import type {
    5+
    Client,
    6+
    DynamicSamplingContext,
    7+
    Scope,
    8+
    Span as SentrySpan,
    9+
    TraceContext,
    10+
    continueTrace as baseContinueTrace,
    11+
    } from '@sentry/core';
    512
    import {
    613
    SDK_VERSION,
    714
    SEMANTIC_ATTRIBUTE_SENTRY_OP,
    8-
    continueTrace as baseContinueTrace,
    915
    getClient,
    1016
    getCurrentScope,
    1117
    getDynamicSamplingContextFromScope,
    @@ -247,9 +253,7 @@ function getContextForScope(scope?: Scope): Context {
    247253
    * It propagates the trace as a remote span, in addition to setting it on the propagation context.
    248254
    */
    249255
    export function continueTrace<T>(options: Parameters<typeof baseContinueTrace>[0], callback: () => T): T {
    250-
    return baseContinueTrace(options, () => {
    251-
    return continueTraceAsRemoteSpan(context.active(), options, callback);
    252-
    });
    256+
    return continueTraceAsRemoteSpan(context.active(), options, callback);
    253257
    }
    254258

    255259
    /**

    0 commit comments

    Comments
     (0)
    0