Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 62d3beb

Browse filesBrowse files
Flarnatargos
authored andcommitted
events: allow monitoring error events
Installing an error listener has a side effect that emitted errors are considered as handled. This is quite bad for monitoring/logging tools which tend to be interested in errors but don't want to cause side effects like swallow an exception. There are some workarounds in the wild like monkey patching emit or remit the error if monitoring tool detects that it is the only listener but this is error prone and risky. This PR allows to install a listener to monitor errors with the side effect to consume the error. To avoid conflicts with other events it exports a symbol on EventEmitter which owns this special meaning. Refs: open-telemetry/opentelemetry-js#225 PR-URL: #30932 Refs: open-telemetry/opentelemetry-js#225 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent e4e086a commit 62d3beb
Copy full SHA for 62d3beb

File tree

Expand file treeCollapse file tree

3 files changed

+69
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+69
-2
lines changed
Open diff view settings
Collapse file

‎doc/api/events.md‎

Copy file name to clipboardExpand all lines: doc/api/events.md
+25Lines changed: 25 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ myEmitter.emit('error', new Error('whoops!'));
155155
// Prints: whoops! there was an error
156156
```
157157

158+
It is possible to monitor `'error'` events without consuming the emitted error
159+
by installing a listener using the symbol `errorMonitor`.
160+
161+
```js
162+
const myEmitter = new MyEmitter();
163+
myEmitter.on(EventEmitter.errorMonitor, (err) => {
164+
MyMonitoringTool.log(err);
165+
});
166+
myEmitter.emit('error', new Error('whoops!'));
167+
// Still throws and crashes Node.js
168+
```
169+
158170
## Capture Rejections of Promises
159171

160172
> Stability: 1 - captureRejections is experimental.
@@ -348,6 +360,19 @@ the event emitter instance, the event’s name and the number of attached
348360
listeners, respectively.
349361
Its `name` property is set to `'MaxListenersExceededWarning'`.
350362

363+
### `EventEmitter.errorMonitor`
364+
<!-- YAML
365+
added: REPLACEME
366+
-->
367+
368+
This symbol shall be used to install a listener for only monitoring `'error'`
369+
events. Listeners installed using this symbol are called before the regular
370+
`'error'` listeners are called.
371+
372+
Installing a listener using this symbol does not change the behavior once an
373+
`'error'` event is emitted, therefore the process will still crash if no
374+
regular `'error'` listener is installed.
375+
351376
### `emitter.addListener(eventName, listener)`
352377
<!-- YAML
353378
added: v0.1.26
Collapse file

‎lib/events.js‎

Copy file name to clipboardExpand all lines: lib/events.js
+12-2Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const {
5656
} = require('internal/util/inspect');
5757

5858
const kCapture = Symbol('kCapture');
59+
const kErrorMonitor = Symbol('events.errorMonitor');
5960

6061
function EventEmitter(opts) {
6162
EventEmitter.init.call(this, opts);
@@ -84,6 +85,13 @@ ObjectDefineProperty(EventEmitter, 'captureRejections', {
8485
enumerable: true
8586
});
8687

88+
ObjectDefineProperty(EventEmitter, 'errorMonitor', {
89+
value: kErrorMonitor,
90+
writable: false,
91+
configurable: true,
92+
enumerable: true
93+
});
94+
8795
// The default for captureRejections is false
8896
ObjectDefineProperty(EventEmitter.prototype, kCapture, {
8997
value: false,
@@ -257,9 +265,11 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
257265
let doError = (type === 'error');
258266

259267
const events = this._events;
260-
if (events !== undefined)
268+
if (events !== undefined) {
269+
if (doError && events[kErrorMonitor] !== undefined)
270+
this.emit(kErrorMonitor, ...args);
261271
doError = (doError && events.error === undefined);
262-
else if (!doError)
272+
} else if (!doError)
263273
return false;
264274

265275
// If there is no 'error' event listener then throw.
Collapse file
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const EventEmitter = require('events');
5+
6+
const EE = new EventEmitter();
7+
const theErr = new Error('MyError');
8+
9+
EE.on(
10+
EventEmitter.errorMonitor,
11+
common.mustCall(function onErrorMonitor(e) {
12+
assert.strictEqual(e, theErr);
13+
}, 3)
14+
);
15+
16+
// Verify with no error listener
17+
common.expectsError(
18+
() => EE.emit('error', theErr), theErr
19+
);
20+
21+
// Verify with error listener
22+
EE.once('error', common.mustCall((e) => assert.strictEqual(e, theErr)));
23+
EE.emit('error', theErr);
24+
25+
26+
// Verify it works with once
27+
process.nextTick(() => EE.emit('error', theErr));
28+
assert.rejects(EventEmitter.once(EE, 'notTriggered'), theErr);
29+
30+
// Only error events trigger error monitor
31+
EE.on('aEvent', common.mustCall());
32+
EE.emit('aEvent');

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.