Skip to content

Commit dd20e68

Browse files
committed
process: add optional detail to process emitWarning
Adds a new method signature variant for process.emitWarning() that accepts an options object. The options object may include a new `detail` option that allows additional detail text to be associated with the warning. By default, this additional text will be printed to stderr along with the warning, and included on the Warning Error object using the `.detail` property. e.g. ```js process.emitWarning('A message', { code: 'WARNING123', detail: 'This is additional detail' }); // Emits: // (node {pid}) [WARNING123] Warning: A message // This is additional detail ``` PR-URL: #12725 Reviewed-By: Colin Ihrig <[email protected]>
1 parent 23fc082 commit dd20e68

File tree

3 files changed

+107
-36
lines changed

3 files changed

+107
-36
lines changed

doc/api/process.md

+51-5
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,52 @@ process's [`ChildProcess.disconnect()`][].
637637
If the Node.js process was not spawned with an IPC channel,
638638
`process.disconnect()` will be `undefined`.
639639

640+
## process.emitWarning(warning[, options])
641+
<!-- YAML
642+
added: REPLACEME
643+
-->
644+
645+
* `warning` {string|Error} The warning to emit.
646+
* `options` {Object}
647+
* `type` {string} When `warning` is a String, `type` is the name to use
648+
for the *type* of warning being emitted. Default: `Warning`.
649+
* `code` {string} A unique identifier for the warning instance being emitted.
650+
* `ctor` {Function} When `warning` is a String, `ctor` is an optional
651+
function used to limit the generated stack trace. Default
652+
`process.emitWarning`
653+
* `detail` {string} Additional text to include with the error.
654+
655+
The `process.emitWarning()` method can be used to emit custom or application
656+
specific process warnings. These can be listened for by adding a handler to the
657+
[`process.on('warning')`][process_warning] event.
658+
659+
```js
660+
// Emit a warning with a code and additional detail.
661+
process.emitWarning('Something happened!', {
662+
code: 'MY_WARNING',
663+
detail: 'This is some additional information'
664+
});
665+
// Emits:
666+
// (node:56338) [MY_WARNING] Warning: Something happened!
667+
// This is some additional information
668+
```
669+
670+
In this example, an `Error` object is generated internally by
671+
`process.emitWarning()` and passed through to the
672+
[`process.on('warning')`][process_warning] event.
673+
674+
```js
675+
process.on('warning', (warning) => {
676+
console.warn(warning.name); // 'Warning'
677+
console.warn(warning.message); // 'Something happened!'
678+
console.warn(warning.code); // 'MY_WARNING'
679+
console.warn(warning.stack); // Stack trace
680+
console.warn(warning.detail); // 'This is some additional information'
681+
});
682+
```
683+
684+
If `warning` is passed as an `Error` object, the `options` argument is ignored.
685+
640686
## process.emitWarning(warning[, type[, code]][, ctor])
641687
<!-- YAML
642688
added: v6.0.0
@@ -655,13 +701,13 @@ specific process warnings. These can be listened for by adding a handler to the
655701
[`process.on('warning')`][process_warning] event.
656702

657703
```js
658-
// Emit a warning using a string...
704+
// Emit a warning using a string.
659705
process.emitWarning('Something happened!');
660706
// Emits: (node: 56338) Warning: Something happened!
661707
```
662708

663709
```js
664-
// Emit a warning using a string and a type...
710+
// Emit a warning using a string and a type.
665711
process.emitWarning('Something Happened!', 'CustomWarning');
666712
// Emits: (node:56338) CustomWarning: Something Happened!
667713
```
@@ -689,14 +735,14 @@ If `warning` is passed as an `Error` object, it will be passed through to the
689735
`code` and `ctor` arguments will be ignored):
690736

691737
```js
692-
// Emit a warning using an Error object...
693-
const myWarning = new Error('Warning! Something happened!');
738+
// Emit a warning using an Error object.
739+
const myWarning = new Error('Something happened!');
694740
// Use the Error name property to specify the type name
695741
myWarning.name = 'CustomWarning';
696742
myWarning.code = 'WARN001';
697743

698744
process.emitWarning(myWarning);
699-
// Emits: (node:56338) [WARN001] CustomWarning: Warning! Something happened!
745+
// Emits: (node:56338) [WARN001] CustomWarning: Something happened!
700746
```
701747

702748
A `TypeError` is thrown if `warning` is anything other than a string or `Error`

lib/internal/process/warning.js

+19-11
Original file line numberDiff line numberDiff line change
@@ -90,30 +90,37 @@ function setupProcessWarnings() {
9090
if (isDeprecation && process.noDeprecation) return;
9191
const trace = process.traceProcessWarnings ||
9292
(isDeprecation && process.traceDeprecation);
93+
let msg = `${prefix}`;
94+
if (warning.code)
95+
msg += `[${warning.code}] `;
9396
if (trace && warning.stack) {
94-
if (warning.code) {
95-
output(`${prefix}[${warning.code}] ${warning.stack}`);
96-
} else {
97-
output(`${prefix}${warning.stack}`);
98-
}
97+
msg += `${warning.stack}`;
9998
} else {
10099
const toString =
101100
typeof warning.toString === 'function' ?
102101
warning.toString : Error.prototype.toString;
103-
if (warning.code) {
104-
output(`${prefix}[${warning.code}] ${toString.apply(warning)}`);
105-
} else {
106-
output(`${prefix}${toString.apply(warning)}`);
107-
}
102+
msg += `${toString.apply(warning)}`;
108103
}
104+
if (typeof warning.detail === 'string') {
105+
msg += `\n${warning.detail}`;
106+
}
107+
output(msg);
109108
});
110109
}
111110

