https://github.com/grantila/trace-unhandled
Much better tracing of unhandled promise rejections in JavaScript
https://github.com/grantila/trace-unhandled
Last synced: 6 months ago
JSON representation
Much better tracing of unhandled promise rejections in JavaScript
- Host: GitHub
- URL: https://github.com/grantila/trace-unhandled
- Owner: grantila
- License: mit
- Created: 2019-06-27T21:59:10.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2021-03-03T22:12:51.000Z (over 4 years ago)
- Last Synced: 2025-04-20T09:44:11.848Z (6 months ago)
- Language: JavaScript
- Size: 37.1 KB
- Stars: 29
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![npm version][npm-image]][npm-url]
[![downloads][downloads-image]][npm-url]
[![build status][build-image]][build-url]
[![coverage status][coverage-image]][coverage-url]
[![Language grade: JavaScript][lgtm-image]][lgtm-url]# trace-unhandled
Node.js and browsers warn on unhandled promise rejections. You might have seen:
```
(node:1234) UnhandledPromiseRejectionWarning
```When this happens, it's not always obvious what promise is unhandled. The error stacktrace will tell where the *error object construction* is, not the construction of the promise which left it dangling. It might have travelled through various asynchronous chains before it got to an unhandled promise chain.
`trace-unhandled` helps with this. It keeps track of promises and when an *unhandled promise rejection* is logged, the location of both the error object **and** the promise is logged. This makes it a lot easier to find the bug.
**This package is not intended to be used in production, only to aid locating bugs**
# Why
Consider the following code which creates an error (on line 1) and rejects a promise (on line 3) and "forgets" to catch it on line 9 (the last line). This is an **incredibly** simple example, and in real life, this would span over a lot of files and a lot of complexity.
```ts {.line-numbers}
1. const err = new Error( "foo" );
2. function b( ) {
3. return Promise.reject( err );
4. }
5. function a( ) {
6. return b( );
7. }
8. const foo = a( );
9. foo.then( ( ) => { } );
```Without `trace-unhandled`, you would get something like:
```
(node:1234) UnhandledPromiseRejectionWarning: Error: foo
at Object. (/my/directory/test.js:1:13)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:643:32)
at Function.Module._load (internal/modules/cjs/loader.js:556:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:839:10)
at internal/main/run_main_module.js:17:11
```This is the output of Node.js. You'll see the stacktrace up to the point of the **Error** `err`, but that's rather irrelevant. What you want to know is where the promise was used leaving a rejection unhandled (i.e. a missing `catch()`). With `trace-unhandled` this is exactly what you get, including the Error construction location:
```
(node:1234) UnhandledPromiseRejectionWarning
[ Stacktrace altered by https://github.com/grantila/trace-unhandled ]
Error: foo
==== Promise at: ==================
at Promise.then ()
at Object. (/my/directory/test.js:9:5) 👈==== Error at: ====================
at Object. (/my/directory/test.js:1:13)==== Shared trace: ================
at Module._compile (internal/modules/cjs/loader.js:776:30)
... more lines below ...
```We *"used"* the promise by appending another `.then()` to it. This means that the promise was actually *"handled"*, and that the new promise should handle rejections. If we delete the last line (line 9), we see where the promise was last *"used"*:
```
(node:1234) UnhandledPromiseRejectionWarning
[ Stacktrace altered by https://github.com/grantila/trace-unhandled ]
Error: foo
==== Promise at: ==================
at b (/my/directory/test.js:3:17) 👈
at a (/my/directory/test.js:6:9) 👈
at Object. (/my/directory/test.js:8:13) 👈==== Error at: ====================
at Object. (/my/directory/test.js:1:13)==== Shared trace: ================
at Module._compile (internal/modules/cjs/loader.js:776:30)
... more lines below ...
```Both these examples show **clearly** where the *promise* is left unhandled, and not only where the Error object is constructed.
# Usage
`trace-unhandled` can be used in 4 ways.
* [As a standalone program to bootstrap a Node.js app](#as-a-standalone-program)
* [From a CDN directly to a browser](#in-a-website)
* [Programmatically from JavaScript (either for Node.js or the web using a bundler)](#programatically---api)
* [In unit tests](#in-unit-tests)## As a standalone program
`trace-unhandled` exports a program which can run JavaScript files and shebang scripts. Instead of running your program as `node index.js` you can do `trace-unhandled index.js` as long as `trace-unhandled` is globally installed.
You can also use `npx`:
`npx trace-unhandled index.js`
## In a website
```html
```
To specify a custom logger function, use `setTraceUnhandledLogger`:
```ts
window.setTraceUnhandledLogger( msg => { ... } ); // msg is a string
```## Programatically - API
```ts
require( 'trace-unhandled/register' ); // As early as possible
```or if you want to allow some code to execute before you start tracing:
```ts
const { register } = require( 'trace-unhandled' );// ... whenever you want to start tracing
register( );
```To specify a custom logger function, use `setLogger`:
```ts
const { setLogger } = require( 'trace-unhandled' );
setLogger( msg => { ... } ); // msg is a string
```## In unit tests
To use this package when running `jest`, install the package and configure jest with the following setup:
```js
{
setupFiles: [
"trace-unhandled/register"
]
}
```For `mocha` you can use `--require node_modules/trace-unhandled/register.js`.
[npm-image]: https://img.shields.io/npm/v/trace-unhandled.svg
[npm-url]: https://npmjs.org/package/trace-unhandled
[downloads-image]: https://img.shields.io/npm/dm/trace-unhandled.svg
[build-image]: https://img.shields.io/github/workflow/status/grantila/trace-unhandled/Master.svg
[build-url]: https://github.com/grantila/trace-unhandled/actions?query=workflow%3AMaster
[coverage-image]: https://coveralls.io/repos/github/grantila/trace-unhandled/badge.svg?branch=master
[coverage-url]: https://coveralls.io/github/grantila/trace-unhandled?branch=master
[lgtm-image]: https://img.shields.io/lgtm/grade/javascript/g/grantila/trace-unhandled.svg?logo=lgtm&logoWidth=18
[lgtm-url]: https://lgtm.com/projects/g/grantila/trace-unhandled/context:javascript