Skip to content

Commit 8e4745c

Browse files
authored
Merge branch 'develop' into onur/remix-v2
2 parents 8c7636e + f1ede57 commit 8e4745c

File tree

16 files changed

+188
-26
lines changed

16 files changed

+188
-26
lines changed

packages/browser-integration-tests/suites/replay/captureReplay/test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT
5656
version: SDK_VERSION,
5757
name: 'sentry.javascript.browser',
5858
},
59-
sdkProcessingMetadata: {},
6059
request: {
6160
url: expect.stringContaining('/dist/index.html'),
6261
headers: {
@@ -94,7 +93,6 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT
9493
version: SDK_VERSION,
9594
name: 'sentry.javascript.browser',
9695
},
97-
sdkProcessingMetadata: {},
9896
request: {
9997
url: expect.stringContaining('/dist/index.html'),
10098
headers: {

packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ sentryTest('should capture replays (@sentry/replay export)', async ({ getLocalTe
5656
version: SDK_VERSION,
5757
name: 'sentry.javascript.browser',
5858
},
59-
sdkProcessingMetadata: {},
6059
request: {
6160
url: expect.stringContaining('/dist/index.html'),
6261
headers: {
@@ -94,7 +93,6 @@ sentryTest('should capture replays (@sentry/replay export)', async ({ getLocalTe
9493
version: SDK_VERSION,
9594
name: 'sentry.javascript.browser',
9695
},
97-
sdkProcessingMetadata: {},
9896
request: {
9997
url: expect.stringContaining('/dist/index.html'),
10098
headers: {

packages/browser-integration-tests/utils/replayEventTemplates.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ const DEFAULT_REPLAY_EVENT = {
3030
version: SDK_VERSION,
3131
name: 'sentry.javascript.browser',
3232
},
33-
sdkProcessingMetadata: {},
3433
request: {
3534
url: expect.stringContaining('/dist/index.html'),
3635
headers: {

packages/core/src/baseclient.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
Integration,
1616
IntegrationClass,
1717
Outcome,
18+
PropagationContext,
1819
SdkMetadata,
1920
Session,
2021
SessionAggregates,
@@ -29,6 +30,7 @@ import {
2930
addItemToEnvelope,
3031
checkOrSetAlreadyCaught,
3132
createAttachmentEnvelopeItem,
33+
dropUndefinedKeys,
3234
isPlainObject,
3335
isPrimitive,
3436
isThenable,
@@ -41,6 +43,7 @@ import {
4143
} from '@sentry/utils';
4244

4345
import { getEnvelopeEndpointWithUrlEncodedAuth } from './api';
46+
import { DEFAULT_ENVIRONMENT } from './constants';
4447
import { createEventEnvelope, createSessionEnvelope } from './envelope';
4548
import type { IntegrationIndex } from './integration';
4649
import { setupIntegration, setupIntegrations } from './integration';
@@ -507,7 +510,49 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
507510
if (!hint.integrations && integrations.length > 0) {
508511
hint.integrations = integrations;
509512
}
510-
return prepareEvent(options, event, hint, scope);
513+
return prepareEvent(options, event, hint, scope).then(evt => {
514+
if (evt === null) {
515+
return evt;
516+
}
517+
518+
// If a trace context is not set on the event, we use the propagationContext set on the event to
519+
// generate a trace context. If the propagationContext does not have a dynamic sampling context, we
520+
// also generate one for it.
521+
const { propagationContext } = evt.sdkProcessingMetadata || {};
522+
const trace = evt.contexts && evt.contexts.trace;
523+
if (!trace && propagationContext) {
524+
const { traceId: trace_id, spanId, parentSpanId, dsc } = propagationContext as PropagationContext;
525+
evt.contexts = {
526+
trace: {
527+
trace_id,
528+
span_id: spanId,
529+
parent_span_id: parentSpanId,
530+
},
531+
...evt.contexts,
532+
};
533+
534+
const { publicKey: public_key } = this.getDsn() || {};
535+
const { segment: user_segment } = (scope && scope.getUser()) || {};
536+
537+
let dynamicSamplingContext = dsc;
538+
if (!dsc) {
539+
dynamicSamplingContext = dropUndefinedKeys({
540+
environment: options.environment || DEFAULT_ENVIRONMENT,
541+
release: options.release,
542+
user_segment,
543+
public_key,
544+
trace_id,
545+
});
546+
this.emit && this.emit('createDsc', dynamicSamplingContext);
547+
}
548+
549+
evt.sdkProcessingMetadata = {
550+
dynamicSamplingContext,
551+
...evt.sdkProcessingMetadata,
552+
};
553+
}
554+
return evt;
555+
});
511556
}
512557

513558
/**

packages/core/src/scope.ts

Lines changed: 35 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
}
@@ -514,6 +532,14 @@ export class Scope implements ScopeInterface {
514532
return this;
515533
}
516534

535+
/**
536+
* @inheritdoc
537+
*/
538+
public setPropagationContext(context: PropagationContext): this {
539+
this._propagationContext = context;
540+
return this;
541+
}
542+
517543
/**
518544
* This will be called after {@link applyToEvent} is finished.
519545
*/
@@ -598,3 +624,11 @@ function getGlobalEventProcessors(): EventProcessor[] {
598624
export function addGlobalEventProcessor(callback: EventProcessor): void {
599625
getGlobalEventProcessors().push(callback);
600626
}
627+
628+
function generatePropagationContext(): PropagationContext {
629+
return {
630+
traceId: uuid4(),
631+
spanId: uuid4().substring(16),
632+
sampled: false,
633+
};
634+
}

packages/core/test/lib/base.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,28 @@ describe('BaseClient', () => {
492492
);
493493
});
494494

495+
test('it adds a trace context all events', () => {
496+
expect.assertions(1);
497+
498+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
499+
const client = new TestClient(options);
500+
const scope = new Scope();
501+
502+
client.captureEvent({ message: 'message' }, { event_id: 'wat' }, scope);
503+
504+
expect(TestClient.instance!.event!).toEqual(
505+
expect.objectContaining({
506+
contexts: {
507+
trace: {
508+
parent_span_id: undefined,
509+
span_id: expect.any(String),
510+
trace_id: expect.any(String),
511+
},
512+
},
513+
}),
514+
);
515+
});
516+
495517
test('adds `event_id` from hint if available', () => {
496518
expect.assertions(1);
497519

packages/hub/test/scope.test.ts

Lines changed: 52 additions & 2 deletions
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', () => {
@@ -220,7 +243,11 @@ describe('Scope', () => {
220243
expect(processedEvent!.transaction).toEqual('/abc');
221244
expect(processedEvent!.breadcrumbs![0]).toHaveProperty('message', 'test');
222245
expect(processedEvent!.contexts).toEqual({ os: { id: '1' } });
223-
expect(processedEvent!.sdkProcessingMetadata).toEqual({ dogs: 'are great!' });
246+
expect(processedEvent!.sdkProcessingMetadata).toEqual({
247+
dogs: 'are great!',
248+
// @ts-expect-error accessing private property for test
249+
propagationContext: scope._propagationContext,
250+
});
224251
});
225252
});
226253

@@ -339,7 +366,7 @@ describe('Scope', () => {
339366
scope.setSpan(span);
340367
const event: Event = {
341368
contexts: {
342-
trace: { a: 'c' },
369+
trace: { a: 'c' } as any,
343370
},
344371
};
345372
return scope.applyToEvent(event).then(processedEvent => {
@@ -383,6 +410,8 @@ describe('Scope', () => {
383410

384411
test('clear', () => {
385412
const scope = new Scope();
413+
// @ts-expect-error accessing private property
414+
const oldPropagationContext = scope._propagationContext;
386415
scope.setExtra('a', 2);
387416
scope.setTag('a', 'b');
388417
scope.setUser({ id: '1' });
@@ -393,6 +422,14 @@ describe('Scope', () => {
393422
scope.clear();
394423
expect((scope as any)._extra).toEqual({});
395424
expect((scope as any)._requestSession).toEqual(undefined);
425+
// @ts-expect-error accessing private property
426+
expect(scope._propagationContext).toEqual({
427+
traceId: expect.any(String),
428+
spanId: expect.any(String),
429+
sampled: false,
430+
});
431+
// @ts-expect-error accessing private property
432+
expect(scope._propagationContext).not.toEqual(oldPropagationContext);
396433
});
397434

398435
test('clearBreadcrumbs', () => {
@@ -486,6 +523,8 @@ describe('Scope', () => {
486523
expect(updatedScope._level).toEqual('warning');
487524
expect(updatedScope._fingerprint).toEqual(['bar']);
488525
expect(updatedScope._requestSession.status).toEqual('ok');
526+
// @ts-ignore accessing private property for test
527+
expect(updatedScope._propagationContext).toEqual(localScope._propagationContext);
489528
});
490529

491530
test('given an empty instance of Scope, it should preserve all the original scope data', () => {
@@ -518,7 +557,13 @@ describe('Scope', () => {
518557
tags: { bar: '3', baz: '4' },
519558
user: { id: '42' },
520559
requestSession: { status: 'errored' as RequestSessionStatus },
560+
propagationContext: {
561+
traceId: '8949daf83f4a4a70bee4c1eb9ab242ed',
562+
spanId: 'a024ad8fea82680e',
563+
sampled: true,
564+
},
521565
};
566+
522567
const updatedScope = scope.update(localAttributes) as any;
523568

524569
expect(updatedScope._tags).toEqual({
@@ -540,6 +585,11 @@ describe('Scope', () => {
540585
expect(updatedScope._level).toEqual('warning');
541586
expect(updatedScope._fingerprint).toEqual(['bar']);
542587
expect(updatedScope._requestSession).toEqual({ status: 'errored' });
588+
expect(updatedScope._propagationContext).toEqual({
589+
traceId: '8949daf83f4a4a70bee4c1eb9ab242ed',
590+
spanId: 'a024ad8fea82680e',
591+
sampled: true,
592+
});
543593
});
544594
});
545595

packages/node/test/async/domain.test.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { getCurrentHub, Hub, runWithAsyncContext, setAsyncContextStrategy } from '@sentry/core';
2-
import * as domain from 'domain';
1+
import type { Hub } from '@sentry/core';
2+
import { getCurrentHub, runWithAsyncContext, setAsyncContextStrategy } from '@sentry/core';
33

44
import { setDomainAsyncContextStrategy } from '../../src/async/domain';
55

@@ -9,13 +9,6 @@ describe('domains', () => {
99
setAsyncContextStrategy(undefined);
1010
});
1111

12-
test('without domain', () => {
13-
// @ts-ignore property active does not exist on domain
14-
expect(domain.active).toBeFalsy();
15-
const hub = getCurrentHub();
16-
expect(hub).toEqual(new Hub());
17-
});
18-
1912
test('hub scope inheritance', () => {
2013
setDomainAsyncContextStrategy();
2114

0 commit comments

Comments
 (0)