javascriptnode.jsloggingwinston

How to make `winston` logging library work like `console.log`?


The winston library is great for transports and flexibility. I'd like to use it to allow configuring levels and redirecting to files, but would like to reproduce console.log behavior for formatting, and having trouble.

Here's what I have so far:

const log = winston.createLogger({
  level: 'debug',
  format: format.combine(
    format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
    format.splat(),
    format.colorize(),
    format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
  ),
  transports: [
    new winston.transports.Stream({
      stream: process.stderr,
      level: 'debug',
    })
  ],
});

log.info("Hello, %s", "Bob");   // Works: outputs "Hello, Bob"

But this don't work:

log.info("Hello", "Bob");
log.info("Hello", 123, {someObj: 1});

I'd like all extraneous objects after those taken up by splat() to get added on, space-separated, and converted to string preferably using util.inspect().


Solution

  • Answering my own question. The issue is with format.splat -- pure util.format offers a simpler and more expected behavior. Replacing format.splat with this utilFormatter addresses the problem:

    const util = require('util');
    
    function transform(info, opts) {
      const args = info[Symbol.for('splat')];
      if (args) { info.message = util.format(info.message, ...args); }
      return info;
    }
    
    function utilFormatter() { return {transform}; }
    

    The example from my question then looks like so:

    const log = winston.createLogger({
      level: 'debug',
      format: format.combine(
        format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
        utilFormatter(),     // <-- this is what changed
        format.colorize(),
        format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
      ),
      transports: [
        new winston.transports.Stream({
          stream: process.stderr,
          level: 'debug',
        })
      ],
    });
    
    log.info("Hello, %s", "Bob");          // Works: outputs "Hello, Bob"
    log.info("Hello", "Bob");              // Works: outputs "Hello Bob"
    log.info("Hello", 123, {someObj: 1});  // Works: outputs "Hello 123 { someObj: 1} "