Skip to content

Commit a4c858f

Browse files
author
Luca Forstner
authored
fix(core): Temporarily store debug IDs in stack frame and only put them into debug_meta before sending (#8347)
1 parent dba9a3d commit a4c858f

File tree

2 files changed

+104
-31
lines changed

2 files changed

+104
-31
lines changed

packages/core/src/utils/prepareEvent.ts

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ export function prepareEvent(
3838
applyClientOptions(prepared, options);
3939
applyIntegrationsMetadata(prepared, integrations);
4040

41-
// Only apply debug metadata to error events.
41+
// Only put debug IDs onto frames for error events.
4242
if (event.type === undefined) {
43-
applyDebugMetadata(prepared, options.stackParser);
43+
applyDebugIds(prepared, options.stackParser);
4444
}
4545

4646
// If we have scope given to us, use it as the base for further modifications.
@@ -75,6 +75,14 @@ export function prepareEvent(
7575
}
7676

7777
return result.then(evt => {
78+
if (evt) {
79+
// We apply the debug_meta field only after all event processors have ran, so that if any event processors modified
80+
// file names (e.g.the RewriteFrames integration) the filename -> debug ID relationship isn't destroyed.
81+
// This should not cause any PII issues, since we're only moving data that is already on the event and not adding
82+
// any new data
83+
applyDebugMeta(evt);
84+
}
85+
7886
if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {
7987
return normalizeEvent(evt, normalizeDepth, normalizeMaxBreadth);
8088
}
@@ -121,9 +129,9 @@ function applyClientOptions(event: Event, options: ClientOptions): void {
121129
const debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();
122130

123131
/**
124-
* Applies debug metadata images to the event in order to apply source maps by looking up their debug ID.
132+
* Puts debug IDs into the stack frames of an error event.
125133
*/
126-
export function applyDebugMetadata(event: Event, stackParser: StackParser): void {
134+
export function applyDebugIds(event: Event, stackParser: StackParser): void {
127135
const debugIdMap = GLOBAL_OBJ._sentryDebugIds;
128136

129137
if (!debugIdMap) {
@@ -160,34 +168,60 @@ export function applyDebugMetadata(event: Event, stackParser: StackParser): void
160168
return acc;
161169
}, {});
162170

163-
// Get a Set of filenames in the stack trace
164-
const errorFileNames = new Set<string>();
165171
try {
166172
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
167173
event!.exception!.values!.forEach(exception => {
168174
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
169175
exception.stacktrace!.frames!.forEach(frame => {
170176
if (frame.filename) {
171-
errorFileNames.add(frame.filename);
177+
frame.debug_id = filenameDebugIdMap[frame.filename];
178+
}
179+
});
180+
});
181+
} catch (e) {
182+
// To save bundle size we're just try catching here instead of checking for the existence of all the different objects.
183+
}
184+
}
185+
186+
/**
187+
* Moves debug IDs from the stack frames of an error event into the debug_meta field.
188+
*/
189+
export function applyDebugMeta(event: Event): void {
190+
// Extract debug IDs and filenames from the stack frames on the event.
191+
const filenameDebugIdMap: Record<string, string> = {};
192+
try {
193+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
194+
event.exception!.values!.forEach(exception => {
195+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
196+
exception.stacktrace!.frames!.forEach(frame => {
197+
if (frame.debug_id) {
198+
if (frame.abs_path) {
199+
filenameDebugIdMap[frame.abs_path] = frame.debug_id;
200+
} else if (frame.filename) {
201+
filenameDebugIdMap[frame.filename] = frame.debug_id;
202+
}
203+
delete frame.debug_id;
172204
}
173205
});
174206
});
175207
} catch (e) {
176208
// To save bundle size we're just try catching here instead of checking for the existence of all the different objects.
177209
}
178210

211+
if (Object.keys(filenameDebugIdMap).length === 0) {
212+
return;
213+
}
214+
179215
// Fill debug_meta information
180216
event.debug_meta = event.debug_meta || {};
181217
event.debug_meta.images = event.debug_meta.images || [];
182218
const images = event.debug_meta.images;
183-
errorFileNames.forEach(filename => {
184-
if (filenameDebugIdMap[filename]) {
185-
images.push({
186-
type: 'sourcemap',
187-
code_file: filename,
188-
debug_id: filenameDebugIdMap[filename],
189-
});
190-
}
219+
Object.keys(filenameDebugIdMap).forEach(filename => {
220+
images.push({
221+
type: 'sourcemap',
222+
code_file: filename,
223+
debug_id: filenameDebugIdMap[filename],
224+
});
191225
});
192226
}
193227

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

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import type { Event } from '@sentry/types';
22
import { createStackParser, GLOBAL_OBJ } from '@sentry/utils';
33

4-
import { applyDebugMetadata } from '../../src/utils/prepareEvent';
4+
import { applyDebugIds, applyDebugMeta } from '../../src/utils/prepareEvent';
55

6-
describe('applyDebugMetadata', () => {
6+
describe('applyDebugIds', () => {
77
afterEach(() => {
88
GLOBAL_OBJ._sentryDebugIds = undefined;
99
});
1010

11-
it('should put debug source map images in debug_meta field', () => {
11+
it("should put debug IDs into an event's stack frames", () => {
1212
GLOBAL_OBJ._sentryDebugIds = {
1313
'filename1.js\nfilename1.js': 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
1414
'filename2.js\nfilename2.js': 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
@@ -34,35 +34,74 @@ describe('applyDebugMetadata', () => {
3434
},
3535
};
3636

37-
applyDebugMetadata(event, stackParser);
37+
applyDebugIds(event, stackParser);
3838

39-
expect(event.debug_meta?.images).toContainEqual({
40-
type: 'sourcemap',
41-
code_file: 'filename1.js',
39+
expect(event.exception?.values?.[0].stacktrace?.frames).toContainEqual({
40+
filename: 'filename1.js',
4241
debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
4342
});
4443

45-
expect(event.debug_meta?.images).toContainEqual({
46-
type: 'sourcemap',
47-
code_file: 'filename2.js',
44+
expect(event.exception?.values?.[0].stacktrace?.frames).toContainEqual({
45+
filename: 'filename2.js',
4846
debug_id: 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
4947
});
5048

5149
// expect not to contain an image for the stack frame that doesn't have a corresponding debug id
52-
expect(event.debug_meta?.images).not.toContainEqual(
50+
expect(event.exception?.values?.[0].stacktrace?.frames).not.toContainEqual(
5351
expect.objectContaining({
54-
type: 'sourcemap',
55-
code_file: 'filename3.js',
52+
filename3: 'filename3.js',
53+
debug_id: expect.any(String),
5654
}),
5755
);
5856

5957
// expect not to contain an image for the debug id mapping that isn't contained in the stack trace
60-
expect(event.debug_meta?.images).not.toContainEqual(
58+
expect(event.exception?.values?.[0].stacktrace?.frames).not.toContainEqual(
6159
expect.objectContaining({
62-
type: 'sourcemap',
63-
code_file: 'filename4.js',
60+
filename3: 'filename4.js',
6461
debug_id: 'cccccccc-cccc-4ccc-cccc-cccccccccc',
6562
}),
6663
);
6764
});
6865
});
66+
67+
describe('applyDebugMeta', () => {
68+
it("should move the debug IDs inside an event's stack frame into the debug_meta field", () => {
69+
const event: Event = {
70+
exception: {
71+
values: [
72+
{
73+
stacktrace: {
74+
frames: [
75+
{ filename: 'filename1.js', debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa' },
76+
{ filename: 'filename2.js', debug_id: 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb' },
77+
{ filename: 'filename1.js', debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa' },
78+
{ filename: 'filename3.js' },
79+
],
80+
},
81+
},
82+
],
83+
},
84+
};
85+
86+
applyDebugMeta(event);
87+
88+
expect(event.exception?.values?.[0].stacktrace?.frames).toEqual([
89+
{ filename: 'filename1.js' },
90+
{ filename: 'filename2.js' },
91+
{ filename: 'filename1.js' },
92+
{ filename: 'filename3.js' },
93+
]);
94+
95+
expect(event.debug_meta?.images).toContainEqual({
96+
type: 'sourcemap',
97+
code_file: 'filename1.js',
98+
debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
99+
});
100+
101+
expect(event.debug_meta?.images).toContainEqual({
102+
type: 'sourcemap',
103+
code_file: 'filename2.js',
104+
debug_id: 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
105+
});
106+
});
107+
});

0 commit comments

Comments
 (0)