1 min read

Parameter handling for Node.js logging with Winston

Making Winston log statements act like console.log()

After a while building a Node.js application (Express-based), I realised that console.log really wasn’t going to scale, assuming I wanted some kind of logging when (if) it made it into production.

Some Googling later (well … actually DuckDuckGoing) - I settled on Winston. I like the approach with transports, and it seems easy to start using.

The only thing that needed improving was the handling of parameters - it wasn’t a drop-in for console.log, because it wouldn’t properly print the arguments given to the log method.

Some more searching turned up this comment by Thijs Koerselman that mostly did the job, but it didn’t quite handle Objects. I’ve finally managed to learn enough JavaScript that I was able to fix that. Though I'm pretty sure those with more JS experience will find better ways of doing it. :-) I thought I’d share the changed version, in case it helps someone else later down the line.

I expose logging via a wrapper - so in src/logger.js I have something like the following code:

wrap = {};

// Make sure the function has a 'this'
wrap.debug = logger.debug.bind(logger);
wrap.debug = function () {
  // Convert arguments to real array
  var args = Array.prototype.slice.call(arguments);
  // For each argument, if it's an object, JSON-ify it.
  args = args.map(x => {
    return ((x instanceof Object) ? JSON.stringify(x) : x);
  // Join it all back together and send it to logger.
  var str = args.join(" ");
  logger.log.apply(logger, ["debug", str]);
Wrapping the 'debug' statement

Where logger is a Winston instance. The debug.bind was necessary as some calls require a this to be present. For the methods where you aren’t adding the unpacking function, just export those more or less as-is:

wrap.warn = logger.warn.bind(logger);

Finally, I export it:

module.exports = {
  logger: wrap