Skip to content

Commit 884dc89

Browse files
authored
feat(integrations): Call toJSON of originalException to extract more data (getsentry#4038)
* feat(integrations): Call toJSON of originalException to extract more data
1 parent 272043d commit 884dc89

File tree

2 files changed

+97
-8
lines changed

2 files changed

+97
-8
lines changed

packages/integrations/src/extraerrordata.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,43 @@ export class ExtraErrorData implements Integration {
7474
/**
7575
* Extract extra information from the Error object
7676
*/
77-
private _extractErrorData(error: ExtendedError): { [key: string]: unknown } | null {
77+
private _extractErrorData(error: ExtendedError): Record<string, unknown> | null {
7878
// We are trying to enhance already existing event, so no harm done if it won't succeed
7979
try {
80-
const nativeKeys = ['name', 'message', 'stack', 'line', 'column', 'fileName', 'lineNumber', 'columnNumber'];
81-
const errorKeys = Object.getOwnPropertyNames(error).filter(key => nativeKeys.indexOf(key) === -1);
80+
const nativeKeys = [
81+
'name',
82+
'message',
83+
'stack',
84+
'line',
85+
'column',
86+
'fileName',
87+
'lineNumber',
88+
'columnNumber',
89+
'toJSON',
90+
];
8291

83-
if (errorKeys.length) {
84-
const extraErrorInfo: { [key: string]: unknown } = {};
85-
for (const key of errorKeys) {
86-
const value = error[key];
92+
const extraErrorInfo: Record<string, unknown> = {};
93+
94+
// We want only enumerable properties, thus `getOwnPropertyNames` is redundant here, as we filter keys anyway.
95+
for (const key of Object.keys(error)) {
96+
if (nativeKeys.indexOf(key) !== -1) {
97+
continue;
98+
}
99+
const value = error[key];
100+
extraErrorInfo[key] = isError(value) ? (value as Error).toString() : value;
101+
}
102+
103+
// Check if someone attached `toJSON` method to grab even more properties (eg. axios is doing that)
104+
if (typeof error.toJSON === 'function') {
105+
const serializedError = error.toJSON() as Record<string, unknown>;
106+
107+
for (const key of Object.keys(serializedError)) {
108+
const value = serializedError[key];
87109
extraErrorInfo[key] = isError(value) ? (value as Error).toString() : value;
88110
}
89-
return extraErrorInfo;
90111
}
112+
113+
return extraErrorInfo;
91114
} catch (oO) {
92115
logger.error('Unable to extract extra data from the Error object:', oO);
93116
}

packages/integrations/test/extraerrordata.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,70 @@ describe('ExtraErrorData()', () => {
8888

8989
expect(enhancedEvent).toEqual(event);
9090
});
91+
92+
it('should call toJSON of original exception and add its properties', () => {
93+
const error = new TypeError('foo') as ExtendedError;
94+
error.baz = 42;
95+
error.foo = 'bar';
96+
error.toJSON = function() {
97+
return {
98+
bar: 1337,
99+
qux: `${this.message} but nicer`,
100+
};
101+
};
102+
103+
const enhancedEvent = extraErrorData.enhanceEventWithErrorData(event, {
104+
originalException: error,
105+
});
106+
107+
expect(enhancedEvent.contexts).toEqual({
108+
TypeError: {
109+
bar: 1337,
110+
baz: 42,
111+
foo: 'bar',
112+
qux: 'foo but nicer',
113+
},
114+
});
115+
});
116+
117+
it('toJSON props should have priority over directly assigned ones', () => {
118+
const error = new TypeError('foo') as ExtendedError;
119+
error.baz = 42;
120+
error.toJSON = function() {
121+
return {
122+
baz: 1337,
123+
};
124+
};
125+
126+
const enhancedEvent = extraErrorData.enhanceEventWithErrorData(event, {
127+
originalException: error,
128+
});
129+
130+
expect(enhancedEvent.contexts).toEqual({
131+
TypeError: {
132+
baz: 1337,
133+
},
134+
});
135+
});
136+
137+
it('toJSON props should allow for usage of native names', () => {
138+
const error = new TypeError('foo') as ExtendedError;
139+
error.baz = 42;
140+
error.toJSON = function() {
141+
return {
142+
message: 'bar',
143+
};
144+
};
145+
146+
const enhancedEvent = extraErrorData.enhanceEventWithErrorData(event, {
147+
originalException: error,
148+
});
149+
150+
expect(enhancedEvent.contexts).toEqual({
151+
TypeError: {
152+
baz: 42,
153+
message: 'bar',
154+
},
155+
});
156+
});
91157
});

0 commit comments

Comments
 (0)