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 f18e08d

Browse filesBrowse files
committed
console: do not emit error events
Fixes: #831 Fixes: #947 Ref: #9470 PR-URL: #9744 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
1 parent 0af4183 commit f18e08d
Copy full SHA for f18e08d

File tree

Expand file treeCollapse file tree

4 files changed

+117
-5
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+117
-5
lines changed
Open diff view settings
Collapse file

‎lib/console.js‎

Copy file name to clipboardExpand all lines: lib/console.js
+53-5Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
const util = require('util');
44

5-
function Console(stdout, stderr) {
5+
function Console(stdout, stderr, ignoreErrors = true) {
66
if (!(this instanceof Console)) {
7-
return new Console(stdout, stderr);
7+
return new Console(stdout, stderr, ignoreErrors);
88
}
99
if (!stdout || typeof stdout.write !== 'function') {
1010
throw new TypeError('Console expects a writable stream instance');
@@ -24,8 +24,14 @@ function Console(stdout, stderr) {
2424
Object.defineProperty(this, '_stdout', prop);
2525
prop.value = stderr;
2626
Object.defineProperty(this, '_stderr', prop);
27+
prop.value = ignoreErrors;
28+
Object.defineProperty(this, '_ignoreErrors', prop);
2729
prop.value = new Map();
2830
Object.defineProperty(this, '_times', prop);
31+
prop.value = createWriteErrorHandler(stdout);
32+
Object.defineProperty(this, '_stdoutErrorHandler', prop);
33+
prop.value = createWriteErrorHandler(stderr);
34+
Object.defineProperty(this, '_stderrErrorHandler', prop);
2935

3036
// bind the prototype functions to this Console instance
3137
var keys = Object.keys(Console.prototype);
@@ -35,20 +41,60 @@ function Console(stdout, stderr) {
3541
}
3642
}
3743

44+
// Make a function that can serve as the callback passed to `stream.write()`.
45+
function createWriteErrorHandler(stream) {
46+
return (err) => {
47+
// This conditional evaluates to true if and only if there was an error
48+
// that was not already emitted (which happens when the _write callback
49+
// is invoked asynchronously).
50+
if (err && !stream._writableState.errorEmitted) {
51+
// If there was an error, it will be emitted on `stream` as
52+
// an `error` event. Adding a `once` listener will keep that error
53+
// from becoming an uncaught exception, but since the handler is
54+
// removed after the event, non-console.* writes won’t be affected.
55+
stream.once('error', noop);
56+
}
57+
};
58+
}
59+
60+
function write(ignoreErrors, stream, string, errorhandler) {
61+
if (!ignoreErrors) return stream.write(string);
62+
63+
// There may be an error occurring synchronously (e.g. for files or TTYs
64+
// on POSIX systems) or asynchronously (e.g. pipes on POSIX systems), so
65+
// handle both situations.
66+
try {
67+
// Add and later remove a noop error handler to catch synchronous errors.
68+
stream.once('error', noop);
69+
70+
stream.write(string, errorhandler);
71+
} catch (e) {
72+
// Sorry, there’s no proper way to pass along the error here.
73+
} finally {
74+
stream.removeListener('error', noop);
75+
}
76+
}
77+
3878

3979
// As of v8 5.0.71.32, the combination of rest param, template string
4080
// and .apply(null, args) benchmarks consistently faster than using
4181
// the spread operator when calling util.format.
4282
Console.prototype.log = function log(...args) {
43-
this._stdout.write(`${util.format.apply(null, args)}\n`);
83+
write(this._ignoreErrors,
84+
this._stdout,
85+
`${util.format.apply(null, args)}\n`,
86+
this._stdoutErrorHandler);
4487
};
4588

4689

4790
Console.prototype.info = Console.prototype.log;
4891

4992

5093
Console.prototype.warn = function warn(...args) {
51-
this._stderr.write(`${util.format.apply(null, args)}\n`);
94+
write(this._ignoreErrors,
95+
this._stderr,
96+
`${util.format.apply(null, args)}\n`,
97+
this._stderrErrorHandler);
5298
};
5399

54100

@@ -57,7 +103,7 @@ Console.prototype.error = Console.prototype.warn;
57103

58104
Console.prototype.dir = function dir(object, options) {
59105
options = Object.assign({customInspect: false}, options);
60-
this._stdout.write(`${util.inspect(object, options)}\n`);
106+
write(this._ignoreErrors, this._stdout, `${util.inspect(object, options)}\n`);
61107
};
62108

63109

@@ -99,3 +145,5 @@ Console.prototype.assert = function assert(expression, ...args) {
99145

100146
module.exports = new Console(process.stdout, process.stderr);
101147
module.exports.Console = Console;
148+
149+
function noop() {}
Collapse file
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
const common = require('../common');
3+
const { Console } = require('console');
4+
const { Writable } = require('stream');
5+
const assert = require('assert');
6+
7+
const out = new Writable({
8+
write: common.mustCall((chunk, enc, callback) => {
9+
process.nextTick(callback, new Error('foobar'));
10+
})
11+
});
12+
13+
const c = new Console(out, out, true);
14+
15+
assert.doesNotThrow(() => {
16+
c.log('abc');
17+
});
Collapse file
+47Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
const common = require('../common');
3+
const { Console } = require('console');
4+
const { Writable } = require('stream');
5+
const assert = require('assert');
6+
7+
{
8+
const out = new Writable({
9+
write: common.mustCall((chunk, enc, callback) => {
10+
callback(new Error('foobar'));
11+
})
12+
});
13+
14+
const c = new Console(out, out, true);
15+
16+
assert.doesNotThrow(() => {
17+
c.log('abc');
18+
});
19+
}
20+
21+
{
22+
const out = new Writable({
23+
write: common.mustCall((chunk, enc, callback) => {
24+
throw new Error('foobar');
25+
})
26+
});
27+
28+
const c = new Console(out, out, true);
29+
30+
assert.doesNotThrow(() => {
31+
c.log('abc');
32+
});
33+
}
34+
35+
{
36+
const out = new Writable({
37+
write: common.mustCall((chunk, enc, callback) => {
38+
setImmediate(() => callback(new Error('foobar')));
39+
})
40+
});
41+
42+
const c = new Console(out, out, true);
43+
44+
assert.doesNotThrow(() => {
45+
c.log('abc');
46+
});
47+
}
Collapse file
File renamed without changes.

0 commit comments

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