From 71fb56579d0e31cc18b04f5496c4c6ac57a9e352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 8 Oct 2021 12:32:07 +0200 Subject: [PATCH 1/6] feat(integrations): Call toJSON of originalException to extract more data --- packages/integrations/src/extraerrordata.ts | 40 +++++++++++++++---- .../integrations/test/extraerrordata.test.ts | 23 +++++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/packages/integrations/src/extraerrordata.ts b/packages/integrations/src/extraerrordata.ts index 0959f30e95b2..9a05f7088684 100644 --- a/packages/integrations/src/extraerrordata.ts +++ b/packages/integrations/src/extraerrordata.ts @@ -77,17 +77,43 @@ export class ExtraErrorData implements Integration { private _extractErrorData(error: ExtendedError): { [key: string]: unknown } | null { // We are trying to enhance already existing event, so no harm done if it won't succeed try { - const nativeKeys = ['name', 'message', 'stack', 'line', 'column', 'fileName', 'lineNumber', 'columnNumber']; - const errorKeys = Object.getOwnPropertyNames(error).filter(key => nativeKeys.indexOf(key) === -1); + const nativeKeys = [ + 'name', + 'message', + 'stack', + 'line', + 'column', + 'fileName', + 'lineNumber', + 'columnNumber', + 'toJSON', + ]; - if (errorKeys.length) { - const extraErrorInfo: { [key: string]: unknown } = {}; - for (const key of errorKeys) { - const value = error[key]; + const extraErrorInfo: { [key: string]: unknown } = {}; + + // We want only enumerable properties, thus `getOwnPropertyNames` is redundant here, as we filter keys anyway. + for (const key of Object.keys(error)) { + if (nativeKeys.indexOf(key) !== -1) { + continue; + } + const value = error[key]; + extraErrorInfo[key] = isError(value) ? (value as Error).toString() : value; + } + + // Check if someone attached `toJSON` method to grab even more properties (eg. axios is doing that) + if (typeof error.toJSON === 'function') { + const serializedError = error.toJSON() as { [key: string]: unknown }; + + for (const key of Object.keys(serializedError)) { + if (nativeKeys.indexOf(key) !== -1) { + continue; + } + const value = serializedError[key]; extraErrorInfo[key] = isError(value) ? (value as Error).toString() : value; } - return extraErrorInfo; } + + return extraErrorInfo; } catch (oO) { logger.error('Unable to extract extra data from the Error object:', oO); } diff --git a/packages/integrations/test/extraerrordata.test.ts b/packages/integrations/test/extraerrordata.test.ts index 2237540249dd..2a93fa739077 100644 --- a/packages/integrations/test/extraerrordata.test.ts +++ b/packages/integrations/test/extraerrordata.test.ts @@ -88,4 +88,27 @@ describe('ExtraErrorData()', () => { expect(enhancedEvent).toEqual(event); }); + + it('should call toJSON of original exception and add its properties', () => { + const error = new TypeError('foo') as ExtendedError; + error.baz = 42; + error.foo = 'bar'; + error.toJSON = function() { + return { + bar: 1337, + }; + }; + + const enhancedEvent = extraErrorData.enhanceEventWithErrorData(event, { + originalException: error, + }); + + expect(enhancedEvent.contexts).toEqual({ + TypeError: { + bar: 1337, + baz: 42, + foo: 'bar', + }, + }); + }); }); From 4a3cc8a16f8cc324c1f1b77bad54fa9588145efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 8 Oct 2021 13:31:20 +0200 Subject: [PATCH 2/6] update test with this context --- packages/integrations/test/extraerrordata.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/integrations/test/extraerrordata.test.ts b/packages/integrations/test/extraerrordata.test.ts index 2a93fa739077..e698e81f485d 100644 --- a/packages/integrations/test/extraerrordata.test.ts +++ b/packages/integrations/test/extraerrordata.test.ts @@ -96,6 +96,7 @@ describe('ExtraErrorData()', () => { error.toJSON = function() { return { bar: 1337, + qux: `${this.message} but nicer`, }; }; @@ -108,6 +109,7 @@ describe('ExtraErrorData()', () => { bar: 1337, baz: 42, foo: 'bar', + qux: 'foo but nicer', }, }); }); From d6c0069379b2e278e66368427a133fd1bf676de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 8 Oct 2021 13:32:07 +0200 Subject: [PATCH 3/6] Use record instead --- packages/integrations/src/extraerrordata.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/integrations/src/extraerrordata.ts b/packages/integrations/src/extraerrordata.ts index 9a05f7088684..b7f14e965bbd 100644 --- a/packages/integrations/src/extraerrordata.ts +++ b/packages/integrations/src/extraerrordata.ts @@ -74,7 +74,7 @@ export class ExtraErrorData implements Integration { /** * Extract extra information from the Error object */ - private _extractErrorData(error: ExtendedError): { [key: string]: unknown } | null { + private _extractErrorData(error: ExtendedError): Record | null { // We are trying to enhance already existing event, so no harm done if it won't succeed try { const nativeKeys = [ @@ -89,7 +89,7 @@ export class ExtraErrorData implements Integration { 'toJSON', ]; - const extraErrorInfo: { [key: string]: unknown } = {}; + const extraErrorInfo: Record = {}; // We want only enumerable properties, thus `getOwnPropertyNames` is redundant here, as we filter keys anyway. for (const key of Object.keys(error)) { @@ -102,7 +102,7 @@ export class ExtraErrorData implements Integration { // Check if someone attached `toJSON` method to grab even more properties (eg. axios is doing that) if (typeof error.toJSON === 'function') { - const serializedError = error.toJSON() as { [key: string]: unknown }; + const serializedError = error.toJSON() as Record; for (const key of Object.keys(serializedError)) { if (nativeKeys.indexOf(key) !== -1) { From b3593cb87a1e8e9c2825845732ccb71cee7e0fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 8 Oct 2021 13:33:09 +0200 Subject: [PATCH 4/6] include all props from toJSON --- packages/integrations/src/extraerrordata.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/integrations/src/extraerrordata.ts b/packages/integrations/src/extraerrordata.ts index b7f14e965bbd..de01df6605c0 100644 --- a/packages/integrations/src/extraerrordata.ts +++ b/packages/integrations/src/extraerrordata.ts @@ -105,9 +105,6 @@ export class ExtraErrorData implements Integration { const serializedError = error.toJSON() as Record; for (const key of Object.keys(serializedError)) { - if (nativeKeys.indexOf(key) !== -1) { - continue; - } const value = serializedError[key]; extraErrorInfo[key] = isError(value) ? (value as Error).toString() : value; } From 328ce71dfbe9b5a903b437fe7a7dfb1fc7208ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 8 Oct 2021 13:34:16 +0200 Subject: [PATCH 5/6] add override test --- .../integrations/test/extraerrordata.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/integrations/test/extraerrordata.test.ts b/packages/integrations/test/extraerrordata.test.ts index e698e81f485d..61338ab96323 100644 --- a/packages/integrations/test/extraerrordata.test.ts +++ b/packages/integrations/test/extraerrordata.test.ts @@ -113,4 +113,24 @@ describe('ExtraErrorData()', () => { }, }); }); + + it('toJSON props should have prioroty over directly assigned ones', () => { + const error = new TypeError('foo') as ExtendedError; + error.baz = 42; + error.toJSON = function() { + return { + baz: 1337, + }; + }; + + const enhancedEvent = extraErrorData.enhanceEventWithErrorData(event, { + originalException: error, + }); + + expect(enhancedEvent.contexts).toEqual({ + TypeError: { + baz: 1337, + }, + }); + }); }); From 0cc9fdcf8437bc3d5f3445b9cef803f80dddab7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Mon, 11 Oct 2021 12:25:11 +0200 Subject: [PATCH 6/6] add native prop name test --- .../integrations/test/extraerrordata.test.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/integrations/test/extraerrordata.test.ts b/packages/integrations/test/extraerrordata.test.ts index 61338ab96323..6782e6706458 100644 --- a/packages/integrations/test/extraerrordata.test.ts +++ b/packages/integrations/test/extraerrordata.test.ts @@ -114,7 +114,7 @@ describe('ExtraErrorData()', () => { }); }); - it('toJSON props should have prioroty over directly assigned ones', () => { + it('toJSON props should have priority over directly assigned ones', () => { const error = new TypeError('foo') as ExtendedError; error.baz = 42; error.toJSON = function() { @@ -133,4 +133,25 @@ describe('ExtraErrorData()', () => { }, }); }); + + it('toJSON props should allow for usage of native names', () => { + const error = new TypeError('foo') as ExtendedError; + error.baz = 42; + error.toJSON = function() { + return { + message: 'bar', + }; + }; + + const enhancedEvent = extraErrorData.enhanceEventWithErrorData(event, { + originalException: error, + }); + + expect(enhancedEvent.contexts).toEqual({ + TypeError: { + baz: 42, + message: 'bar', + }, + }); + }); });