Common logging for node, express application -- best practice?

dewd picture dewd · Dec 7, 2012 · Viewed 8k times · Source

I'm working on an node.js application with several dozen modules and using bunyan for logging (JSON output, multiple configurable streams). I've been looking for good examples of how to implement a instance across all the modules, but haven't seen what appears to be a really clean example I can learn from.

Below illustrates an approach that works, but seems quite inelegant (ugly) to me. I'm new to node & commonjs javascript in general, so looking for recommendations on how to improve it.

module: ./lib/logger

// load config file (would like this to be passed in to the constructor)
nconf.file({ file: fileConfig});
var logSetting = nconf.get('log');

// instantiate the logger
var Bunyan = require('bunyan');
var log = new Bunyan({
    name: logSetting.name,
streams : [
        { stream  : process.stdout, 
        level : logSetting.stdoutLevel},
        {    path : logSetting.logfile, 
            level : logSetting.logfileLevel}
    ],
serializers : Bunyan.stdSerializers
});

function Logger() {
};

Logger.prototype.info = function info(e) { log.info(e) };
Logger.prototype.debug = function debug(e) { log.debug(e) };
Logger.prototype.trace = function trace(e) { log.trace(e) };
Logger.prototype.error = function error(e) { log.error(e) };
Logger.prototype.warn = function warn(e) {  log.warn(e) };

module.exports = Logger;

module: main app

// create the logger
var logger = require('./lib/logger)
var log = new logger();

// note: would like to pass in options -->  new logger(options)


module: any project module using logger
// open the logger (new, rely on singleton...)
var logger = require('./lib/logger');
var log = new logger();

or view the gist

any recommendations?

EDIT:

I've modified the constructor, making the singleton pattern explicit (rather than implicit as part of the 'require' behaviour.

var log = null;
function Logger(option) {

// make the singleton pattern explicit
if (!Logger.log) {
    Logger.log = this;
}
    return Logger.log;
};  

and then changed the initialization to take an options parameter

// initialize the logger 
Logger.prototype.init = function init(options) {
log = new Bunyan({
    name: options.name,
    streams : [
        { stream  : process.stdout, 
            level : options.stdoutLevel},
        {    path : options.logfile, 
            level : options.logfileLevel}
    ],
    serializers : Bunyan.stdSerializers     
    });
};

Answer

lixiang picture lixiang · Mar 12, 2013

Singleton pattern in nodejs - is it needed? Actually, singleton is perhaps not needed in Node's environment. All you need to do is to create a logger in a separate file say, logger.js:

var bunyan = require("bunyan"); // Bunyan dependency
var logger = bunyan.createLogger({name: "myLogger"});

module.exports = logger;

Then, retrieve this logger from another module:

var logger = require("./logger");
logger.info("Anything you like");