Skip to content

Commit

Permalink
feat(logger): improve regex in stack trace parsing (#2194)
Browse files Browse the repository at this point in the history
* improved the stacktrace location regex to handle various location patterns

* chore(logger): improve stacktrace location identification regex - lazy match line:column
  • Loading branch information
karthikeyanjp committed Mar 11, 2024
1 parent 4ba7ee4 commit ebe5eef
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/logger/src/formatter/LogFormatter.ts
Expand Up @@ -95,7 +95,7 @@ abstract class LogFormatter implements LogFormatterInterface {
}

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

let i;
for (i = 0; i < stackLines.length; i++) {
Expand Down
122 changes: 84 additions & 38 deletions packages/logger/tests/unit/formatter/PowertoolsLogFormatter.test.ts
Expand Up @@ -312,43 +312,89 @@ describe('Class: PowertoolsLogFormatter', () => {
});

describe('Method: getCodeLocation', () => {
test('when the stack IS present, it returns a datetime value ISO 8601 compliant', () => {
// Prepare
const formatter = new PowertoolsLogFormatter();
const stack =
'Error: Things keep happening!\n' +
' at /home/foo/bar/file-that-threw-the-error.ts:22:5\n' +
' at SomeOther.function (/home/foo/bar/some-file.ts:154:19)';

// Act
const errorLocation = formatter.getCodeLocation(stack);

// Assess
expect(errorLocation).toEqual('/home/foo/bar/some-file.ts:154');
});

test('when the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => {
// Prepare
const formatter = new PowertoolsLogFormatter();
const stack = undefined;

// Act
const errorLocation = formatter.getCodeLocation(stack);

// Assess
expect(errorLocation).toEqual('');
});

test('when the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => {
// Prepare
const formatter = new PowertoolsLogFormatter();
const stack = 'A weird stack trace...';

// Act
const errorLocation = formatter.getCodeLocation(stack);

// Assess
expect(errorLocation).toEqual('');
});
test.each([
{
condition: 'stack IS present',
returnExpection:
'it returns a location for a stackframe with absolute file path',
stack:
'Error: Things keep happening!\n' +
' at /home/foo/bar/file-that-threw-the-error.ts:22:5\n' +
' at SomeOther.function (/home/foo/bar/some-file.ts:154:19)',
expectedLocation: '/home/foo/bar/some-file.ts:154',
},
{
condition: 'stack IS present',
returnExpection:
'it returns a location for a stackframe ending with an optional backslash',
stack:
'Error: Reference Error!\n' +
' at /home/foo/bar/file-that-threw-the-error.ts:22:5\n' +
' at SomeOther.function (/home/foo/bar/some-frame-with-ending-backslash.ts:154:19)\\',
expectedLocation:
'/home/foo/bar/some-frame-with-ending-backslash.ts:154',
},
{
condition: 'stack IS present',
returnExpection:
'it returns a location for a path containing multiple colons',
stack:
'Error: The message failed to send\n' +
'at REPL2:1:17\n' +
'at Script.runInThisContext (node:vm:130:12)\n' +
'... 7 lines matching cause stack trace ...\n' +
'at [_line] [as _line] (node:internal/readline/interface:886:18) {\n' +
'[cause]: Error: The remote HTTP server responded with a 500 status\n' +
' at REPL1:1:15\n' +
' at Script.runInThisContext (node:vm:130:12)\n' +
' at REPLServer.defaultEval (node:repl:574:29)\n' +
' at bound (node:domain:426:15)\n' +
' at REPLServer.runBound [as eval] (node:domain:437:12)\n' +
' at REPLServer.onLine (node:repl:902:10)\n' +
' at REPLServer.emit (node:events:549:35)\n' +
' at REPLServer.emit (node:domain:482:12)\n' +
' at [_onLine] [as _onLine] (node:internal/readline/interface:425:12)\n' +
' at [_line] [as _line] (node:internal/readline/interface:886:18) \n',
expectedLocation: 'node:vm:130',
},
{
condition: 'stack IS present',
returnExpection: 'it returns a location for a nested path',
stack:
'Error: unknown\n' +
'at eval (eval at <anonymous> (file:///home/foo/bar/some-file.ts:1:35), <anonymous>:1:7)\n' +
'at <anonymous> (/home/foo/bar/file-that-threw-the-error.ts:52:3)\n' +
'at ModuleJob.run (node:internal/modules/esm/module_job:218:25)\n' +
'at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)\n' +
'at async loadESM (node:internal/process/esm_loader:28:7)\n' +
'at async handleMainPromise (node:internal/modules/run_main:113:12)\n',
expectedLocation: '/home/foo/bar/file-that-threw-the-error.ts:52',
},
{
condition: 'stack IS NOT present',
returnExpection: 'it returns an empty location',
stack: undefined,
expectedLocation: '',
},
{
condition: 'stack IS present',
returnExpection:
'if a stackframe does not have a location, it returns an empty location',
stack: 'A weird stack trace...',
expectedLocation: '',
},
])(
'when the $condition, $returnExpection',
({ stack, expectedLocation }) => {
// Prepare
const formatter = new PowertoolsLogFormatter();

// Act
const errorLocation = formatter.getCodeLocation(stack);

// Assess
expect(errorLocation).toEqual(expectedLocation);
}
);
});
});

0 comments on commit ebe5eef

Please sign in to comment.