text: In this blog post I will show how to intercept messages logged by a Node process using a pre-loaded module. You can find the source code for these examples in bahmutov/capture-logs-example repository.
  Capture console logs
  Imagine you want to collect all strings logged from a Node program. You could proxy all
  console.log calls and store them until needed. Take an example Node program like this one in index.js:
  When we run this program, all logs are written to their respective output streams. Note that values are substituted into placeholders like
  %s -> "console".
  Note that
  console.log writes its messages to
  STDOUT, while
  console.warn and
  console.error write to
  STDERR. You can verify this by hiding
  STDERR stream via redirect.
  Great, now let's collect the messages by pre-loading a module that is going to proxy
  console.* methods. Here is the log.js file:
  Each method like
  console.log is replaced with our function that keeps a copy of the formatted string and calls the original
  log method. We can now run our original program, but require the
  ./log.js first; all logged strings will be collected and printed again at the end.
  Capture
  debug logs
  I love using
  debug module to control my verbose logs. Just import the module and control if its messages are showing up in the terminal using an environment variable
  DEBUG=some:name:space. Here is a copy of the program but with additional logging statement. See index-debug.js file:
  If we run the program "normally" the
  debug calls are ignored. We need to enable "verbose" namespace to actually see them.
  Perfect - can we capture the log calls to the
  debug instances? Well,
  debug module writes directly into
  process.stderr stream bypassing
  console.* methods, thus our proxy is not going to work. Luckily, the
  debug module exposes its internals so we can easily proxy its methods. Bonus: we can log even the disabled
  debug namespaces!
  Look at the implementation of log-debug.js. When a new debug log instance is created using
  require('debug')(... namespace name ...), it is added to the list of debug instances. That list is an
  Array instance, and a new instance is pushed to the array using "standard"
  debug.instances.push(). Well, we can overwrite this method, just like we can overwrite pretty much everything in JavaScript. When we do this, we get access to every
  debug instance instantiated by the process. That's where we can insert out logic to capture debug log messages - even if the namespace is disabled!
  The above file
  log-debug.js exports the
  logDebugCalls and we can call it from our
  log.js file passing the
  messages list. Thus the debug messages get inserted into the same list as the intercepted
  console.log messages, giving us the right order.
  And there is the logging in action - first let's run with
  DEBUG=verbose enabled. The
  debug call shows up in the terminal AND is captured. Then we will run the process without
  DEBUG environment variable. The
  debug call is NOT in the normal terminal output, because the namespace is not enabled, yet it is still captured.
  Beautiful - we have all the logs we might need, yet the "normal" terminal output only shows top level messages. We are now free to do anything with the verbose logs. For example we could show all the logs ONLY if something goes wrong, avoiding double test runs like locha does.
  See also
  - I have released the log interception in
  @bahmutov/all-logsNPM module. It can collect all
  console.{log, warn, error}messages
  - all messages via
  debugmodule
  - all messages via
  util.debuglog(see the update below)
  - Good logging
  - OO vs FP console log example
  debugmodule
  - Source code for this blog post is in the bahmutov/capture-logs-example repository.
  Update 1 -
  util.debuglog
  In Node, there is built-in
  NODE_DEBUG=<namespace> mechanism for verbose logs, see
  util.debuglog.
  If you run the above piece of code with
  NODE_DEBUG=foo it will show the namespace (uppercased) and process id
  One can intercept these log messages by overwriting
  util.debuglog method.