Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add source map debug ids #7068

Merged
merged 14 commits into from
Feb 8, 2023
1 change: 1 addition & 0 deletions packages/types/src/stackframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export interface StackFrame {
instruction_addr?: string;
addr_mode?: string;
vars?: { [key: string]: any };
debug_id?: string;
}
35 changes: 35 additions & 0 deletions packages/utils/src/stacktrace.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import type { StackFrame, StackLineParser, StackLineParserFn, StackParser } from '@sentry/types';

import { GLOBAL_OBJ } from './worldwide';

const STACKTRACE_LIMIT = 50;

type DebugIdFilename = string;
type DebugId = string;

const debugIdParserCache = new Map<StackLineParserFn, Map<DebugIdFilename, DebugId>>();

/**
* Creates a stack parser with the supplied line parsers
*
Expand All @@ -15,6 +22,26 @@ export function createStackParser(...parsers: StackLineParser[]): StackParser {
return (stack: string, skipFirst: number = 0): StackFrame[] => {
const frames: StackFrame[] = [];

for (const parser of sortedParsers) {
let debugIdCache = debugIdParserCache.get(parser);
if (!debugIdCache) {
debugIdCache = new Map();
debugIdParserCache.set(parser, debugIdCache);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: This is unbounded, which is not a problem for browser js, but it is for node. We may have re-think this as a result, or add some crude eviction mechanism.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed: The upper bound is the number of modules that have been injected with the debug id times the amount of stack trace parsers. I am gonna go ahead and say this is safely cachable.

}

if (GLOBAL_OBJ._sentryDebugIds) {
Object.keys(GLOBAL_OBJ._sentryDebugIds).forEach(debugIdStackTrace => {
debugIdStackTrace.split('\n').forEach(line => {
const frame = parser(line);
if (frame && frame.filename) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
debugIdCache!.set(frame.filename, GLOBAL_OBJ._sentryDebugIds![debugIdStackTrace]);
}
});
});
}
}

for (const line of stack.split('\n').slice(skipFirst)) {
// Ignore lines over 1kb as they are unlikely to be stack frames.
// Many of the regular expressions use backtracking which results in run time that increases exponentially with
Expand All @@ -32,6 +59,14 @@ export function createStackParser(...parsers: StackLineParser[]): StackParser {
const frame = parser(cleanedLine);

if (frame) {
const debugIdCache = debugIdParserCache.get(parser);
if (debugIdCache && frame.filename) {
const cachedDebugId = debugIdCache.get(frame.filename);
if (cachedDebugId) {
frame.debug_id = cachedDebugId;
}
}

frames.push(frame);
break;
}
Expand Down
1 change: 1 addition & 0 deletions packages/utils/src/worldwide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface InternalGlobal {
id?: string;
};
SENTRY_SDK_SOURCE?: SdkSource;
_sentryDebugIds?: Record<string, string>;
__SENTRY__: {
globalEventProcessors: any;
hub: any;
Expand Down
41 changes: 40 additions & 1 deletion packages/utils/test/stacktrace.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { stripSentryFramesAndReverse } from '../src/stacktrace';
import { createStackParser, stripSentryFramesAndReverse } from '../src/stacktrace';
import { GLOBAL_OBJ } from '../src/worldwide';

describe('Stacktrace', () => {
describe('stripSentryFramesAndReverse()', () => {
Expand Down Expand Up @@ -68,3 +69,41 @@ describe('Stacktrace', () => {
});
});
});

describe('Stack parsers created with createStackParser', () => {
afterEach(() => {
GLOBAL_OBJ._sentryDebugIds = undefined;
});

it('put debug ids onto individual frames', () => {
GLOBAL_OBJ._sentryDebugIds = {
'filename1.js\nfilename1.js': 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
'filename2.js\nfilename2.js': 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
};

const fakeErrorStack = 'filename1.js\nfilename2.js\nfilename1.js\nfilename3.js';
const stackParser = createStackParser([0, line => ({ filename: line })]);

const result = stackParser(fakeErrorStack);

expect(result[0]).toStrictEqual({ filename: 'filename3.js', function: '?' });

expect(result[1]).toStrictEqual({
filename: 'filename1.js',
function: '?',
debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
});

expect(result[2]).toStrictEqual({
filename: 'filename2.js',
function: '?',
debug_id: 'bbbbbbbb-bbbb-4bbb-bbbb-bbbbbbbbbb',
});

expect(result[3]).toStrictEqual({
filename: 'filename1.js',
function: '?',
debug_id: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa',
});
});
});
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24479,6 +24479,11 @@ uuid@^8.0.0, uuid@^8.3.1, uuid@^8.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

uuid@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==

v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
Expand Down