UNPKG

traceable

Version:

Capture, parse and format V8 stack trace.

22 lines (21 loc) 10.4 kB
{ "name": "traceable", "version": "0.2.4", "description": "Capture, parse and format V8 stack trace.", "main": "traceable.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "misonou", "license": "MIT", "keywords": [ "stack", "trace" ], "repository": { "type": "git", "url": "https://github.com/misonou/node-traceable.git" }, "bugs": "https://github.com/misonou/node-traceable/issues", "readme": "# traceable\r\n\r\nCapture, parse and format V8 stack trace.\r\n\r\n## Installation\r\n\r\n```\r\nnpm install traceable\r\n```\r\n\r\n## Usage\r\n\r\n### traceable([input], [options])\r\n\r\nThe main function can:\r\n- Capture and normalize the stack trace from the current invocation\r\n- Parse stack trace from an `Error` object\r\n- Recongize `asyncStack` on an `Error` object\r\n- Format the stack trace\r\n\r\nThe returned object is an instance of `StackTrace`.\r\n\r\n```javascript\r\nvar traceable = require('traceable');\r\n\r\n// main function is aliased as a property of the module\r\ntraceable.trace === traceable;\r\n\r\n// get stack trace\r\ntraceable();\r\n\r\n// get stack trace with top most N frames skipped\r\ntraceable(2);\r\n\r\n// get stack trace with frames above myFunc skipped\r\ntraceable(myFunc);\r\n\r\n// get stack trace captured by the Error object\r\nvar err = new Error();\r\ntraceable(err);\r\n\r\n// same as above in case only the stack trace itself is available\r\nvar stack = err.stack\r\ntraceable(stack);\r\n```\r\n\r\n#### Options\r\n\r\nBelow is an exhausive list of options, with the default value shown.\r\n\r\n```javascript\r\n{\r\n // string prepended to each frame\r\n // if supplied with number, that number of spaces is prepended\r\n indent: \" \",\r\n\r\n // hide frames from source files specified (see 'Blackboxing')\r\n blackbox: [],\r\n\r\n // format the stack trace when StackTrace.toString is called\r\n formatter: Formatter.default,\r\n\r\n // descriptive label for anonymous function\r\n anonString: \"\",\r\n\r\n // show column number\r\n showColumnNumber: false,\r\n\r\n // show eval site if function is from eval'd code\r\n showEvalOrigin: true,\r\n\r\n // append async stack trace if any\r\n showAsyncOrigin: true,\r\n\r\n // show original source file path (see 'Paths to source files')\r\n showFullPath: false,\r\n\r\n // show original function name (see 'Function names')\r\n showRawFunctionName: false\r\n}\r\n```\r\n\r\n#### Paths to source files\r\n\r\nUnless `showFullPath` is set to `true`, paths to source files are stripped as\r\nrelative to:\r\n- the **innermost** `node_modules` folder\r\n- any of the global module paths\r\n- directory of the main module\r\n- process working directory\r\n\r\n`/path/to/node_modules/my-mod/node_modules/traceable/traceable.js` is resolved as `traceable/traceable.js`\r\n\r\n#### Function names\r\n\r\nUnless `showRawFunctionName` is set to `true`, function names are manipulated as follow:\r\n\r\n- function which aliased to another name takes the highest precedence\r\n\r\n `Object.aliasedName` instead of `Object.origName [as aliasedName]`\r\n\r\n- function names resolved with pseudo-namespaces are stripped\r\n\r\n `Object.myFunc` instead of `Object.$.extend.myFunc`\r\n\r\n- if the function is called on an anonymous object (often calling function of an object literal)\r\n and the function is not defined on `Object.prototype`, the type name is replaced with `?`:\r\n\r\n `?.resolve` instead of `Object.resolve`; while\r\n\r\n `Object.hasOwnProperty` is kept\r\n\r\n#### Blackboxing\r\n\r\nBlackboxing, similar to the node inspector interface, can hide frames from certain source file\r\nas specified.\r\n\r\nPaths can be:\r\n- names to built-in modules: `fs.js`\r\n- relative to the **innermost** `node_modules` folder\r\n- relative to any of the global module paths\r\n- relative to directory of the main module\r\n- relative to process working directory\r\n\r\nIf a path resolves to a folder, all scripts under that folder will be blackboxed.\r\nThus:\r\n\r\n`/path/to/program/node_modules/my-mod/node_modules/nested/util/x.js`\r\ncan be blackboxed by one of the following path:\r\n- `nested/util/x.js`,\r\n- `nested/util`,\r\n- `nested`\r\n\r\n### traceable.StackTrace\r\n\r\nThe `StackTrace` object is an `Array`-prototyped object that contains\r\n`StackFrame` objects parsed from the stack trace.\r\n\r\nSo you can freely work with the parsed stack trace with functions like\r\n`Array.filter` and `Array.forEach` etc.\r\n\r\n```javascript\r\nvar st = traceable(err);\r\nst.forEach(function (v) {\r\n // prints the function name of each call site\r\n console.log(v.functionName);\r\n});\r\n```\r\n\r\n### traceable.StackFrame\r\n\r\nThe `StackFrame` object represent each call site parsed and contains\r\nnormalized information about the call site.\r\n\r\n```javascript\r\n{\r\n // formatted string from built-in CallSite.toString()\r\n rawString: ' at new Object.extend.doSomething (/path/to/my/script.js:50:4)'\r\n\r\n // whether the call site is native\r\n native: false,\r\n\r\n // whether the call site is called by 'new' operator\r\n isConstructor: true,\r\n\r\n // type name of 'this' object in the call site\r\n typeName: 'Object',\r\n\r\n // function name resolved by V8\r\n rawFunctionName: 'extend.doSomething',\r\n\r\n // full path of the script file\r\n // null for native call site\r\n fileName: '/path/to/my/script.js',\r\n\r\n // line number of the call site\r\n // null for native call site\r\n lineNumber: 50,\r\n\r\n // column number of the call site\r\n // null for native call site\r\n columnNumber: 4,\r\n\r\n // a StackTrace object parsed from the async stack trace\r\n // if the Error object is prep'd with async stack trace\r\n // otherwise undefined\r\n asyncOrigin: <#StackTrace>,\r\n\r\n // a StackFrame object of the eval call site\r\n // if the call site in a function compiled in eval or new Function\r\n // otherwise null\r\n get evalOrigin(),\r\n\r\n // function name\r\n get functionName(),\r\n\r\n // formatted string of the function location\r\n // depends on options.formatter\r\n get source()\r\n}\r\n```\r\n\r\n### traceable.Formatter([options])\r\n\r\nProvides means to customize the formatted output of the stack trace.\r\n\r\nThere is two built-in formatters, `default` and `native`.\r\n\r\n- `traceable.Formatter.default` (a.k.a inspector style):\r\n```\r\n (anonymous function) @ /trace-test/anon.js:2\r\n MyClass.method @ myclass/myclass.js:210\r\n dynamic_function @ <anonymous>:2 eval at myclass/helper.js:50\r\n```\r\n\r\n- `traceable.Formatter.native`\r\n```\r\n at /trace-test/anon.js:2:10\r\n at MyClass.extend.myMethod (/trace-test/node_modules/myclass/myclass.js:210:4)\r\n at dynamic_function (eval at /trace-test/node_modules/myclass/helper.js:50:12, <anonymous>:2:4)\r\n```\r\n\r\nYou can create your own formatter by defining functions\r\nthe handle different components of a stack trace.\r\n\r\nAll options are **optional**, if not specified the `native` style is used.\r\nThe second parameter `options` is the options passed to `traceable()`.\r\n\r\nEach function should return a string.\r\n\r\n```javascript\r\nnew traceable.Formatter({\r\n // format the entire stack trace\r\n // called by StackTrace.toString\r\n formatTrace: function (stackTrace, options) { ... },\r\n\r\n // format each call site\r\n formatFrame: function (stackFrame, options) { ... },\r\n\r\n // format the location of call site\r\n // called by StackFrame.source\r\n formatSource: function (stackFrame, options) { ... },\r\n\r\n // format eval site which is appended to the source\r\n // called by StackFrame.source\r\n formatEvalOrigin: function (stackFrame, options) { ... },\r\n\r\n // format async marker and the whole async stack trace\r\n // called by StackFrame.toString\r\n // see async stack trace example below\r\n formatAsyncOrigin: function (stackTrace, options) { ... }\r\n})\r\n```\r\n\r\n### traceable.prepAsyncStack([skip])\r\n\r\nEnable more verbose stack trace in async operation.\r\n\r\nSimilar to [long-stack-trace](https://www.npmjs.com/package/long-stack-trace)\r\nbut instead of wrapping async function such as `setTimeout` and `EventEmitter.on`,\r\nit records the current stack trace and return a prep function.\r\n\r\n```javascript\r\nfunction somethingAsync() {\r\n var prep = traceable.prepAsyncStack(); // returns a function\r\n setTimeout(function () {\r\n var err = new Error();\r\n // the stack trace captured by prepAsyncStack()\r\n // is assigned to the Error object\r\n throw prep(err);\r\n });\r\n}\r\nprocess.on('uncaughtException', function(err){\r\n // recognizes the prep'd async stack\r\n console.log(traceable(err));\r\n});\r\n```\r\nwould output the following to console:\r\n```\r\n at async.js:6:19\r\n [async]\r\n at somethingAsync (async.js:2:16)\r\n at someOtherFunction (main.js:40:4)\r\n```\r\n\r\n#### Options\r\n\r\n`skip`: Number of frames to skip\r\n\r\n## License\r\n\r\nThe MIT License (MIT)\r\n\r\nCopyright (c) 2015 misonou\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE.\r\n" }