Skip to content

Commit ecb4111

Browse files
committed
fix(node): Profiling debug ID matching
1 parent 5da93d8 commit ecb4111

2 files changed

Lines changed: 174 additions & 6 deletions

File tree

packages/core/src/utils/debug-ids.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,15 @@ export function getDebugImagesForResources(
101101

102102
const images: DebugImage[] = [];
103103
for (const path of resource_paths) {
104-
if (path && filenameDebugIdMap[path]) {
105-
images.push({
106-
type: 'sourcemap',
107-
code_file: path,
108-
debug_id: filenameDebugIdMap[path],
109-
});
104+
if (path) {
105+
const normalizedPath = path.startsWith('file://') ? path.slice(7) : path;
106+
if (filenameDebugIdMap[normalizedPath]) {
107+
images.push({
108+
type: 'sourcemap',
109+
code_file: path,
110+
debug_id: filenameDebugIdMap[normalizedPath],
111+
});
112+
}
110113
}
111114
}
112115

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { beforeEach, describe, expect, it } from 'vitest';
2+
import type { StackParser } from '../../../src/types-hoist/stacktrace';
3+
import { getDebugImagesForResources, getFilenameToDebugIdMap } from '../../../src/utils/debug-ids';
4+
5+
describe('getDebugImagesForResources', () => {
6+
const mockStackParser: StackParser = (stack: string) => {
7+
// Simple mock that extracts filename from a stack string
8+
const match = stack.match(/at .* \((.*?):\d+:\d+\)/);
9+
if (match) {
10+
return [{ filename: match[1], function: 'mockFunction', lineno: 1, colno: 1 }];
11+
}
12+
return [];
13+
};
14+
15+
beforeEach(() => {
16+
// Clear any existing debug ID maps
17+
delete (globalThis as any)._sentryDebugIds;
18+
delete (globalThis as any)._debugIds;
19+
});
20+
21+
it('should return debug images for resources without file:// prefix', () => {
22+
// Setup debug IDs
23+
(globalThis as any)._sentryDebugIds = {
24+
'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
25+
};
26+
27+
const resources = ['/var/task/index.js'];
28+
const images = getDebugImagesForResources(mockStackParser, resources);
29+
30+
expect(images).toHaveLength(1);
31+
expect(images[0]).toEqual({
32+
type: 'sourcemap',
33+
code_file: '/var/task/index.js',
34+
debug_id: 'debug-id-123',
35+
});
36+
});
37+
38+
it('should return debug images for resources with file:// prefix', () => {
39+
// Setup debug IDs - the stack parser strips file:// when parsing
40+
(globalThis as any)._sentryDebugIds = {
41+
'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
42+
};
43+
44+
// V8 profiler returns resources WITH file:// prefix
45+
const resources = ['file:///var/task/index.js'];
46+
const images = getDebugImagesForResources(mockStackParser, resources);
47+
48+
expect(images).toHaveLength(1);
49+
expect(images[0]).toEqual({
50+
type: 'sourcemap',
51+
code_file: 'file:///var/task/index.js',
52+
debug_id: 'debug-id-123',
53+
});
54+
});
55+
56+
it('should handle mixed resources with and without file:// prefix', () => {
57+
(globalThis as any)._sentryDebugIds = {
58+
'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
59+
'at anotherFunction (/var/task/utils.js:10:5)': 'debug-id-456',
60+
};
61+
62+
const resources = ['file:///var/task/index.js', '/var/task/utils.js'];
63+
const images = getDebugImagesForResources(mockStackParser, resources);
64+
65+
expect(images).toHaveLength(2);
66+
expect(images[0]).toEqual({
67+
type: 'sourcemap',
68+
code_file: 'file:///var/task/index.js',
69+
debug_id: 'debug-id-123',
70+
});
71+
expect(images[1]).toEqual({
72+
type: 'sourcemap',
73+
code_file: '/var/task/utils.js',
74+
debug_id: 'debug-id-456',
75+
});
76+
});
77+
78+
it('should return empty array when no debug IDs match', () => {
79+
(globalThis as any)._sentryDebugIds = {
80+
'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
81+
};
82+
83+
const resources = ['file:///var/task/other.js'];
84+
const images = getDebugImagesForResources(mockStackParser, resources);
85+
86+
expect(images).toHaveLength(0);
87+
});
88+
89+
it('should return empty array when no debug IDs are registered', () => {
90+
const resources = ['file:///var/task/index.js'];
91+
const images = getDebugImagesForResources(mockStackParser, resources);
92+
93+
expect(images).toHaveLength(0);
94+
});
95+
96+
it('should handle empty resource paths array', () => {
97+
(globalThis as any)._sentryDebugIds = {
98+
'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
99+
};
100+
101+
const resources: string[] = [];
102+
const images = getDebugImagesForResources(mockStackParser, resources);
103+
104+
expect(images).toHaveLength(0);
105+
});
106+
});
107+
108+
describe('getFilenameToDebugIdMap', () => {
109+
const mockStackParser: StackParser = (stack: string) => {
110+
const match = stack.match(/at .* \((.*?):\d+:\d+\)/);
111+
if (match) {
112+
return [{ filename: match[1], function: 'mockFunction', lineno: 1, colno: 1 }];
113+
}
114+
return [];
115+
};
116+
117+
beforeEach(() => {
118+
delete (globalThis as any)._sentryDebugIds;
119+
delete (globalThis as any)._debugIds;
120+
});
121+
122+
it('should return empty object when no debug IDs are registered', () => {
123+
const map = getFilenameToDebugIdMap(mockStackParser);
124+
expect(map).toEqual({});
125+
});
126+
127+
it('should build map from _sentryDebugIds', () => {
128+
(globalThis as any)._sentryDebugIds = {
129+
'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
130+
'at anotherFunction (/var/task/utils.js:10:5)': 'debug-id-456',
131+
};
132+
133+
const map = getFilenameToDebugIdMap(mockStackParser);
134+
135+
expect(map).toEqual({
136+
'/var/task/index.js': 'debug-id-123',
137+
'/var/task/utils.js': 'debug-id-456',
138+
});
139+
});
140+
141+
it('should build map from native _debugIds', () => {
142+
(globalThis as any)._debugIds = {
143+
'at mockFunction (/var/task/index.js:1:1)': 'native-debug-id-123',
144+
};
145+
146+
const map = getFilenameToDebugIdMap(mockStackParser);
147+
148+
expect(map).toEqual({
149+
'/var/task/index.js': 'native-debug-id-123',
150+
});
151+
});
152+
153+
it('should prioritize native _debugIds over _sentryDebugIds', () => {
154+
(globalThis as any)._sentryDebugIds = {
155+
'at mockFunction (/var/task/index.js:1:1)': 'sentry-debug-id',
156+
};
157+
(globalThis as any)._debugIds = {
158+
'at mockFunction (/var/task/index.js:1:1)': 'native-debug-id',
159+
};
160+
161+
const map = getFilenameToDebugIdMap(mockStackParser);
162+
163+
expect(map['/var/task/index.js']).toBe('native-debug-id');
164+
});
165+
});

0 commit comments

Comments
 (0)