Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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().

like image 344
DS. Avatar asked Mar 27 '19 22:03

DS.


2 Answers

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} "
like image 71
DS. Avatar answered Oct 16 '22 23:10

DS.


I had a similar problem, and after much trial and error i think i have a solution that you might be interested in. As i mentioned in my last update, we ended up building our own logger. well, over the weekend i published this logger to npm, and you're welcome to check it out.

It should have more or less identical output to console.log. If you notice any inconsistencies, please let me know.

Also it also has multiple transports, and you can even pass custom ones, and you can even "wrap" the console functions to quickly integrate into your project.

example code:

const {createLogger,wrapConsole,unwrapConsole} = require('@r3wt/log');
const log = createLogger({log_level:'info',transports:['console','file']});
wrapConsole(log);//wraps the console globally with the log instance, making integration into large existing project less painful

// NOTE: only the following 4 functions are wrapped. 
console.log('hi!');
console.warn('warning');
console.error('error');
console.info('info');

unwrapConsole();//unwrap console globally

You can find the library here as well as more code examples and basic documentation if you're interested, and PR's with features and fixes are welcomed and encouraged. code is MIT so you are free to fork and create your own version :-)

Best of luck, and i hope this helps.

like image 4
r3wt Avatar answered Oct 16 '22 23:10

r3wt