Skip to content

Commit 8ab69ac

Browse files
committed
feat: RewriteFrames pluggable integration for Node
1 parent a2f2a57 commit 8ab69ac

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Scope } from '@sentry/hub';
2+
import { Integration, SentryEvent, StackFrame } from '@sentry/types';
3+
import { basename } from 'path';
4+
import { getCurrentHub } from '../../hub';
5+
6+
type StackFrameIteratee = (frame: StackFrame) => Promise<StackFrame>;
7+
8+
/** Rewrite event frames paths */
9+
export class RewriteFrames implements Integration {
10+
/**
11+
* @inheritDoc
12+
*/
13+
public name: string = 'RewriteFrames';
14+
15+
/**
16+
* @inheritDoc
17+
*/
18+
public iteratee: StackFrameIteratee = async (frame: StackFrame) => {
19+
if (frame.filename && frame.filename.startsWith('/')) {
20+
frame.filename = `app:///${basename(frame.filename)}`;
21+
}
22+
return frame;
23+
};
24+
25+
/**
26+
* @inheritDoc
27+
*/
28+
public constructor(options: { iteratee?: StackFrameIteratee } = {}) {
29+
if (options.iteratee) {
30+
this.iteratee = options.iteratee;
31+
}
32+
}
33+
34+
/**
35+
* @inheritDoc
36+
*/
37+
public install(): void {
38+
getCurrentHub().configureScope((scope: Scope) => {
39+
scope.addEventProcessor(async event => this.process(event));
40+
});
41+
}
42+
43+
/** JSDoc */
44+
public async process(event: SentryEvent): Promise<SentryEvent> {
45+
const frames = this.getFramesFromEvent(event);
46+
if (frames) {
47+
for (const i in frames) {
48+
// tslint:disable-next-line
49+
frames[i] = await this.iteratee(frames[i]);
50+
}
51+
}
52+
return event;
53+
}
54+
55+
/** JSDoc */
56+
private getFramesFromEvent(event: SentryEvent): StackFrame[] | undefined {
57+
const exception = event.exception;
58+
59+
if (exception) {
60+
try {
61+
return (exception as any).values[0].stacktrace.frames;
62+
} catch (_oO) {
63+
return undefined;
64+
}
65+
} else if (event.stacktrace) {
66+
return event.stacktrace.frames;
67+
} else {
68+
return undefined;
69+
}
70+
}
71+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { SentryEvent, StackFrame } from '@sentry/types';
2+
import { RewriteFrames } from '../../src/integrations/pluggable/rewriteframes';
3+
4+
let rewriteFrames: RewriteFrames;
5+
let messageEvent: SentryEvent;
6+
let exceptionEvent: SentryEvent;
7+
8+
describe('RewriteFrames', () => {
9+
beforeEach(() => {
10+
messageEvent = {
11+
stacktrace: {
12+
frames: [
13+
{
14+
filename: '/some/file1.js',
15+
},
16+
{
17+
filename: '/some/file2.js',
18+
},
19+
],
20+
},
21+
};
22+
exceptionEvent = {
23+
exception: {
24+
values: [
25+
{
26+
stacktrace: {
27+
frames: [
28+
{
29+
filename: '/some/file1.js',
30+
},
31+
{
32+
filename: '/some/file2.js',
33+
},
34+
],
35+
},
36+
},
37+
],
38+
},
39+
};
40+
});
41+
42+
describe('default iteratee appends `app:///` if frame starts with `/`', () => {
43+
beforeEach(() => {
44+
rewriteFrames = new RewriteFrames();
45+
});
46+
47+
it('transforms messageEvent frames', async () => {
48+
const event = await rewriteFrames.process(messageEvent);
49+
expect(event.stacktrace!.frames![0].filename).toEqual('app:///file1.js');
50+
expect(event.stacktrace!.frames![1].filename).toEqual('app:///file2.js');
51+
});
52+
53+
it('transforms exceptionEvent frames', async () => {
54+
const event = await rewriteFrames.process(exceptionEvent);
55+
expect(event.exception!.values![0].stacktrace!.frames![0].filename).toEqual('app:///file1.js');
56+
expect(event.exception!.values![0].stacktrace!.frames![1].filename).toEqual('app:///file2.js');
57+
});
58+
});
59+
60+
describe('can use custom iteratee', () => {
61+
beforeEach(() => {
62+
rewriteFrames = new RewriteFrames({
63+
iteratee: async (frame: StackFrame) => ({
64+
...frame,
65+
function: 'whoops',
66+
}),
67+
});
68+
});
69+
70+
it('transforms messageEvent frames', async () => {
71+
const event = await rewriteFrames.process(messageEvent);
72+
expect(event.stacktrace!.frames![0].filename).toEqual('/some/file1.js');
73+
expect(event.stacktrace!.frames![0].function).toEqual('whoops');
74+
expect(event.stacktrace!.frames![1].filename).toEqual('/some/file2.js');
75+
expect(event.stacktrace!.frames![1].function).toEqual('whoops');
76+
});
77+
78+
it('transforms exceptionEvent frames', async () => {
79+
const event = await rewriteFrames.process(exceptionEvent);
80+
expect(event.exception!.values![0].stacktrace!.frames![0].filename).toEqual('/some/file1.js');
81+
expect(event.exception!.values![0].stacktrace!.frames![0].function).toEqual('whoops');
82+
expect(event.exception!.values![0].stacktrace!.frames![1].filename).toEqual('/some/file2.js');
83+
expect(event.exception!.values![0].stacktrace!.frames![1].function).toEqual('whoops');
84+
});
85+
});
86+
});

0 commit comments

Comments
 (0)