Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process: allow monitoring uncaughtException #31257

Closed
Prev Previous commit
Next Next commit
replace symbol uncaughtExceptionMonitor by a string
  • Loading branch information
Flarna committed Jan 10, 2020
commit 5daab4d8b5077acdec562cc1c6fbebf4c250bcda
56 changes: 30 additions & 26 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,18 +263,8 @@ console.log('This will not run.');
```

It is possible to monitor `'uncaughtException'` events without overriding the
default behavior to exit the process by installing a listener using the symbol
`uncaughtExceptionMonitor`.

```js
process.on(process.uncaughtExceptionMonitor, (err, origin) => {
MyMonitoringTool.logSync(err, origin);
});

// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
// Still crashes Node.js
```
default behavior to exit the process by installing a
`'uncaughtExceptionMonitor'` listener.

#### Warning: Using `'uncaughtException'` correctly

Expand Down Expand Up @@ -303,6 +293,34 @@ To restart a crashed application in a more reliable way, whether
in a separate process to detect application failures and recover or restart as
needed.

### Event: `'uncaughtExceptionMonitor'`
<!-- YAML
added: REPLACEME
-->

* `err` {Error} The uncaught exception.
* `origin` {string} Indicates if the exception originates from an unhandled
rejection or from synchronous errors. Can either be `'uncaughtException'` or
`'unhandledRejection'`.

The `'uncaughtExceptionMonitor'` event is emitted before an
`'uncaughtException'` event is emitted or a hook installed via
[`process.setUncaughtExceptionCaptureCallback()`][] is called.

Installing a `'uncaughtExceptionMonitor'` listener does not change the behavior
Flarna marked this conversation as resolved.
Show resolved Hide resolved
once an `'uncaughtException'` event is emitted, therefore the process will
Flarna marked this conversation as resolved.
Show resolved Hide resolved
still crash if no regular `'uncaughtException'` listener is installed.
Flarna marked this conversation as resolved.
Show resolved Hide resolved

```js
process.on('uncaughtExceptionMonitor', (err, origin) => {
MyMonitoringTool.logSync(err, origin);
});

// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
// Still crashes Node.js
```

### Event: `'unhandledRejection'`
<!-- YAML
added: v1.4.1
Expand Down Expand Up @@ -2334,20 +2352,6 @@ documentation for the [`'warning'` event][process_warning] and the
[`emitWarning()` method][process_emit_warning] for more information about this
flag's behavior.

## `process.uncaughtExceptionMonitor`
<!-- YAML
added: REPLACEME
-->

This symbol shall be used to install a listener for only monitoring
`'uncaughtException'` events. Listeners installed using this symbol are called
before the regular `'uncaughtException'` listeners and before a hook
installed via [`process.setUncaughtExceptionCaptureCallback()`][].

Installing a listener using this symbol does not change the behavior once an
`'uncaughtException'` event is emitted, therefore the process will still crash
if no regular `'uncaughtException'` listener is installed.

## `process.umask([mask])`
<!-- YAML
added: v0.1.19
Expand Down
9 changes: 1 addition & 8 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,7 @@ ObjectDefineProperty(process, 'features', {
const {
onGlobalUncaughtException,
setUncaughtExceptionCaptureCallback,
hasUncaughtExceptionCaptureCallback,
kUncaughtExceptionMonitor
hasUncaughtExceptionCaptureCallback
} = require('internal/process/execution');

// For legacy reasons this is still called `_fatalException`, even
Expand All @@ -221,12 +220,6 @@ ObjectDefineProperty(process, 'features', {
setUncaughtExceptionCaptureCallback;
process.hasUncaughtExceptionCaptureCallback =
hasUncaughtExceptionCaptureCallback;
ObjectDefineProperty(process, 'uncaughtExceptionMonitor', {
value: kUncaughtExceptionMonitor,
writable: false,
configurable: true,
enumerable: true
});
}

const { emitWarning } = require('internal/process/warning');
Expand Down
8 changes: 2 additions & 6 deletions lib/internal/process/execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
const {
JSONStringify,
PromiseResolve,
Symbol,
} = primordials;

const path = require('path');
Expand All @@ -28,8 +27,6 @@ const {
// communication with JS.
const { shouldAbortOnUncaughtToggle } = internalBinding('util');

const kUncaughtExceptionMonitor = Symbol('process.uncaughtExceptionMonitor');

function tryGetCwd() {
try {
return process.cwd();
Expand Down Expand Up @@ -162,7 +159,7 @@ function createOnGlobalUncaughtException() {
}

const type = fromPromise ? 'unhandledRejection' : 'uncaughtException';
process.emit(kUncaughtExceptionMonitor, er, type);
process.emit('uncaughtExceptionMonitor', er, type);
if (exceptionHandlerState.captureFn !== null) {
exceptionHandlerState.captureFn(er);
} else if (!process.emit('uncaughtException', er, type)) {
Expand Down Expand Up @@ -218,6 +215,5 @@ module.exports = {
evalScript,
onGlobalUncaughtException: createOnGlobalUncaughtException(),
setUncaughtExceptionCaptureCallback,
hasUncaughtExceptionCaptureCallback,
kUncaughtExceptionMonitor
hasUncaughtExceptionCaptureCallback
};
2 changes: 1 addition & 1 deletion test/fixtures/uncaught-exceptions/uncaught-monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Keep the event loop alive.
setTimeout(() => {}, 1e6);

process.on(process.uncaughtExceptionMonitor, (err) => {
process.on('uncaughtExceptionMonitor', (err) => {
console.log(`Monitored: ${err.message}`);
});

Flarna marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-process-uncaught-exception-monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const fixtures = require('../common/fixtures');
const theErr = new Error('MyError');

process.on(
process.uncaughtExceptionMonitor,
'uncaughtExceptionMonitor',
common.mustCall((err, origin) => {
assert.strictEqual(err, theErr);
assert.strictEqual(origin, 'uncaughtException');
Expand Down