Skip to content

Commit b17d167

Browse files
committed
ref: merge global scope in prepareEvent
1 parent da61340 commit b17d167

File tree

9 files changed

+309
-117
lines changed

9 files changed

+309
-117
lines changed

packages/core/src/scope.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ export class Scope implements ScopeInterface {
456456

457457
/**
458458
* @inheritDoc
459+
* @deprecated Use `getScopeData()` instead.
459460
*/
460461
public getAttachments(): Attachment[] {
461462
const data = this.getScopeData();
@@ -472,7 +473,7 @@ export class Scope implements ScopeInterface {
472473
}
473474

474475
/** @inheritDoc */
475-
public getPerScopeData(): ScopeData {
476+
public getScopeData(): ScopeData {
476477
const {
477478
_breadcrumbs,
478479
_attachments,
@@ -506,16 +507,6 @@ export class Scope implements ScopeInterface {
506507
};
507508
}
508509

509-
/** @inheritdoc */
510-
public getScopeData(): ScopeData {
511-
const data = getGlobalScope().getPerScopeData();
512-
const scopeData = this.getPerScopeData();
513-
514-
mergeScopeData(data, scopeData);
515-
516-
return data;
517-
}
518-
519510
/**
520511
* Applies data from the scope to the event and runs all event processors on it.
521512
*

packages/core/src/utils/prepareEvent.ts

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { GLOBAL_OBJ, addExceptionMechanism, dateTimestampInSeconds, normalize, t
1313

1414
import { DEFAULT_ENVIRONMENT } from '../constants';
1515
import { getGlobalEventProcessors, notifyEventProcessors } from '../eventProcessors';
16-
import { Scope } from '../scope';
17-
import { applyScopeDataToEvent } from './applyScopeDataToEvent';
16+
import { Scope, getGlobalScope } from '../scope';
17+
import { applyScopeDataToEvent, mergeScopeData } from './applyScopeDataToEvent';
1818

1919
/**
2020
* This type makes sure that we get either a CaptureContext, OR an EventHint.
@@ -74,36 +74,32 @@ export function prepareEvent(
7474
}
7575

7676
const clientEventProcessors = client && client.getEventProcessors ? client.getEventProcessors() : [];
77-
// TODO (v8): Update this order to be: Global > Client > Scope
78-
const eventProcessors = [
79-
...clientEventProcessors,
80-
// eslint-disable-next-line deprecation/deprecation
81-
...getGlobalEventProcessors(),
82-
];
8377

8478
// This should be the last thing called, since we want that
8579
// {@link Hub.addEventProcessor} gets the finished prepared event.
86-
//
87-
// We need to check for the existence of `finalScope.getAttachments`
88-
// because `getAttachments` can be undefined if users are using an older version
89-
// of `@sentry/core` that does not have the `getAttachments` method.
90-
// See: https://github.com/getsentry/sentry-javascript/issues/5229
80+
// Merge scope data together
81+
const data = getGlobalScope().getScopeData();
82+
9183
if (finalScope) {
92-
// Collect attachments from the hint and scope
93-
if (finalScope.getAttachments) {
94-
const attachments = [...(hint.attachments || []), ...finalScope.getAttachments()];
84+
const finalScopeData = finalScope.getScopeData();
85+
mergeScopeData(data, finalScopeData);
86+
}
9587

96-
if (attachments.length) {
97-
hint.attachments = attachments;
98-
}
99-
}
88+
const attachments = [...(hint.attachments || []), ...data.attachments];
89+
if (attachments.length) {
90+
hint.attachments = attachments;
91+
}
10092

101-
const scopeData = finalScope.getScopeData();
102-
applyScopeDataToEvent(prepared, scopeData);
93+
applyScopeDataToEvent(prepared, data);
10394

95+
// TODO (v8): Update this order to be: Global > Client > Scope
96+
const eventProcessors = [
97+
...clientEventProcessors,
98+
// eslint-disable-next-line deprecation/deprecation
99+
...getGlobalEventProcessors(),
104100
// Run scope event processors _after_ all other processors
105-
eventProcessors.push(...scopeData.eventProcessors);
106-
}
101+
...data.eventProcessors,
102+
];
107103

108104
const result = notifyEventProcessors(eventProcessors, prepared, hint);
109105

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Client, Envelope, Event, Span, Transaction } from '@sentry/types';
22
import { SentryError, SyncPromise, dsnToString, logger } from '@sentry/utils';
33

4-
import { Hub, Scope, makeSession } from '../../src';
4+
import { Hub, Scope, clearGlobalData, makeSession } from '../../src';
55
import * as integrationModule from '../../src/integration';
66
import { TestClient, getDefaultTestClientOptions } from '../mocks/client';
77
import { AdHocIntegration, TestIntegration } from '../mocks/integration';
@@ -54,6 +54,7 @@ describe('BaseClient', () => {
5454
beforeEach(() => {
5555
TestClient.sendEventCalled = undefined;
5656
TestClient.instance = undefined;
57+
clearGlobalData();
5758
});
5859

5960
afterEach(() => {
@@ -756,7 +757,8 @@ describe('BaseClient', () => {
756757
expect(TestClient.instance!.event!).toEqual(
757758
expect.objectContaining({
758759
breadcrumbs: [normalizedBreadcrumb, normalizedBreadcrumb, normalizedBreadcrumb],
759-
contexts: normalizedObject,
760+
// also has trace context from global scope
761+
contexts: { ...normalizedObject, trace: expect.anything() },
760762
environment: 'production',
761763
event_id: '42',
762764
extra: normalizedObject,
@@ -805,7 +807,8 @@ describe('BaseClient', () => {
805807
expect(TestClient.instance!.event!).toEqual(
806808
expect.objectContaining({
807809
breadcrumbs: [normalizedBreadcrumb, normalizedBreadcrumb, normalizedBreadcrumb],
808-
contexts: normalizedObject,
810+
// also has trace context from global scope
811+
contexts: { ...normalizedObject, trace: expect.anything() },
809812
environment: 'production',
810813
event_id: '42',
811814
extra: normalizedObject,
@@ -859,7 +862,8 @@ describe('BaseClient', () => {
859862
expect(TestClient.instance!.event!).toEqual(
860863
expect.objectContaining({
861864
breadcrumbs: [normalizedBreadcrumb, normalizedBreadcrumb, normalizedBreadcrumb],
862-
contexts: normalizedObject,
865+
// also has trace context from global scope
866+
contexts: { ...normalizedObject, trace: expect.anything() },
863867
environment: 'production',
864868
event_id: '42',
865869
extra: normalizedObject,

packages/core/test/lib/prepareEvent.test.ts

Lines changed: 185 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1-
import type { Event, EventHint, ScopeContext } from '@sentry/types';
1+
import type {
2+
Attachment,
3+
Breadcrumb,
4+
Client,
5+
ClientOptions,
6+
Event,
7+
EventHint,
8+
EventProcessor,
9+
ScopeContext,
10+
} from '@sentry/types';
211
import { GLOBAL_OBJ, createStackParser } from '@sentry/utils';
12+
import { clearGlobalData } from '../../src';
313

4-
import { Scope } from '../../src/scope';
5-
import { applyDebugIds, applyDebugMeta, parseEventHintOrCaptureContext } from '../../src/utils/prepareEvent';
14+
import { Scope, getGlobalScope } from '../../src/scope';
15+
import {
16+
applyDebugIds,
17+
applyDebugMeta,
18+
parseEventHintOrCaptureContext,
19+
prepareEvent,
20+
} from '../../src/utils/prepareEvent';
621

722
describe('applyDebugIds', () => {
823
afterEach(() => {
@@ -173,3 +188,170 @@ describe('parseEventHintOrCaptureContext', () => {
173188
});
174189
});
175190
});
191+
192+
describe('prepareEvent', () => {
193+
beforeEach(() => {
194+
clearGlobalData();
195+
});
196+
197+
it('works without any scope data', async () => {
198+
const eventProcessor = jest.fn((a: unknown) => a) as EventProcessor;
199+
200+
const scope = new Scope();
201+
202+
const event = { message: 'foo' };
203+
204+
const options = {} as ClientOptions;
205+
const client = {
206+
getEventProcessors() {
207+
return [eventProcessor];
208+
},
209+
} as Client;
210+
const processedEvent = await prepareEvent(
211+
options,
212+
event,
213+
{
214+
integrations: [],
215+
},
216+
scope,
217+
client,
218+
);
219+
220+
expect(eventProcessor).toHaveBeenCalledWith(processedEvent, {
221+
integrations: [],
222+
// no attachments are added to hint
223+
});
224+
225+
expect(processedEvent).toEqual({
226+
timestamp: expect.any(Number),
227+
event_id: expect.any(String),
228+
environment: 'production',
229+
message: 'foo',
230+
sdkProcessingMetadata: {
231+
propagationContext: {
232+
spanId: expect.any(String),
233+
traceId: expect.any(String),
234+
},
235+
},
236+
});
237+
});
238+
239+
it('merges scope data', async () => {
240+
const breadcrumb1 = { message: '1', timestamp: 111 } as Breadcrumb;
241+
const breadcrumb2 = { message: '2', timestamp: 222 } as Breadcrumb;
242+
const breadcrumb3 = { message: '3', timestamp: 123 } as Breadcrumb;
243+
244+
const eventProcessor1 = jest.fn((a: unknown) => a) as EventProcessor;
245+
const eventProcessor2 = jest.fn((b: unknown) => b) as EventProcessor;
246+
247+
const attachment1 = { filename: '1' } as Attachment;
248+
const attachment2 = { filename: '2' } as Attachment;
249+
250+
const scope = new Scope();
251+
scope.update({
252+
user: { id: '1', email: '[email protected]' },
253+
tags: { tag1: 'aa', tag2: 'aa' },
254+
extra: { extra1: 'aa', extra2: 'aa' },
255+
contexts: { os: { name: 'os1' }, culture: { display_name: 'name1' } },
256+
propagationContext: { spanId: '1', traceId: '1' },
257+
fingerprint: ['aa'],
258+
});
259+
scope.addBreadcrumb(breadcrumb1);
260+
scope.addEventProcessor(eventProcessor1);
261+
scope.addAttachment(attachment1);
262+
263+
const globalScope = getGlobalScope();
264+
265+
globalScope.addBreadcrumb(breadcrumb2);
266+
globalScope.addEventProcessor(eventProcessor2);
267+
globalScope.setSDKProcessingMetadata({ aa: 'aa' });
268+
globalScope.addAttachment(attachment2);
269+
270+
const event = { message: 'foo', breadcrumbs: [breadcrumb3], fingerprint: ['dd'] };
271+
272+
const options = {} as ClientOptions;
273+
const processedEvent = await prepareEvent(
274+
options,
275+
event,
276+
{
277+
integrations: [],
278+
},
279+
scope,
280+
);
281+
282+
expect(eventProcessor1).toHaveBeenCalledTimes(1);
283+
expect(eventProcessor2).toHaveBeenCalledTimes(1);
284+
285+
// Test that attachments are correctly merged
286+
expect(eventProcessor1).toHaveBeenCalledWith(processedEvent, {
287+
integrations: [],
288+
attachments: [attachment2, attachment1],
289+
});
290+
291+
expect(processedEvent).toEqual({
292+
timestamp: expect.any(Number),
293+
event_id: expect.any(String),
294+
environment: 'production',
295+
message: 'foo',
296+
user: { id: '1', email: '[email protected]' },
297+
tags: { tag1: 'aa', tag2: 'aa' },
298+
extra: { extra1: 'aa', extra2: 'aa' },
299+
contexts: { os: { name: 'os1' }, culture: { display_name: 'name1' } },
300+
fingerprint: ['dd', 'aa'],
301+
breadcrumbs: [breadcrumb3, breadcrumb2, breadcrumb1],
302+
sdkProcessingMetadata: {
303+
aa: 'aa',
304+
propagationContext: {
305+
spanId: '1',
306+
traceId: '1',
307+
},
308+
},
309+
});
310+
});
311+
312+
it('works without a scope', async () => {
313+
const breadcrumb1 = { message: '1', timestamp: 111 } as Breadcrumb;
314+
const breadcrumb2 = { message: '2', timestamp: 222 } as Breadcrumb;
315+
316+
const eventProcessor1 = jest.fn((a: unknown) => a) as EventProcessor;
317+
318+
const attachment1 = { filename: '1' } as Attachment;
319+
const attachment2 = { filename: '2' } as Attachment;
320+
321+
const globalScope = getGlobalScope();
322+
323+
globalScope.addBreadcrumb(breadcrumb1);
324+
globalScope.addEventProcessor(eventProcessor1);
325+
globalScope.setSDKProcessingMetadata({ aa: 'aa' });
326+
globalScope.addAttachment(attachment1);
327+
328+
const event = { message: 'foo', breadcrumbs: [breadcrumb2], fingerprint: ['dd'] };
329+
330+
const options = {} as ClientOptions;
331+
const processedEvent = await prepareEvent(options, event, {
332+
integrations: [],
333+
attachments: [attachment2],
334+
});
335+
336+
expect(eventProcessor1).toHaveBeenCalledTimes(1);
337+
338+
// Test that attachments are correctly merged
339+
expect(eventProcessor1).toHaveBeenCalledWith(processedEvent, {
340+
integrations: [],
341+
attachments: [attachment2, attachment1],
342+
});
343+
344+
expect(processedEvent).toEqual({
345+
timestamp: expect.any(Number),
346+
event_id: expect.any(String),
347+
environment: 'production',
348+
message: 'foo',
349+
fingerprint: ['dd'],
350+
breadcrumbs: [breadcrumb2, breadcrumb1],
351+
sdkProcessingMetadata: {
352+
aa: 'aa',
353+
propagationContext: globalScope.getPropagationContext(),
354+
},
355+
});
356+
});
357+
});

0 commit comments

Comments
 (0)