Skip to content

Commit 026072e

Browse files
author
Luca Forstner
authored
feat: Add source map debug ids (#7068)
1 parent f26ebcc commit 026072e

File tree

4 files changed

+79
-1
lines changed

4 files changed

+79
-1
lines changed

packages/types/src/stackframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ export interface StackFrame {
1414
instruction_addr?: string;
1515
addr_mode?: string;
1616
vars?: { [key: string]: any };
17+
debug_id?: string;
1718
}

packages/utils/src/stacktrace.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import type { StackFrame, StackLineParser, StackLineParserFn, StackParser } from '@sentry/types';
22

3+
import { GLOBAL_OBJ } from './worldwide';
4+
35
const STACKTRACE_LIMIT = 50;
46

7+
type DebugIdFilename = string;
8+
type DebugId = string;
9+
10+
const debugIdParserCache = new Map<StackLineParserFn, Map<DebugIdFilename, DebugId>>();
11+
512
/**
613
* Creates a stack parser with the supplied line parsers
714
*
@@ -15,6 +22,28 @@ export function createStackParser(...parsers: StackLineParser[]): StackParser {
1522
return (stack: string, skipFirst: number = 0): StackFrame[] => {
1623
const frames: StackFrame[] = [];
1724

25+
for (const parser of sortedParsers) {
26+
let debugIdCache = debugIdParserCache.get(parser);
27+
if (!debugIdCache) {
28+
debugIdCache = new Map();
29+
debugIdParserCache.set(parser, debugIdCache);
30+
}
31+
32+
const debugIdMap = GLOBAL_OBJ._sentryDebugIds;
33+
34+
if (debugIdMap) {
35+
Object.keys(debugIdMap).forEach(debugIdStackTrace => {
36+
debugIdStackTrace.split('\n').forEach(line => {
37+
const frame = parser(line);
38+
if (frame && frame.filename) {
39+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
40+
debugIdCache!.set(frame.filename, debugIdMap[debugIdStackTrace]);
41+
}
42+
});
43+
});
44+
}
45+
}
46+
1847
for (const line of stack.split('\n').slice(skipFirst)) {
1948
// Ignore lines over 1kb as they are unlikely to be stack frames.
2049
// Many of the regular expressions use backtracking which results in run time that increases exponentially with
@@ -32,6 +61,14 @@ export function createStackParser(...parsers: StackLineParser[]): StackParser {
3261
const frame = parser(cleanedLine);
3362

3463
if (frame) {
64+
const debugIdCache = debugIdParserCache.get(parser);
65+
if (debugIdCache && frame.filename) {
66+
const cachedDebugId = debugIdCache.get(frame.filename);
67+
if (cachedDebugId) {
68+
frame.debug_id = cachedDebugId;
69+
}
70+
}
71+
3572
frames.push(frame);
3673
break;
3774
}

packages/utils/src/worldwide.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface InternalGlobal {
2929
id?: string;
3030
};
3131
SENTRY_SDK_SOURCE?: SdkSource;
32+
_sentryDebugIds?: Record<string, string>;
3233
__SENTRY__: {
3334
globalEventProcessors: any;
3435
hub: any;

packages/utils/test/stacktrace.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { stripSentryFramesAndReverse } from '../src/stacktrace';
1+
import { createStackParser, stripSentryFramesAndReverse } from '../src/stacktrace';
2+
import { GLOBAL_OBJ } from '../src/worldwide';
23

34
describe('Stacktrace', () => {
45
describe('stripSentryFramesAndReverse()', () => {
@@ -68,3 +69,41 @@ describe('Stacktrace', () => {
6869
});
6970
});
7071
});
72+
73+
describe('Stack parsers created with createStackParser', () => {
74+
afterEach(() => {
75+
GLOBAL_OBJ._sentryDebugIds = undefined;
76+
});
77+
78+
it('put debug ids onto individual frames', () => {
79+
GLOBAL_OBJ._sentryDebugIds = {
80+
'filename1.js\nfilename1.js': 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
81+
'filename2.js\nfilename2.js': 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
82+
};
83+
84+
const fakeErrorStack = 'filename1.js\nfilename2.js\nfilename1.js\nfilename3.js';
85+
const stackParser = createStackParser([0, line => ({ filename: line })]);
86+
87+
const result = stackParser(fakeErrorStack);
88+
89+
expect(result[0]).toStrictEqual({ filename: 'filename3.js', function: '?' });
90+
91+
expect(result[1]).toStrictEqual({
92+
filename: 'filename1.js',
93+
function: '?',
94+
debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
95+
});
96+
97+
expect(result[2]).toStrictEqual({
98+
filename: 'filename2.js',
99+
function: '?',
100+
debug_id: 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
101+
});
102+
103+
expect(result[3]).toStrictEqual({
104+
filename: 'filename1.js',
105+
function: '?',
106+
debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
107+
});
108+
});
109+
});

0 commit comments

Comments
 (0)