diagnostics_channel: capture console messages

PR-URL: https://github.com/nodejs/node/pull/56292
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Kohei Ueno <kohei.ueno119@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
This commit is contained in:
Stephen Belanger 2025-01-13 20:51:31 +08:00 committed by GitHub
parent af89b537ac
commit db7a31e276
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 149 additions and 6 deletions

View File

@ -1121,6 +1121,43 @@ While the diagnostics\_channel API is now considered stable, the built-in
channels currently available are not. Each channel must be declared stable
independently.
#### Console
`console.log`
* `args` {any\[]}
Emitted when `console.log()` is called. Receives and array of the arguments
passed to `console.log()`.
`console.info`
* `args` {any\[]}
Emitted when `console.info()` is called. Receives and array of the arguments
passed to `console.info()`.
`console.debug`
* `args` {any\[]}
Emitted when `console.debug()` is called. Receives and array of the arguments
passed to `console.debug()`.
`console.warn`
* `args` {any\[]}
Emitted when `console.warn()` is called. Receives and array of the arguments
passed to `console.warn()`.
`console.error`
* `args` {any\[]}
Emitted when `console.error()` is called. Receives and array of the arguments
passed to `console.error()`.
#### HTTP
`http.client.request.created`

View File

@ -61,6 +61,13 @@ const {
} = require('internal/constants');
const kCounts = Symbol('counts');
const { time, timeLog, timeEnd, kNone } = require('internal/util/debuglog');
const { channel } = require('diagnostics_channel');
const onLog = channel('console.log');
const onWarn = channel('console.warn');
const onError = channel('console.error');
const onInfo = channel('console.info');
const onDebug = channel('console.debug');
const kTraceConsoleCategory = 'node,node.console';
@ -371,14 +378,39 @@ function timeLogImpl(consoleRef, label, formatted, args) {
const consoleMethods = {
log(...args) {
if (onLog.hasSubscribers) {
onLog.publish(args);
}
this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
},
info(...args) {
if (onInfo.hasSubscribers) {
onInfo.publish(args);
}
this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
},
debug(...args) {
if (onDebug.hasSubscribers) {
onDebug.publish(args);
}
this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
},
warn(...args) {
if (onWarn.hasSubscribers) {
onWarn.publish(args);
}
this[kWriteToConsole](kUseStderr, this[kFormatForStderr](args));
},
error(...args) {
if (onError.hasSubscribers) {
onError.publish(args);
}
this[kWriteToConsole](kUseStderr, this[kFormatForStderr](args));
},
dir(object, options) {
this[kWriteToConsole](kUseStdout, inspect(object, {
@ -614,10 +646,7 @@ function noop() {}
for (const method of ReflectOwnKeys(consoleMethods))
Console.prototype[method] = consoleMethods[method];
Console.prototype.debug = Console.prototype.log;
Console.prototype.info = Console.prototype.log;
Console.prototype.dirxml = Console.prototype.log;
Console.prototype.error = Console.prototype.warn;
Console.prototype.groupCollapsed = Console.prototype.group;
function initializeGlobalConsole(globalConsole) {

View File

@ -0,0 +1,77 @@
'use strict';
const { mustCall } = require('../common');
const { deepStrictEqual, ok, strictEqual } = require('assert');
const { channel } = require('diagnostics_channel');
const {
hijackStdout,
hijackStderr,
restoreStdout,
restoreStderr
} = require('../common/hijackstdio');
const stdoutMethods = [
'log',
'info',
'debug',
];
const stderrMethods = [
'warn',
'error',
];
const methods = [
...stdoutMethods,
...stderrMethods,
];
const channels = {
log: channel('console.log'),
info: channel('console.info'),
debug: channel('console.debug'),
warn: channel('console.warn'),
error: channel('console.error')
};
process.stdout.isTTY = false;
process.stderr.isTTY = false;
for (const method of methods) {
let intercepted = false;
let formatted = false;
const isStdout = stdoutMethods.includes(method);
const hijack = isStdout ? hijackStdout : hijackStderr;
const restore = isStdout ? restoreStdout : restoreStderr;
const foo = 'string';
const bar = { key: /value/ };
const baz = [ 1, 2, 3 ];
channels[method].subscribe(mustCall((args) => {
// Should not have been formatted yet.
intercepted = true;
ok(!formatted);
// Should receive expected log message args.
deepStrictEqual(args, [foo, bar, baz]);
// Should be able to mutate message args and have it reflected in output.
bar.added = true;
}));
hijack(mustCall((output) => {
// Should have already been intercepted.
formatted = true;
ok(intercepted);
// Should produce expected formatted output with mutated message args.
strictEqual(output, 'string { key: /value/, added: true } [ 1, 2, 3 ]\n');
}));
console[method](foo, bar, baz);
restore();
}

View File

@ -794,7 +794,10 @@ const errorTests = [
expect: [
'Object [console] {',
' log: [Function: log],',
' info: [Function: info],',
' debug: [Function: debug],',
' warn: [Function: warn],',
' error: [Function: error],',
' dir: [Function: dir],',
' time: [Function: time],',
' timeEnd: [Function: timeEnd],',
@ -807,10 +810,7 @@ const errorTests = [
' group: [Function: group],',
' groupEnd: [Function: groupEnd],',
' table: [Function: table],',
/ {2}debug: \[Function: (debug|log)],/,
/ {2}info: \[Function: (info|log)],/,
/ {2}dirxml: \[Function: (dirxml|log)],/,
/ {2}error: \[Function: (error|warn)],/,
/ {2}groupCollapsed: \[Function: (groupCollapsed|group)],/,
/ {2}Console: \[Function: Console],?/,
...process.features.inspector ? [