javascriptnode.jsloggingsingletonbunyan

design pattern for wrapping logger in node.js application


I am writing a node.js application and using bunyan for logging. what i would like to do is to create one instance of the bunyan logger in the initialization of my app and from now on i want every module that will require the logger will get the same instance with the same configuration options.

// index.js
var logger = require('./app/utils/logger');
var config = require('./app/config');

config.init().then(function(configData) {
  // create the logger instance once
  var log = logger({
      name: 'appLogger'
      level: configData['log.level'],
      src: process.env.NODE_ENV === 'development',
      streams: [{
         path: path.resolve(configData['log.file']),
         type: 'file'
      }]
    });
 log.info('logger created');
}).catch(function(err) {
  console.log(err)
});

now i want that every module in my app will get the same logger instance:

// foo.js
var log = require('./app/utils/logger');
log.info('this should be logged in the file that was defined in index.js');

what is the recommended design pattern that i should implement in the logger module?

// logger.js
var bunyan = require('bunyan');
// bunyan.createLogger(options)
// what should be here?

Solution

  • You can have your logger act as both a constructor function as well as the logger singleton off of which to hang your info(), debug(), warn() and error() methods.

    // logger.js
    var bunyan = require('bunyan');
    // bunyan.createLogger(options)
    
    var name, level, src, streams;
    
    var logger = function(params){
        name = params.name;
        level = params.level;
        src = params.src;
        streams = params.streams;
    
        logger.info = function(msg){
            console.log("writing to " + streams.path);
        };
        // logger.debug = ...
    
        return logger;
    };
    
    module.exports = logger;
    

    Notice how the info() and other methods aren't created until you've actually called the logger function. The logger() function doesn't actually create the singleton logger -- it just creates the functions that hang off it.