StackTracey
Parses call stacks. Reads sources. Clean & filtered output. Sourcemaps. Node & browsers.
Why
What For
How To
npm install stacktracey
StackTracey = require ('stacktracey')
Captures the current call stack:
stack = new StackTracey ()
Parses stacks from an Error
object:
stack = new StackTracey (error)
stack = new StackTracey (error.stack)
It is an array instance:
stack instanceof Array
stack.length
stack[0]
...where each item exposes:
{
beforeParse: <original text>,
callee: <function name>,
calleeShort: <shortened function name>,
file: <full path to file>, // e.g. /Users/john/my_project/node_modules/foobar/main.js
fileRelative: <relative path to file>, // e.g. node_modules/foobar/main.js
fileShort: <short path to file>, // e.g. foobar/main.js
fileName: <file name>, // e.g. main.js
line: <line number>, // starts from 1
column: <column number>, // starts from 1
index: /* true if occured in HTML file at index page */,
native: /* true if occured in native browser code */,
thirdParty: /* true if occured in library code */,
hide: /* true if marked as hidden by "// @hide" tag */,
syntaxError: /* true if generated from a SyntaxError instance */
}
Accessing sources:
stack = stack.withSources
top = stack[0]
...or:
top = stack.withSource (0)
...or:
top = StackTracey.withSource (stack[0])
It will return an item supplied with the source code info (already mapped through sourcemaps):
{
...
line: <original line number>,
column: <original column number>,
sourceFile: <original source file object>,
sourceLine: <original source line text>
}
To learn about the sourceFile
object, read the get-source docs.
Cleaning Output
stack = stack.withSources.clean
- Excludes locations marked with the
isThirdParty
flag (library calls) - Excludes locations marked with a
// @hide
comment (user defined exclusion) - Merges repeated lines (via the
.mergeRepeatedLines
)
You can augment the global isThirdParty
predicate with new rules:
StackTracey.isThirdParty.include (path => path.includes ('my-lib'))
StackTracey.isThirdParty.except (path => path.includes ('jquery'))
P.S. It is better to call .clean
on stacks supplied with sources (i.e. after the .withSources
), to make the // @hide
magic work, and to make third-party recognition work by reading proper file names in case if your source is compiled from other sources (and has a sourcemap attached).
Pretty Printing
const prettyPrintedString = new StackTracey (error).pretty
It produces a nice compact table layout (thanks to as-table
), supplied with source lines (if available):
at shouldBeVisibleInStackTrace test.js:25 const shouldBeVisibleInStackTrace = () => new StackTracey ()
at it test.js:100 const stack = shouldBeVisibleInStackTrace ()
at callFn mocha/lib/runnable.js:326 var result = fn.call(ctx);
at run mocha/lib/runnable.js:319 callFn(this.fn);
at runTest mocha/lib/runner.js:422 test.run(fn);
at mocha/lib/runner.js:528 self.runTest(function(err) {
at next mocha/lib/runner.js:342 return fn();
at mocha/lib/runner.js:352 next(suites.pop());
at next mocha/lib/runner.js:284 return fn();
at <anonymous> mocha/lib/runner.js:320 next(0);
You can even replace the default NodeJS exception printer with this! This is how you can do it:
process.on ('uncaughtException', e => { })
process.on ('unhandledRejection', e => { })
But the most simple way to achieve that is to use the ololog
library (that is built upon StackTracey and several other handy libraries coded by me). Check it out, it's pretty awesome and will blow your brains out :)
const log = require ('ololog').handleNodeErrors ()
Overriding Max Column Widths in Pretty Printed Tables
If you get your pretty printed tables undesirably trimmed, you can try changing these numbers:
StackTracey.maxColumnWidths = {
callee: 30,
file: 40,
sourceLine: 80
}
Parsing SyntaxError
instances
For example, when trying to require
a file named test_files/syntax_error.js
:
foo->bar ()
...the pretty printed call stack for the error thrown would be something like:
at (syntax error) test_files/syntax_error.js:2 foo->bar ()
at it test.js:184 try { require ('./test_files/syntax_error.js') }
at runCallback timers.js:781
at tryOnImmediate timers.js:743
at processImmediate [as _immediat timers.js:714
...where the first line is generated from parsing the raw output from the util.inspect
call in Node. Unfortunately, this won't work in older versions of Node (v4 and below) as these versions can't provide any meaningful information for a SyntaxError
instance.
Array Methods
All StackTracey instances expose map
, filter
, concat
, reverse
and slice
methods. These methods will return mapped, filtered, joined, reversed and sliced stacks, respectively:
s = new StackTracey ().slice (1).filter (x => !x.isThirdParty)
s instanceof StackTracey
s instanceof Array
Other methods of the Array
are supported too, but they will return Array
instances, not StackTracey instances. You can convert from array via this:
stack = new StackTracey (array)
..and to array via this (but generally this is not needed — you can pass around StackTracey instances as if they were real Arrays):
Array.from (stack)
You can compare two locations via this predicate (tests file
, line
and column
for equality):
StackTracey.locationsEqual (a, b)
Resetting source cache (calls getSource.resetCache ()
from get-source):
StackTracey.resetCache ()
Projects That Use StackTracey
- Ololog — a better
console.log
for the log-driven debugging junkies! - CCXT — a cryptocurrency trading library that supports 85+ exchanges
- pnpm — a fast, disk space efficient package manager (faster than npm and Yarn!)