112111
// process.emitWarning(error)
113112
// process.emitWarning(str[, type[, code]][, ctor])
113+
// process.emitWarning(str[, options])
114114
process.emitWarning = function(warning, type, code, ctor) {
115115
const errors = lazyErrors();
116-
if (typeof type === 'function') {
116+
var detail;
117+
if (type !== null && typeof type === 'object' && !Array.isArray(type)) {
118+
ctor = type.ctor;
119+
code = type.code;
120+
if (typeof type.detail === 'string')
121+
detail = type.detail;
122+
type = type.type || 'Warning';
123+
} else if (typeof type === 'function') {
117124
ctor = type;
118125
code = undefined;
119126
type = 'Warning';
@@ -130,6 +137,7 @@ function setupProcessWarnings() {
130137
warning = new Error(warning);
131138
warning.name = String(type || 'Warning');
132139
if (code !== undefined) warning.code = code;
140+
if (detail !== undefined) warning.detail = detail;
133141
Error.captureStackTrace(warning, ctor || process.emitWarning);
134142
}
135143
if (!(warning instanceof Error)) {

test/parallel/test-process-emitwarning.js

+37-20
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,48 @@
44

55
const common = require('../common');
66
const assert = require('assert');
7-
const util = require('util');
7+
8+
const testMsg = 'A Warning';
9+
const testCode = 'CODE001';
10+
const testDetail = 'Some detail';
11+
const testType = 'CustomWarning';
812

913
process.on('warning', common.mustCall((warning) => {
1014
assert(warning);
1115
assert(/^(Warning|CustomWarning)/.test(warning.name));
12-
assert.strictEqual(warning.message, 'A Warning');
13-
if (warning.code) assert.strictEqual(warning.code, 'CODE001');
14-
}, 8));
15-
16-
process.emitWarning('A Warning');
17-
process.emitWarning('A Warning', 'CustomWarning');
18-
process.emitWarning('A Warning', CustomWarning);
19-
process.emitWarning('A Warning', 'CustomWarning', CustomWarning);
20-
process.emitWarning('A Warning', 'CustomWarning', 'CODE001');
21-
22-
function CustomWarning() {
23-
Error.call(this);
24-
this.name = 'CustomWarning';
25-
this.message = 'A Warning';
26-
this.code = 'CODE001';
27-
Error.captureStackTrace(this, CustomWarning);
16+
assert.strictEqual(warning.message, testMsg);
17+
if (warning.code) assert.strictEqual(warning.code, testCode);
18+
if (warning.detail) assert.strictEqual(warning.detail, testDetail);
19+
}, 15));
20+
21+
class CustomWarning extends Error {
22+
constructor() {
23+
super();
24+
this.name = testType;
25+
this.message = testMsg;
26+
this.code = testCode;
27+
Error.captureStackTrace(this, CustomWarning);
28+
}
2829
}
29-
util.inherits(CustomWarning, Error);
30-
process.emitWarning(new CustomWarning());
30+
31+
[
32+
[testMsg],
33+
[testMsg, testType],
34+
[testMsg, CustomWarning],
35+
[testMsg, testType, CustomWarning],
36+
[testMsg, testType, testCode],
37+
[testMsg, { type: testType }],
38+
[testMsg, { type: testType, code: testCode }],
39+
[testMsg, { type: testType, code: testCode, detail: testDetail }],
40+
[new CustomWarning()],
41+
// detail will be ignored for the following. No errors thrown
42+
[testMsg, { type: testType, code: testCode, detail: true }],
43+
[testMsg, { type: testType, code: testCode, detail: [] }],
44+
[testMsg, { type: testType, code: testCode, detail: null }],
45+
[testMsg, { type: testType, code: testCode, detail: 1 }]
46+
].forEach((i) => {
47+
assert.doesNotThrow(() => process.emitWarning.apply(null, i));
48+
});
3149

3250
const warningNoToString = new CustomWarning();
3351
warningNoToString.toString = null;
@@ -47,7 +65,6 @@ assert.throws(() => process.emitWarning(1), expectedError);
4765
assert.throws(() => process.emitWarning({}), expectedError);
4866
assert.throws(() => process.emitWarning(true), expectedError);
4967
assert.throws(() => process.emitWarning([]), expectedError);
50-
assert.throws(() => process.emitWarning('', {}), expectedError);
5168
assert.throws(() => process.emitWarning('', '', {}), expectedError);
5269
assert.throws(() => process.emitWarning('', 1), expectedError);
5370
assert.throws(() => process.emitWarning('', '', 1), expectedError);

0 commit comments

Comments
 (0)