Skip to content

Commit 6b86b3e

Browse files
author
Luca Forstner
authored
feat(utils): Add propagationContextFromHeaders (#10313)
1 parent 1ec15ee commit 6b86b3e

File tree

14 files changed

+131
-21
lines changed

14 files changed

+131
-21
lines changed

packages/core/src/tracing/trace.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Span, SpanTimeInput, StartSpanOptions, TransactionContext } from '@sentry/types';
22

3+
import type { propagationContextFromHeaders } from '@sentry/utils';
34
import { dropUndefinedKeys, logger, tracingContextFromHeaders } from '@sentry/utils';
45

56
import { DEBUG_BUILD } from '../debug-build';
@@ -228,16 +229,16 @@ export function continueTrace({
228229
sentryTrace,
229230
baggage,
230231
}: {
231-
sentryTrace: Parameters<typeof tracingContextFromHeaders>[0];
232-
baggage: Parameters<typeof tracingContextFromHeaders>[1];
232+
sentryTrace: Parameters<typeof propagationContextFromHeaders>[0];
233+
baggage: Parameters<typeof propagationContextFromHeaders>[1];
233234
}): Partial<TransactionContext>;
234235
export function continueTrace<V>(
235236
{
236237
sentryTrace,
237238
baggage,
238239
}: {
239-
sentryTrace: Parameters<typeof tracingContextFromHeaders>[0];
240-
baggage: Parameters<typeof tracingContextFromHeaders>[1];
240+
sentryTrace: Parameters<typeof propagationContextFromHeaders>[0];
241+
baggage: Parameters<typeof propagationContextFromHeaders>[1];
241242
},
242243
callback: (transactionContext: Partial<TransactionContext>) => V,
243244
): V;
@@ -253,13 +254,23 @@ export function continueTrace<V>(
253254
sentryTrace,
254255
baggage,
255256
}: {
257+
// eslint-disable-next-line deprecation/deprecation
256258
sentryTrace: Parameters<typeof tracingContextFromHeaders>[0];
259+
// eslint-disable-next-line deprecation/deprecation
257260
baggage: Parameters<typeof tracingContextFromHeaders>[1];
258261
},
259262
callback?: (transactionContext: Partial<TransactionContext>) => V,
260263
): V | Partial<TransactionContext> {
264+
// TODO(v8): Change this function so it doesn't do anything besides setting the propagation context on the current scope:
265+
/*
266+
const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);
267+
getCurrentScope().setPropagationContext(propagationContext);
268+
return;
269+
*/
270+
261271
const currentScope = getCurrentScope();
262272

273+
// eslint-disable-next-line deprecation/deprecation
263274
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
264275
sentryTrace,
265276
baggage,

packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export function pagesRouterInstrumentation(
119119
startTransactionOnLocationChange: boolean = true,
120120
): void {
121121
const { route, params, sentryTrace, baggage } = extractNextDataTagInformation();
122+
// eslint-disable-next-line deprecation/deprecation
122123
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
123124
sentryTrace,
124125
baggage,

packages/nextjs/src/common/utils/wrapperUtils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
9393
const sentryTrace =
9494
req.headers && isString(req.headers['sentry-trace']) ? req.headers['sentry-trace'] : undefined;
9595
const baggage = req.headers?.baggage;
96+
// eslint-disable-next-line deprecation/deprecation
9697
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
9798
sentryTrace,
9899
baggage,

packages/nextjs/src/common/withServerActionInstrumentation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ async function withServerActionInstrumentationImplementation<A extends (...args:
7676
}
7777

7878
const currentScope = getCurrentScope();
79+
// eslint-disable-next-line deprecation/deprecation
7980
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
8081
sentryTraceHeader,
8182
baggageHeader,

packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
2828
return new Proxy(routeHandler, {
2929
apply: (originalFunction, thisArg, args) => {
3030
return runWithAsyncContext(async () => {
31+
// eslint-disable-next-line deprecation/deprecation
3132
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
3233
sentryTraceHeader ?? headers?.get('sentry-trace') ?? undefined,
3334
baggageHeader ?? headers?.get('baggage'),

packages/node-experimental/src/sdk/init.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import {
1212
consoleSandbox,
1313
dropUndefinedKeys,
1414
logger,
15+
propagationContextFromHeaders,
1516
stackParserFromStackParserOptions,
16-
tracingContextFromHeaders,
1717
} from '@sentry/utils';
1818
import { DEBUG_BUILD } from '../debug-build';
1919

@@ -190,7 +190,7 @@ function updateScopeFromEnvVariables(): void {
190190
if (!['false', 'n', 'no', 'off', '0'].includes(sentryUseEnvironment)) {
191191
const sentryTraceEnv = process.env.SENTRY_TRACE;
192192
const baggageEnv = process.env.SENTRY_BAGGAGE;
193-
const { propagationContext } = tracingContextFromHeaders(sentryTraceEnv, baggageEnv);
193+
const propagationContext = propagationContextFromHeaders(sentryTraceEnv, baggageEnv);
194194
getCurrentScope().setPropagationContext(propagationContext);
195195
}
196196
}

packages/node/src/sdk.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import {
1717
GLOBAL_OBJ,
1818
createStackParser,
1919
nodeStackLineParser,
20+
propagationContextFromHeaders,
2021
stackParserFromStackParserOptions,
21-
tracingContextFromHeaders,
2222
} from '@sentry/utils';
2323

2424
import { setNodeAsyncContextStrategy } from './async';
@@ -291,7 +291,7 @@ function updateScopeFromEnvVariables(): void {
291291
if (!['false', 'n', 'no', 'off', '0'].includes(sentryUseEnvironment)) {
292292
const sentryTraceEnv = process.env.SENTRY_TRACE;
293293
const baggageEnv = process.env.SENTRY_BAGGAGE;
294-
const { propagationContext } = tracingContextFromHeaders(sentryTraceEnv, baggageEnv);
294+
const propagationContext = propagationContextFromHeaders(sentryTraceEnv, baggageEnv);
295295
getCurrentScope().setPropagationContext(propagationContext);
296296
}
297297
}

packages/opentelemetry/src/propagator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { TraceFlags, propagation, trace } from '@opentelemetry/api';
33
import { W3CBaggagePropagator, isTracingSuppressed } from '@opentelemetry/core';
44
import { getDynamicSamplingContextFromClient } from '@sentry/core';
55
import type { DynamicSamplingContext, PropagationContext } from '@sentry/types';
6-
import { SENTRY_BAGGAGE_KEY_PREFIX, generateSentryTraceHeader, tracingContextFromHeaders } from '@sentry/utils';
6+
import { SENTRY_BAGGAGE_KEY_PREFIX, generateSentryTraceHeader, propagationContextFromHeaders } from '@sentry/utils';
77

88
import { SENTRY_BAGGAGE_HEADER, SENTRY_TRACE_HEADER } from './constants';
99
import { getClient } from './custom/hub';
@@ -55,7 +55,7 @@ export class SentryPropagator extends W3CBaggagePropagator {
5555
: maybeSentryTraceHeader
5656
: undefined;
5757

58-
const { propagationContext } = tracingContextFromHeaders(sentryTraceHeader, maybeBaggageHeader);
58+
const propagationContext = propagationContextFromHeaders(sentryTraceHeader, maybeBaggageHeader);
5959

6060
// Add propagation context to context
6161
const contextWithPropagationContext = setPropagationContextOnContext(context, propagationContext);

packages/remix/src/utils/instrumentServer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ export function startRequestHandlerTransaction(
401401
method: string;
402402
},
403403
): Transaction {
404+
// eslint-disable-next-line deprecation/deprecation
404405
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
405406
request.headers['sentry-trace'],
406407
request.headers.baggage,

packages/sveltekit/src/server/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import { DEBUG_BUILD } from '../common/debug-build';
1010
*
1111
* Sets propagation context as a side effect.
1212
*/
13+
// eslint-disable-next-line deprecation/deprecation
1314
export function getTracePropagationData(event: RequestEvent): ReturnType<typeof tracingContextFromHeaders> {
1415
const sentryTraceHeader = event.request.headers.get('sentry-trace') || '';
1516
const baggageHeader = event.request.headers.get('baggage');
17+
// eslint-disable-next-line deprecation/deprecation
1618
return tracingContextFromHeaders(sentryTraceHeader, baggageHeader);
1719
}
1820

packages/tracing-internal/src/browser/browserTracingIntegration.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
browserPerformanceTimeOrigin,
2424
getDomElement,
2525
logger,
26-
tracingContextFromHeaders,
26+
propagationContextFromHeaders,
2727
} from '@sentry/utils';
2828

2929
import { DEBUG_BUILD } from '../common/debug-build';
@@ -203,21 +203,23 @@ export const browserTracingIntegration = ((_options: Partial<BrowserTracingOptio
203203
if (isPageloadTransaction) {
204204
const sentryTrace = isPageloadTransaction ? getMetaContent('sentry-trace') : '';
205205
const baggage = isPageloadTransaction ? getMetaContent('baggage') : undefined;
206-
const { traceparentData, dynamicSamplingContext } = tracingContextFromHeaders(sentryTrace, baggage);
206+
const { traceId, dsc, parentSpanId, sampled } = propagationContextFromHeaders(sentryTrace, baggage);
207207
expandedContext = {
208+
traceId,
209+
parentSpanId,
210+
parentSampled: sampled,
208211
...context,
209-
...traceparentData,
210212
metadata: {
211213
// eslint-disable-next-line deprecation/deprecation
212214
...context.metadata,
213-
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
215+
dynamicSamplingContext: dsc,
214216
},
215217
trimEnd: true,
216218
};
217219
} else {
218220
expandedContext = {
219-
...context,
220221
trimEnd: true,
222+
...context,
221223
};
222224
}
223225

packages/tracing-internal/src/browser/browsertracing.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
startIdleTransaction,
99
} from '@sentry/core';
1010
import type { EventProcessor, Integration, Transaction, TransactionContext, TransactionSource } from '@sentry/types';
11-
import { getDomElement, logger, tracingContextFromHeaders } from '@sentry/utils';
11+
import { getDomElement, logger, propagationContextFromHeaders } from '@sentry/utils';
1212

1313
import { DEBUG_BUILD } from '../common/debug-build';
1414
import { registerBackgroundTabDetection } from './backgroundtab';
@@ -312,21 +312,23 @@ export class BrowserTracing implements Integration {
312312
if (isPageloadTransaction) {
313313
const sentryTrace = isPageloadTransaction ? getMetaContent('sentry-trace') : '';
314314
const baggage = isPageloadTransaction ? getMetaContent('baggage') : undefined;
315-
const { traceparentData, dynamicSamplingContext } = tracingContextFromHeaders(sentryTrace, baggage);
315+
const { traceId, dsc, parentSpanId, sampled } = propagationContextFromHeaders(sentryTrace, baggage);
316316
expandedContext = {
317+
traceId,
318+
parentSpanId,
319+
parentSampled: sampled,
317320
...context,
318-
...traceparentData,
319321
metadata: {
320322
// eslint-disable-next-line deprecation/deprecation
321323
...context.metadata,
322-
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
324+
dynamicSamplingContext: dsc,
323325
},
324326
trimEnd: true,
325327
};
326328
} else {
327329
expandedContext = {
328-
...context,
329330
trimEnd: true,
331+
...context,
330332
};
331333
}
332334

packages/utils/src/tracing.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ export function extractTraceparentData(traceparent?: string): TraceparentData |
4545

4646
/**
4747
* Create tracing context from incoming headers.
48+
*
49+
* @deprecated Use `propagationContextFromHeaders` instead.
4850
*/
51+
// TODO(v8): Remove this function
4952
export function tracingContextFromHeaders(
5053
sentryTrace: Parameters<typeof extractTraceparentData>[0],
5154
baggage: Parameters<typeof baggageHeaderToDynamicSamplingContext>[0],
@@ -83,6 +86,34 @@ export function tracingContextFromHeaders(
8386
}
8487
}
8588

89+
/**
90+
* Create a propagation context from incoming headers.
91+
*/
92+
export function propagationContextFromHeaders(
93+
sentryTrace: string | undefined,
94+
baggage: string | number | boolean | string[] | null | undefined,
95+
): PropagationContext {
96+
const traceparentData = extractTraceparentData(sentryTrace);
97+
const dynamicSamplingContext = baggageHeaderToDynamicSamplingContext(baggage);
98+
99+
const { traceId, parentSpanId, parentSampled } = traceparentData || {};
100+
101+
if (!traceparentData) {
102+
return {
103+
traceId: traceId || uuid4(),
104+
spanId: uuid4().substring(16),
105+
};
106+
} else {
107+
return {
108+
traceId: traceId || uuid4(),
109+
parentSpanId: parentSpanId || uuid4().substring(16),
110+
spanId: uuid4().substring(16),
111+
sampled: parentSampled,
112+
dsc: dynamicSamplingContext || {}, // If we have traceparent data but no DSC it means we are not head of trace and we must freeze it
113+
};
114+
}
115+
}
116+
86117
/**
87118
* Create sentry-trace header from span context values.
88119
*/

packages/utils/test/tracing.test.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,66 @@
1-
import { tracingContextFromHeaders } from '../src/tracing';
1+
import { propagationContextFromHeaders, tracingContextFromHeaders } from '../src/tracing';
2+
3+
const EXAMPLE_SENTRY_TRACE = '12312012123120121231201212312012-1121201211212012-1';
4+
const EXAMPLE_BAGGAGE = 'sentry-release=1.2.3,sentry-foo=bar,other=baz';
25

36
describe('tracingContextFromHeaders()', () => {
47
it('should produce a frozen baggage (empty object) when there is an incoming trace but no baggage header', () => {
8+
// eslint-disable-next-line deprecation/deprecation
59
const tracingContext = tracingContextFromHeaders('12312012123120121231201212312012-1121201211212012-1', undefined);
610
expect(tracingContext.dynamicSamplingContext).toEqual({});
711
expect(tracingContext.propagationContext.dsc).toEqual({});
812
});
913
});
14+
15+
describe('propagationContextFromHeaders()', () => {
16+
it('returns a completely new propagation context when no sentry-trace data is given but baggage data is given', () => {
17+
const result = propagationContextFromHeaders(undefined, undefined);
18+
expect(result).toEqual({
19+
traceId: expect.any(String),
20+
spanId: expect.any(String),
21+
});
22+
});
23+
24+
it('returns a completely new propagation context when no sentry-trace data is given', () => {
25+
const result = propagationContextFromHeaders(undefined, EXAMPLE_BAGGAGE);
26+
expect(result).toEqual({
27+
traceId: expect.any(String),
28+
spanId: expect.any(String),
29+
});
30+
});
31+
32+
it('returns the correct traceparent data within the propagation context when sentry trace data is given', () => {
33+
const result = propagationContextFromHeaders(EXAMPLE_SENTRY_TRACE, undefined);
34+
expect(result).toEqual(
35+
expect.objectContaining({
36+
traceId: '12312012123120121231201212312012',
37+
parentSpanId: '1121201211212012',
38+
spanId: expect.any(String),
39+
sampled: true,
40+
}),
41+
);
42+
});
43+
44+
it('returns a frozen dynamic sampling context (empty object) when there is an incoming trace but no baggage header', () => {
45+
const result = propagationContextFromHeaders(EXAMPLE_SENTRY_TRACE, undefined);
46+
expect(result).toEqual(
47+
expect.objectContaining({
48+
dsc: {},
49+
}),
50+
);
51+
});
52+
53+
it('returns the correct trace parent data when both sentry-trace and baggage are given', () => {
54+
const result = propagationContextFromHeaders(EXAMPLE_SENTRY_TRACE, EXAMPLE_BAGGAGE);
55+
expect(result).toEqual({
56+
traceId: '12312012123120121231201212312012',
57+
parentSpanId: '1121201211212012',
58+
spanId: expect.any(String),
59+
sampled: true,
60+
dsc: {
61+
release: '1.2.3',
62+
foo: 'bar',
63+
},
64+
});
65+
});
66+
});

0 commit comments

Comments
 (0)