diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index 6fa1a57f3eeb60..0f21259a98b1f4 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -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` diff --git a/lib/internal/console/constructor.js b/lib/internal/console/constructor.js index cefb50fb35e32b..26f2e837d74f6f 100644 --- a/lib/internal/console/constructor.js +++ b/lib/internal/console/constructor.js @@ -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) { diff --git a/test/parallel/test-console-diagnostics-channels.js b/test/parallel/test-console-diagnostics-channels.js new file mode 100644 index 00000000000000..7ee4f2626a3b07 --- /dev/null +++ b/test/parallel/test-console-diagnostics-channels.js @@ -0,0 +1,82 @@ +'use strict'; + +const { mustCall } = require('../common'); +const { deepStrictEqual, strictEqual, match, ok } = require('assert'); +const { formatWithOptions } = require('util'); + +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 hijack = stdoutMethods.includes(method) + ? hijackStdout + : hijackStderr; + + const restore = stdoutMethods.includes(method) + ? 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. + deepStrictEqual(output, 'string { key: /value/, added: true } [ 1, 2, 3 ]\n'); + })); + + console[method](foo, bar, baz); + restore(); +}