diff --git a/packages/sdk-core/src/modules/converter/V8StackTraceConverter.ts b/packages/sdk-core/src/modules/converter/V8StackTraceConverter.ts index 8b30ee01..4d39b6d9 100644 --- a/packages/sdk-core/src/modules/converter/V8StackTraceConverter.ts +++ b/packages/sdk-core/src/modules/converter/V8StackTraceConverter.ts @@ -43,20 +43,44 @@ export class V8StackTraceConverter implements BacktraceStackTraceConverter { } stackFrame = stackFrame.substring(stackFrame.indexOf(frameSeparator) + frameSeparator.length); + const asyncKeyword = 'async '; const sourceCodeSeparator = ' ('; - const sourceCodeStartIndex = stackFrame.indexOf(sourceCodeSeparator); + let sourceCodeStartIndex = stackFrame.indexOf(sourceCodeSeparator); const anonymousFunction = sourceCodeStartIndex === -1; if (anonymousFunction) { + if (stackFrame.startsWith(asyncKeyword)) { + stackFrame = stackFrame.substring(asyncKeyword.length); + } return { funcName: ANONYMOUS_FUNCTION, ...this.parseSourceCodeInformation(stackFrame), }; } + + let sourceCodeInformation = stackFrame.substring( + sourceCodeStartIndex + sourceCodeSeparator.length - 1, + stackFrame.length, + ); + const anonymousGenericSymbol = '()'; + if (sourceCodeInformation.startsWith(anonymousGenericSymbol)) { + sourceCodeStartIndex += anonymousGenericSymbol.length + 1; + sourceCodeInformation = sourceCodeInformation.substring(anonymousGenericSymbol.length); + } + + if (sourceCodeInformation.startsWith(` ${frameSeparator}`)) { + sourceCodeInformation = sourceCodeInformation.substring(frameSeparator.length + 1); + } else { + sourceCodeInformation = sourceCodeInformation.substring(1, sourceCodeInformation.length - 1); + } + + let functionName = stackFrame.substring(0, sourceCodeStartIndex); + if (functionName.startsWith(asyncKeyword)) { + functionName = functionName.substring(asyncKeyword.length); + } + return { - funcName: stackFrame.substring(0, sourceCodeStartIndex), - ...this.parseSourceCodeInformation( - stackFrame.substring(sourceCodeStartIndex + sourceCodeSeparator.length, stackFrame.length - 1), - ), + funcName: functionName, + ...this.parseSourceCodeInformation(sourceCodeInformation), }; } diff --git a/packages/sdk-core/tests/converters/v8stackTraceTestCases.ts b/packages/sdk-core/tests/converters/v8stackTraceTestCases.ts index 17c1fedb..e7521279 100644 --- a/packages/sdk-core/tests/converters/v8stackTraceTestCases.ts +++ b/packages/sdk-core/tests/converters/v8stackTraceTestCases.ts @@ -5,6 +5,122 @@ export const v8StackTraceTests: Array<{ test: { message: string; stackTrace: string }; expectation: BacktraceStackFrame[]; }> = [ + { + name: 'async function', + test: { + message: 'TypeError: invalid function invocation', + stackTrace: + 'TypeError: invalid function invocation \n' + + 'at getLsTree2 (/path/to/code/dist/src/lib/file_routines.js:232:42)\n' + + 'at new Promise ()\n' + + 'at getFilePath (/path/to/code/dist/src/lib/file_routines.js:480:24)\n' + + 'at getFileDirectory (/path/to/code/dist/src/lib/file_routines.js:621:40)\n' + + 'at async getFile (/path/to/code/dist/src/lib/file_routines.js:837:22)\n' + + 'at async /path/to/code/dist/src/controller/controller-name.js:70:30', + }, + expectation: [ + { + funcName: 'getLsTree2', + library: '/path/to/code/dist/src/lib/file_routines.js', + line: 232, + column: 42, + }, + { + funcName: 'new Promise ()', + library: '', + }, + { + funcName: 'getFilePath', + library: '/path/to/code/dist/src/lib/file_routines.js', + line: 480, + column: 24, + }, + { + funcName: 'getFileDirectory', + library: '/path/to/code/dist/src/lib/file_routines.js', + line: 621, + column: 40, + }, + { + funcName: 'getFile', + library: '/path/to/code/dist/src/lib/file_routines.js', + line: 837, + column: 22, + }, + { + funcName: 'anonymous', + library: '/path/to/code/dist/src/controller/controller-name.js', + line: 70, + column: 30, + }, + ], + }, + { + name: 'generic anonymous', + test: { + message: `Cannot read properties of undefined (reading 'split')`, + stackTrace: + "TypeError: Cannot read properties of undefined (reading 'split')\n" + + 'at DifferentClass.convert (/path/to/module/lib/modules/converter/DifferentClass.js:12:37)\n' + + 'at DataBuilder.create (/path/to/module/lib/modules/data/DataBuilder.js:45:57)\n' + + 'at DataBuilder.build (/path/to/module/lib/modules/data/DataBuilder.js:16:59)\n' + + 'at Client.create (/path/to/module/lib/Client.js:176:49)\n' + + 'at Client. (/path/to/module/lib/Client.js:130:40)\n' + + 'at Generator.next () at /path/to/module/lib/Client.js:8:71\n' + + 'at new Promise () at /path/to/module/lib/Client.js:4:12\n' + + 'at Client.generate (/path/to/module/lib/Client.js:114:16)', + }, + expectation: [ + { + funcName: 'DifferentClass.convert', + library: '/path/to/module/lib/modules/converter/DifferentClass.js', + line: 12, + column: 37, + }, + { + funcName: 'DataBuilder.create', + library: '/path/to/module/lib/modules/data/DataBuilder.js', + line: 45, + column: 57, + }, + { + funcName: 'DataBuilder.build', + library: '/path/to/module/lib/modules/data/DataBuilder.js', + line: 16, + column: 59, + }, + { + funcName: 'Client.create', + library: '/path/to/module/lib/Client.js', + line: 176, + column: 49, + }, + { + funcName: 'Client.', + library: '/path/to/module/lib/Client.js', + line: 130, + column: 40, + }, + { + funcName: 'Generator.next ()', + library: '/path/to/module/lib/Client.js', + line: 8, + column: 71, + }, + { + funcName: 'new Promise ()', + library: '/path/to/module/lib/Client.js', + line: 4, + column: 12, + }, + { + funcName: 'Client.generate', + library: '/path/to/module/lib/Client.js', + line: 114, + column: 16, + }, + ], + }, { name: 'old source code syntax', test: {