Skip to content

Commit ea7ce30

Browse files
committed
fix(replay): Ensure replay_id is removed from frozen DSC
1 parent 3f0926e commit ea7ce30

File tree

4 files changed

+40
-0
lines changed

4 files changed

+40
-0
lines changed

packages/core/src/baseclient.ts

+6
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
430430
/** @inheritdoc */
431431
public on(hook: 'createDsc', callback: (dsc: DynamicSamplingContext, rootSpan?: Span) => void): () => void;
432432

433+
/** @inheritdoc */
434+
public on(hook: 'useFrozenDsc', callback: (dsc: Partial<DynamicSamplingContext>, rootSpan: Span) => void): () => void;
435+
433436
/** @inheritdoc */
434437
public on(
435438
hook: 'beforeSendFeedback',
@@ -527,6 +530,9 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
527530
/** @inheritdoc */
528531
public emit(hook: 'createDsc', dsc: DynamicSamplingContext, rootSpan?: Span): void;
529532

533+
/** @inheritdoc */
534+
public emit(hook: 'useFrozenDsc', dsc: Partial<DynamicSamplingContext>, rootSpan: Span): void;
535+
530536
/** @inheritdoc */
531537
public emit(hook: 'beforeSendFeedback', feedback: FeedbackEvent, options?: { includeReplay: boolean }): void;
532538

packages/core/src/tracing/dynamicSamplingContext.ts

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
7272
// For core implementation, we freeze the DSC onto the span as a non-enumerable property
7373
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
7474
if (frozenDsc) {
75+
client.emit('useFrozenDsc', frozenDsc, rootSpan);
7576
return frozenDsc;
7677
}
7778

@@ -83,6 +84,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
8384
const dscOnTraceState = traceStateDsc && baggageHeaderToDynamicSamplingContext(traceStateDsc);
8485

8586
if (dscOnTraceState) {
87+
client.emit('useFrozenDsc', dscOnTraceState, rootSpan);
8688
return dscOnTraceState;
8789
}
8890

packages/replay-internal/src/util/addGlobalListeners.ts

+20
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ export function addGlobalListeners(replay: ReplayContainer): void {
4747
}
4848
});
4949

50+
// If a frozen DSC is used from a span, we want to make sure to remove the replay ID
51+
// if the session has expired in the meanwhile
52+
client.on('useFrozenDsc', (dsc: Partial<DynamicSamplingContext>) => {
53+
if (!dsc.replay_id) {
54+
return;
55+
}
56+
57+
const replayId = replay.getSessionId();
58+
if (
59+
!replayId ||
60+
!replay.isEnabled() ||
61+
// We do not want to set the DSC when in buffer mode, as that means the replay has not been sent (yet)
62+
replay.recordingMode !== 'session' ||
63+
// This returns false if the session has expired in the meanwhile
64+
!replay.checkAndHandleExpiredSession()
65+
) {
66+
delete dsc.replay_id;
67+
}
68+
});
69+
5070
client.on('spanStart', span => {
5171
replay.lastActiveSpan = span;
5272
});

packages/types/src/client.ts

+12
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ export interface Client<O extends ClientOptions = ClientOptions> {
262262
*/
263263
on(hook: 'createDsc', callback: (dsc: DynamicSamplingContext, rootSpan?: Span) => void): () => void;
264264

265+
/**
266+
* Register a callback to be used whenever a frozen DSC is used.
267+
* @returns A function that, when executed, removes the registered callback.
268+
*/
269+
on(hook: 'useFrozenDsc', callback: (dsc: Partial<DynamicSamplingContext>, rootSpan: Span) => void): () => void;
270+
265271
/**
266272
* Register a callback when a Feedback event has been prepared.
267273
* This should be used to mutate the event. The options argument can hint
@@ -366,6 +372,12 @@ export interface Client<O extends ClientOptions = ClientOptions> {
366372
*/
367373
emit(hook: 'createDsc', dsc: DynamicSamplingContext, rootSpan?: Span): void;
368374

375+
/**
376+
* Fire a hook for when a frozen DSC (Dynamic Sampling Context) from a span is used.
377+
* Expects the DSC as second argument, and the root span as third.
378+
*/
379+
emit(hook: 'useFrozenDsc', dsc: Partial<DynamicSamplingContext>, rootSpan: Span): void;
380+
369381
/**
370382
* Fire a hook event for after preparing a feedback event. Events to be given
371383
* a feedback event as the second argument, and an optional options object as

0 commit comments

Comments
 (0)