Skip to content

Commit f013bca

Browse files
committed
add propagation context to scope
1 parent 96367bf commit f013bca

File tree

6 files changed

+80
-5
lines changed

6 files changed

+80
-5
lines changed

packages/core/src/scope.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
Extra,
1212
Extras,
1313
Primitive,
14+
PropagationContext,
1415
RequestSession,
1516
Scope as ScopeInterface,
1617
ScopeContext,
@@ -29,6 +30,7 @@ import {
2930
isThenable,
3031
logger,
3132
SyncPromise,
33+
uuid4,
3234
} from '@sentry/utils';
3335

3436
import { updateSession } from './session';
@@ -70,6 +72,9 @@ export class Scope implements ScopeInterface {
7072
/** Attachments */
7173
protected _attachments: Attachment[];
7274

75+
/** Propagation Context for distributed tracing */
76+
protected _propagationContext: PropagationContext;
77+
7378
/**
7479
* A place to stash data which is needed at some point in the SDK's event processing pipeline but which shouldn't get
7580
* sent to Sentry
@@ -108,6 +113,7 @@ export class Scope implements ScopeInterface {
108113
this._extra = {};
109114
this._contexts = {};
110115
this._sdkProcessingMetadata = {};
116+
this._propagationContext = generatePropagationContext();
111117
}
112118

113119
/**
@@ -131,6 +137,7 @@ export class Scope implements ScopeInterface {
131137
newScope._requestSession = scope._requestSession;
132138
newScope._attachments = [...scope._attachments];
133139
newScope._sdkProcessingMetadata = { ...scope._sdkProcessingMetadata };
140+
newScope._propagationContext = { ...scope._propagationContext };
134141
}
135142
return newScope;
136143
}
@@ -347,6 +354,9 @@ export class Scope implements ScopeInterface {
347354
if (captureContext._requestSession) {
348355
this._requestSession = captureContext._requestSession;
349356
}
357+
if (captureContext._propagationContext) {
358+
this._propagationContext = captureContext._propagationContext;
359+
}
350360
} else if (isPlainObject(captureContext)) {
351361
// eslint-disable-next-line no-param-reassign
352362
captureContext = captureContext as ScopeContext;
@@ -365,6 +375,9 @@ export class Scope implements ScopeInterface {
365375
if (captureContext.requestSession) {
366376
this._requestSession = captureContext.requestSession;
367377
}
378+
if (captureContext.propagationContext) {
379+
this._propagationContext = captureContext.propagationContext;
380+
}
368381
}
369382

370383
return this;
@@ -387,6 +400,7 @@ export class Scope implements ScopeInterface {
387400
this._session = undefined;
388401
this._notifyScopeListeners();
389402
this._attachments = [];
403+
this._propagationContext = generatePropagationContext();
390404
return this;
391405
}
392406

@@ -500,7 +514,11 @@ export class Scope implements ScopeInterface {
500514
event.breadcrumbs = [...(event.breadcrumbs || []), ...this._breadcrumbs];
501515
event.breadcrumbs = event.breadcrumbs.length > 0 ? event.breadcrumbs : undefined;
502516

503-
event.sdkProcessingMetadata = { ...event.sdkProcessingMetadata, ...this._sdkProcessingMetadata };
517+
event.sdkProcessingMetadata = {
518+
...event.sdkProcessingMetadata,
519+
...this._sdkProcessingMetadata,
520+
propagationContext: this._propagationContext,
521+
};
504522

505523
return this._notifyEventProcessors([...getGlobalEventProcessors(), ...this._eventProcessors], event, hint);
506524
}
@@ -598,3 +616,11 @@ function getGlobalEventProcessors(): EventProcessor[] {
598616
export function addGlobalEventProcessor(callback: EventProcessor): void {
599617
getGlobalEventProcessors().push(callback);
600618
}
619+
620+
function generatePropagationContext(): PropagationContext {
621+
return {
622+
traceId: uuid4(),
623+
spanId: uuid4().substring(16),
624+
sampled: false,
625+
};
626+
}

packages/hub/test/scope.test.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ describe('Scope', () => {
1212
GLOBAL_OBJ.__SENTRY__.globalEventProcessors = undefined;
1313
});
1414

15+
describe('init', () => {
16+
test('it creates a propagation context', () => {
17+
const scope = new Scope();
18+
19+
// @ts-ignore asserting on private properties
20+
expect(scope._propagationContext).toEqual({
21+
traceId: expect.any(String),
22+
spanId: expect.any(String),
23+
sampled: false,
24+
dsc: undefined,
25+
parentSpanId: undefined,
26+
});
27+
});
28+
});
29+
1530
describe('attributes modification', () => {
1631
test('setFingerprint', () => {
1732
const scope = new Scope();
@@ -193,6 +208,14 @@ describe('Scope', () => {
193208
expect(parentScope.getRequestSession()).toEqual({ status: 'ok' });
194209
expect(scope.getRequestSession()).toEqual({ status: 'ok' });
195210
});
211+
212+
test('should clone propagation context', () => {
213+
const parentScope = new Scope();
214+
const scope = Scope.clone(parentScope);
215+
216+
// @ts-ignore accessing private property for test
217+
expect(scope._propagationContext).toEqual(parentScope._propagationContext);
218+
});
196219
});
197220

198221
describe('applyToEvent', () => {
@@ -339,7 +362,7 @@ describe('Scope', () => {
339362
scope.setSpan(span);
340363
const event: Event = {
341364
contexts: {
342-
trace: { a: 'c' },
365+
trace: { a: 'c' } as any,
343366
},
344367
};
345368
return scope.applyToEvent(event).then(processedEvent => {
@@ -383,6 +406,8 @@ describe('Scope', () => {
383406

384407
test('clear', () => {
385408
const scope = new Scope();
409+
// @ts-expect-error accessing private property
410+
const oldPropagationContext = scope._propagationContext;
386411
scope.setExtra('a', 2);
387412
scope.setTag('a', 'b');
388413
scope.setUser({ id: '1' });
@@ -393,6 +418,14 @@ describe('Scope', () => {
393418
scope.clear();
394419
expect((scope as any)._extra).toEqual({});
395420
expect((scope as any)._requestSession).toEqual(undefined);
421+
// @ts-expect-error accessing private property
422+
expect(scope._propagationContext).toEqual({
423+
traceId: expect.any(String),
424+
spanId: expect.any(String),
425+
sampled: false,
426+
});
427+
// @ts-expect-error accessing private property
428+
expect(scope._propagationContext).not.toEqual(oldPropagationContext);
396429
});
397430

398431
test('clearBreadcrumbs', () => {
@@ -486,6 +519,8 @@ describe('Scope', () => {
486519
expect(updatedScope._level).toEqual('warning');
487520
expect(updatedScope._fingerprint).toEqual(['bar']);
488521
expect(updatedScope._requestSession.status).toEqual('ok');
522+
// @ts-ignore accessing private property for test
523+
expect(updatedScope._propagationContext).toEqual(localScope._propagationContext);
489524
});
490525

491526
test('given an empty instance of Scope, it should preserve all the original scope data', () => {
@@ -518,7 +553,13 @@ describe('Scope', () => {
518553
tags: { bar: '3', baz: '4' },
519554
user: { id: '42' },
520555
requestSession: { status: 'errored' as RequestSessionStatus },
556+
propagationContext: {
557+
traceId: '8949daf83f4a4a70bee4c1eb9ab242ed',
558+
spanId: 'a024ad8fea82680e',
559+
sampled: true,
560+
},
521561
};
562+
522563
const updatedScope = scope.update(localAttributes) as any;
523564

524565
expect(updatedScope._tags).toEqual({
@@ -540,6 +581,11 @@ describe('Scope', () => {
540581
expect(updatedScope._level).toEqual('warning');
541582
expect(updatedScope._fingerprint).toEqual(['bar']);
542583
expect(updatedScope._requestSession).toEqual({ status: 'errored' });
584+
expect(updatedScope._propagationContext).toEqual({
585+
traceId: '8949daf83f4a4a70bee4c1eb9ab242ed',
586+
spanId: 'a024ad8fea82680e',
587+
sampled: true,
588+
});
543589
});
544590
});
545591

packages/types/src/context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface Contexts extends Record<string, Context | undefined> {
88
os?: OsContext;
99
culture?: CultureContext;
1010
response?: ResponseContext;
11+
trace?: TraceContext;
1112
}
1213

1314
export interface AppContext extends Record<string, unknown> {

packages/types/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export type { Span, SpanContext } from './span';
8383
export type { StackFrame } from './stackframe';
8484
export type { Stacktrace, StackParser, StackLineParser, StackLineParserFn } from './stacktrace';
8585
export type { TextEncoderInternal } from './textencoder';
86-
export type { TracePropagationTargets } from './tracing';
86+
export type { PropagationContext, TracePropagationTargets } from './tracing';
8787
export type {
8888
CustomSamplingContext,
8989
SamplingContext,

packages/types/src/scope.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { Primitive } from './misc';
77
import type { RequestSession, Session } from './session';
88
import type { Severity, SeverityLevel } from './severity';
99
import type { Span } from './span';
10+
import type { PropagationContext } from './tracing';
1011
import type { Transaction } from './transaction';
1112
import type { User } from './user';
1213

@@ -23,6 +24,7 @@ export interface ScopeContext {
2324
tags: { [key: string]: Primitive };
2425
fingerprint: string[];
2526
requestSession: RequestSession;
27+
propagationContext: PropagationContext;
2628
}
2729

2830
/**

packages/types/src/tracing.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export type TracePropagationTargets = (string | RegExp)[];
55
export interface PropagationContext {
66
traceId: string;
77
spanId: string;
8-
parentSpanId: string;
98
sampled: boolean;
10-
dsc: DynamicSamplingContext;
9+
parentSpanId?: string;
10+
dsc?: DynamicSamplingContext;
1111
}

0 commit comments

Comments
 (0)