From 79464f7beb4f97411da39f8f4432403fe9661479 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Tue, 15 Mar 2022 12:02:47 +0000 Subject: [PATCH 1/3] Fix stack parsing --- packages/node/src/stack-parser.ts | 11 +++- packages/node/test/stacktrace.test.ts | 88 ++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/packages/node/src/stack-parser.ts b/packages/node/src/stack-parser.ts index 2cbd6f116ccf..0cedc899d51d 100644 --- a/packages/node/src/stack-parser.ts +++ b/packages/node/src/stack-parser.ts @@ -36,8 +36,9 @@ function getModule(filename: string | undefined): string | undefined { } const FILENAME_MATCH = /^\s*[-]{4,}$/; -const FULL_MATCH = /at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/; +const FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/; +// eslint-disable-next-line complexity const node: StackLineParserFn = (line: string) => { if (line.match(FILENAME_MATCH)) { return { @@ -87,7 +88,11 @@ const node: StackLineParserFn = (line: string) => { functionName = undefined; } - const filename = lineMatch[2]; + if (functionName === undefined) { + functionName = typeName ? `${typeName}.${methodName || ''}` : methodName || ''; + } + + const filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].substr(7) : lineMatch[2]; const isNative = lineMatch[5] === 'native'; const isInternal = isNative || (filename && !filename.startsWith('/') && !filename.startsWith('.') && filename.indexOf(':\\') !== 1); @@ -100,7 +105,7 @@ const node: StackLineParserFn = (line: string) => { return { filename, module: getModule(filename), - function: functionName || `${typeName}.${methodName || ''}`, + function: functionName, lineno: parseInt(lineMatch[3], 10) || undefined, colno: parseInt(lineMatch[4], 10) || undefined, in_app, diff --git a/packages/node/test/stacktrace.test.ts b/packages/node/test/stacktrace.test.ts index 1c4cd5126c85..ac94dbd88e6e 100644 --- a/packages/node/test/stacktrace.test.ts +++ b/packages/node/test/stacktrace.test.ts @@ -218,7 +218,7 @@ describe('Stack parsing', () => { { filename: '/Users/felix/code/node-fast-or-slow/lib/test_case.js', module: 'test_case', - function: 'undefined.', + function: '', lineno: 80, colno: 10, in_app: true, @@ -238,7 +238,7 @@ describe('Stack parsing', () => { { filename: '/Users/felix/code/node-fast-or-slow/lib/test_case.js', module: 'test_case', - function: 'undefined.', + function: '', lineno: 80, colno: 10, in_app: true, @@ -294,4 +294,88 @@ describe('Stack parsing', () => { }, ]); }); + + test('parses with async frames', () => { + // https://github.com/getsentry/sentry-javascript/issues/4692#issuecomment-1063835795 + const err: { [key: string]: any } = {}; + err.stack = + 'Error: Client request error\n' + + ' at Object.httpRequestError (file:///code/node_modules/@waroncancer/gaia/lib/error/error-factory.js:17:73)\n' + + ' at Object.run (file:///code/node_modules/@waroncancer/gaia/lib/http-client/http-client.js:81:36)\n' + + ' at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' + + ' at async Object.send (file:///code/lib/post-created/send-post-created-notification-module.js:17:27)\n' + + ' at async each (file:///code/lib/process-post-events-module.js:14:21)\n' + + ' at async Runner.processEachMessage (/code/node_modules/kafkajs/src/consumer/runner.js:151:9)\n' + + ' at async onBatch (/code/node_modules/kafkajs/src/consumer/runner.js:326:9)\n' + + ' at async /code/node_modules/kafkajs/src/consumer/runner.js:376:15\n'; + + const frames = parseStackFrames(err as Error); + + expect(frames).toEqual([ + { + filename: '/code/node_modules/kafkajs/src/consumer/runner.js', + module: 'kafkajs.src.consumer:runner', + function: '', + lineno: 376, + colno: 15, + in_app: false, + }, + { + filename: '/code/node_modules/kafkajs/src/consumer/runner.js', + module: 'kafkajs.src.consumer:runner', + function: 'onBatch', + lineno: 326, + colno: 9, + in_app: false, + }, + { + filename: '/code/node_modules/kafkajs/src/consumer/runner.js', + module: 'kafkajs.src.consumer:runner', + function: 'Runner.processEachMessage', + lineno: 151, + colno: 9, + in_app: false, + }, + { + filename: '/code/lib/process-post-events-module.js', + module: 'process-post-events-module', + function: 'each', + lineno: 14, + colno: 21, + in_app: true, + }, + { + filename: '/code/lib/post-created/send-post-created-notification-module.js', + module: 'send-post-created-notification-module', + function: 'Object.send', + lineno: 17, + colno: 27, + in_app: true, + }, + { + filename: 'node:internal/process/task_queues', + module: 'task_queues', + function: 'processTicksAndRejections', + lineno: 96, + colno: 5, + in_app: false, + }, + { + filename: '/code/node_modules/@waroncancer/gaia/lib/http-client/http-client.js', + module: '@waroncancer.gaia.lib.http-client:http-client', + function: 'Object.run', + lineno: 81, + colno: 36, + in_app: false, + }, + { + filename: '/code/node_modules/@waroncancer/gaia/lib/error/error-factory.js', + module: '@waroncancer.gaia.lib.error:error-factory', + function: 'Object.httpRequestError', + lineno: 17, + colno: 73, + in_app: false, + }, + ]); + }); }); From bb9de54bd2ed9e20eeb956c09e549567d4a640e8 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Tue, 15 Mar 2022 12:08:41 +0000 Subject: [PATCH 2/3] Minor improvement --- packages/node/src/stack-parser.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/node/src/stack-parser.ts b/packages/node/src/stack-parser.ts index 0cedc899d51d..a37e38001da3 100644 --- a/packages/node/src/stack-parser.ts +++ b/packages/node/src/stack-parser.ts @@ -89,7 +89,8 @@ const node: StackLineParserFn = (line: string) => { } if (functionName === undefined) { - functionName = typeName ? `${typeName}.${methodName || ''}` : methodName || ''; + methodName = methodName || ''; + functionName = typeName ? `${typeName}.${methodName}` : methodName; } const filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].substr(7) : lineMatch[2]; From b2c0971dfbfc662c76eed4884f3e020eeb89bf58 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Tue, 15 Mar 2022 21:27:21 +0000 Subject: [PATCH 3/3] Replace record/object type with new Error --- packages/node/test/stacktrace.test.ts | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/node/test/stacktrace.test.ts b/packages/node/test/stacktrace.test.ts index ac94dbd88e6e..656ba1a69a9b 100644 --- a/packages/node/test/stacktrace.test.ts +++ b/packages/node/test/stacktrace.test.ts @@ -53,13 +53,13 @@ describe('Stack parsing', () => { }); test('parses object in fn name', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'Error: Foo\n' + ' at [object Object].global.every [as _onTimeout] (/Users/hoitz/develop/test.coffee:36:3)\n' + ' at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)\n'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -89,7 +89,7 @@ describe('Stack parsing', () => { }); test('parses corrupt stack', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: true == false\n' + ' fuck' + @@ -97,7 +97,7 @@ describe('Stack parsing', () => { 'oh no' + ' at TestCase.run (/Users/felix/code/node-fast-or-slow/lib/test_case.js:61:8)\n'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -120,13 +120,13 @@ describe('Stack parsing', () => { }); test('parses with missing column numbers', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: true == false\n' + ' at Test.fn (/Users/felix/code/node-fast-or-slow/test/fast/example/test-example.js:6)\n' + ' at Test.run (/Users/felix/code/node-fast-or-slow/lib/test.js:45)'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -147,7 +147,7 @@ describe('Stack parsing', () => { }); test('parses with native methods', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: true == false\n' + ' at Test.fn (/Users/felix/code/node-fast-or-slow/test/fast/example/test-example.js:6:10)\n' + @@ -157,7 +157,7 @@ describe('Stack parsing', () => { ' at Array.0 (native)\n' + ' at EventEmitter._tickCallback (node.js:126:26)'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -209,10 +209,10 @@ describe('Stack parsing', () => { }); test('parses with file only', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: true == false\n' + ' at /Users/felix/code/node-fast-or-slow/lib/test_case.js:80:10'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -227,12 +227,12 @@ describe('Stack parsing', () => { }); test('parses with multi line message', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: true == false\nAnd some more shit\n' + ' at /Users/felix/code/node-fast-or-slow/lib/test_case.js:80:10'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -247,12 +247,12 @@ describe('Stack parsing', () => { }); test('parses with anonymous fn call', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: expected [] to be arguments\n' + ' at Assertion.prop.(anonymous function) (/Users/den/Projects/should.js/lib/should.js:60:14)\n'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -267,13 +267,13 @@ describe('Stack parsing', () => { }); test('parses with braces in paths', () => { - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'AssertionError: true == false\n' + ' at Test.run (/Users/felix (something)/code/node-fast-or-slow/lib/test.js:45:10)\n' + ' at TestCase.run (/Users/felix (something)/code/node-fast-or-slow/lib/test_case.js:61:8)\n'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ { @@ -297,7 +297,7 @@ describe('Stack parsing', () => { test('parses with async frames', () => { // https://github.com/getsentry/sentry-javascript/issues/4692#issuecomment-1063835795 - const err: { [key: string]: any } = {}; + const err = new Error(); err.stack = 'Error: Client request error\n' + ' at Object.httpRequestError (file:///code/node_modules/@waroncancer/gaia/lib/error/error-factory.js:17:73)\n' + @@ -309,7 +309,7 @@ describe('Stack parsing', () => { ' at async onBatch (/code/node_modules/kafkajs/src/consumer/runner.js:326:9)\n' + ' at async /code/node_modules/kafkajs/src/consumer/runner.js:376:15\n'; - const frames = parseStackFrames(err as Error); + const frames = parseStackFrames(err); expect(frames).toEqual([ {