How do Winston's log streams work?

drzax picture drzax · Dec 10, 2013 · Viewed 10.6k times · Source

The Winston documentation has a section on streaming logs which says:

Streaming allows you to stream your logs back from your chosen transport.

and gives the following code example:

//
// Start at the end.
//
winston.stream({ start: -1 }).on('log', function(log) {
  console.log(log);
});

My reading of this is that each new log message added would be output to the console. The {start: -1} config tells the stream to start at the end of the file, so only new log entries are output. I expect the following Node script would result in each existing line of the test.log file being output to the console, and then a new object to be output every 500ms thereafter.

var winston = require('winston');
winston.add(winston.transports.File, {
    filename: 'test.log'
});
winston.remove(winston.transports.Console);
winston.stream().on('log', function(log) {
    console.log(log);
});

setInterval(function(){
    winston.log('info', 'help');
}, 500);

I would expect to see something like the following output:

{"level":"info","message":"help","timestamp":"2013-12-10T05:55:15.806Z"}
{"level":"info","message":"help","timestamp":"2013-12-10T05:55:16.307Z"}
{"level":"info","message":"help","timestamp":"2013-12-10T05:55:16.809Z"}
{"level":"info","message":"help","timestamp":"2013-12-10T05:55:17.309Z"}
{"level":"info","message":"help","timestamp":"2013-12-10T05:56:48.316Z"}

What actually occurs is that the logging works as expected with the File transport (the file gets a new log entry every 500ms) but there is no output to the console. The console.log(log) line is never called.

Have I missed something obvious, or misunderstood the purpose of Winston's log streams?

Answer

user579089 picture user579089 · Mar 28, 2014

I have experienced the same kind of bugg that you are describing. My conclusion is that the default logger var winston = require('winston') do not work with the functions query, stream nor is an EventEmitter so that you can use winston.on('logging', function() {...}).

The solution you need to use is to instantiate your own logger like so:

  var logger = new (winston.Logger)({
    transports: [
      new (winston.transports.Console)({ level: 'info' }),
      new (winston.transports.File)({ filename: 'app.log' })
    ]
  });

and then you do some logging:

  setInterval(function(){
    logger.log('info', 'logging some stuff..');
  }, 500);

then you can stream the already logged entries by using stream:

  logger.stream().on('log', function(log) {
    console.log('>>> ', log);
  });

I think you have misunderstood the stream function because it do not stream log-entries on the fly, it just streams all the entries you have already logged. To hook up an event to your logger you can use the 'logging' event on the logger object:

  logger.on('logging', function (transport, level, msg, meta) {
    // [msg] and [meta] have now been logged at [level] to [transport]
    console.log("[%s] and [%s] have now been logged at [%s] to [%s]",
                 msg, JSON.stringify(meta), level, transport.name);
  });

I do not know why this is not supported by the default logger and as I said in the beginning of this post I get errors inside of the async-library (dependency to winston) when using the query or stream functions with the default logger.