Skip to content

Commit ebe5eef

Browse files
feat(logger): improve regex in stack trace parsing (#2194)
* improved the stacktrace location regex to handle various location patterns * chore(logger): improve stacktrace location identification regex - lazy match line:column
1 parent 4ba7ee4 commit ebe5eef

File tree

2 files changed

+85
-39
lines changed

2 files changed

+85
-39
lines changed

Diff for: packages/logger/src/formatter/LogFormatter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ abstract class LogFormatter implements LogFormatterInterface {
9595
}
9696

9797
const stackLines = stack.split('\n');
98-
const regex = /\((.*):(\d+):(\d+)\)\\?$/;
98+
const regex = /\(([^)]*?):(\d+?):(\d+?)\)\\?$/;
9999

100100
let i;
101101
for (i = 0; i < stackLines.length; i++) {

Diff for: packages/logger/tests/unit/formatter/PowertoolsLogFormatter.test.ts

+84-38
Original file line numberDiff line numberDiff line change
@@ -312,43 +312,89 @@ describe('Class: PowertoolsLogFormatter', () => {
312312
});
313313

314314
describe('Method: getCodeLocation', () => {
315-
test('when the stack IS present, it returns a datetime value ISO 8601 compliant', () => {
316-
// Prepare
317-
const formatter = new PowertoolsLogFormatter();
318-
const stack =
319-
'Error: Things keep happening!\n' +
320-
' at /home/foo/bar/file-that-threw-the-error.ts:22:5\n' +
321-
' at SomeOther.function (/home/foo/bar/some-file.ts:154:19)';
322-
323-
// Act
324-
const errorLocation = formatter.getCodeLocation(stack);
325-
326-
// Assess
327-
expect(errorLocation).toEqual('/home/foo/bar/some-file.ts:154');
328-
});
329-
330-
test('when the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => {
331-
// Prepare
332-
const formatter = new PowertoolsLogFormatter();
333-
const stack = undefined;
334-
335-
// Act
336-
const errorLocation = formatter.getCodeLocation(stack);
337-
338-
// Assess
339-
expect(errorLocation).toEqual('');
340-
});
341-
342-
test('when the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => {
343-
// Prepare
344-
const formatter = new PowertoolsLogFormatter();
345-
const stack = 'A weird stack trace...';
346-
347-
// Act
348-
const errorLocation = formatter.getCodeLocation(stack);
349-
350-
// Assess
351-
expect(errorLocation).toEqual('');
352-
});
315+
test.each([
316+
{
317+
condition: 'stack IS present',
318+
returnExpection:
319+
'it returns a location for a stackframe with absolute file path',
320+
stack:
321+
'Error: Things keep happening!\n' +
322+
' at /home/foo/bar/file-that-threw-the-error.ts:22:5\n' +
323+
' at SomeOther.function (/home/foo/bar/some-file.ts:154:19)',
324+
expectedLocation: '/home/foo/bar/some-file.ts:154',
325+
},
326+
{
327+
condition: 'stack IS present',
328+
returnExpection:
329+
'it returns a location for a stackframe ending with an optional backslash',
330+
stack:
331+
'Error: Reference Error!\n' +
332+
' at /home/foo/bar/file-that-threw-the-error.ts:22:5\n' +
333+
' at SomeOther.function (/home/foo/bar/some-frame-with-ending-backslash.ts:154:19)\\',
334+
expectedLocation:
335+
'/home/foo/bar/some-frame-with-ending-backslash.ts:154',
336+
},
337+
{
338+
condition: 'stack IS present',
339+
returnExpection:
340+
'it returns a location for a path containing multiple colons',
341+
stack:
342+
'Error: The message failed to send\n' +
343+
'at REPL2:1:17\n' +
344+
'at Script.runInThisContext (node:vm:130:12)\n' +
345+
'... 7 lines matching cause stack trace ...\n' +
346+
'at [_line] [as _line] (node:internal/readline/interface:886:18) {\n' +
347+
'[cause]: Error: The remote HTTP server responded with a 500 status\n' +
348+
' at REPL1:1:15\n' +
349+
' at Script.runInThisContext (node:vm:130:12)\n' +
350+
' at REPLServer.defaultEval (node:repl:574:29)\n' +
351+
' at bound (node:domain:426:15)\n' +
352+
' at REPLServer.runBound [as eval] (node:domain:437:12)\n' +
353+
' at REPLServer.onLine (node:repl:902:10)\n' +
354+
' at REPLServer.emit (node:events:549:35)\n' +
355+
' at REPLServer.emit (node:domain:482:12)\n' +
356+
' at [_onLine] [as _onLine] (node:internal/readline/interface:425:12)\n' +
357+
' at [_line] [as _line] (node:internal/readline/interface:886:18) \n',
358+
expectedLocation: 'node:vm:130',
359+
},
360+
{
361+
condition: 'stack IS present',
362+
returnExpection: 'it returns a location for a nested path',
363+
stack:
364+
'Error: unknown\n' +
365+
'at eval (eval at <anonymous> (file:///home/foo/bar/some-file.ts:1:35), <anonymous>:1:7)\n' +
366+
'at <anonymous> (/home/foo/bar/file-that-threw-the-error.ts:52:3)\n' +
367+
'at ModuleJob.run (node:internal/modules/esm/module_job:218:25)\n' +
368+
'at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)\n' +
369+
'at async loadESM (node:internal/process/esm_loader:28:7)\n' +
370+
'at async handleMainPromise (node:internal/modules/run_main:113:12)\n',
371+
expectedLocation: '/home/foo/bar/file-that-threw-the-error.ts:52',
372+
},
373+
{
374+
condition: 'stack IS NOT present',
375+
returnExpection: 'it returns an empty location',
376+
stack: undefined,
377+
expectedLocation: '',
378+
},
379+
{
380+
condition: 'stack IS present',
381+
returnExpection:
382+
'if a stackframe does not have a location, it returns an empty location',
383+
stack: 'A weird stack trace...',
384+
expectedLocation: '',
385+
},
386+
])(
387+
'when the $condition, $returnExpection',
388+
({ stack, expectedLocation }) => {
389+
// Prepare
390+
const formatter = new PowertoolsLogFormatter();
391+
392+
// Act
393+
const errorLocation = formatter.getCodeLocation(stack);
394+
395+
// Assess
396+
expect(errorLocation).toEqual(expectedLocation);
397+
}
398+
);
353399
});
354400
});

0 commit comments

Comments
 (0)