node.jsexpressloggingwinston

How to add uuid in every winston log node js per request?


I am using winston logger. I want to add uuid in every logs having same uuid per request.

In app.js

var distributorapp = require('./routes/distributorapp');
app.use('/dstapp',distributorapp);

In routes/distributorapp.js(Middleware)

var qs = require('querystring');
var request = require('request');
var logger = require('../locallibs/logger');
var uuid = require('uuid/v1');
module.exports = {
    mddlw: function (req, res, next) {
        req.bodyData = qs.parse(req.body); // parsing body and added to request object
        req.uuid = uuid(); // Adding uuid to request to available every where throught request
        callHsmRest(req, res); // function to do some logic and handle middleware functionality
    }
};

In logger.js

var winston = require('winston');
var fs = require('fs');
var moment = require('moment');
var today = moment().format('YYYY-MM-DD');

if (!fs.existsSync(today)) {
    fs.mkdirSync(today);
}


function customFileFormatter(options) {
    console.log(options);
    return options.timestamp() + ' [' + options.level.toUpperCase() + '] ' + (undefined !== options.message ? options.message : '') +
            (options.meta && Object.keys(options.meta).length ? JSON.stringify(options.meta) : '');
}

var logger = new (winston.Logger)({
    transports: [
        new (winston.transports.File)({
            timestamp: function () {
                return moment().format();
            },
            json: false,
            filename: today + '/test.log',
            formatter: customFileFormatter
        })
    ]
});

Now in every request I want to generate uuid and add it to request body.So I have added in Middleware.But how it will be available to logger.js in customFileFormatter formatter function?

When some one uses this logger to log any data i want that uuid to be prepended in logger formatter in every logs through request.

If some one require logger.js and do

logger.info("Hello");
logger.info("Hi");

Currently following I have following logs

2017-02-24T12:36:23+05:30 [INFO] "Hello"
2017-02-24T12:36:23+05:30 [INFO] "Hi"

But I want

2017-02-24T12:36:23+05:30 [INFO] c00d6800-fa5f-11e6-83c2-f531bfc95472 "Hello"
2017-02-24T12:36:23+05:30 [INFO] c00d6800-fa5f-11e6-83c2-f531bfc95472 "Hi"


Also I want to change logger file path according to route middleware.

Currently when request came from /dstapp it uses distributorapp Middleware and every subsequent logs from this request goes to path dstapp/2017-02-24/test.log
But when request came from lets say /anotherapp it uses anotherapp Middleware and subsequent logs from this request goes to path anotherapp/2017-02-24/test.log

I have searched through every where but can't find any solution Thanks in Advance


Solution

  • I had to face this same problem. I found out a solution using node-uuid library to generate a unique uuid for each request, and continuation-local-storage library to share information among modules.

    1º. I added a middleware functionality to create the uuid for each request and add it to the namespace I had created:

    var uuid = require('node-uuid');
    var createNamespace = require('continuation-local-storage').createNamespace;
    var myRequest = createNamespace('my request');
    
    // Run the context for each request. Assign a unique identifier to each request
    app.use(function(req, res, next) {
        myRequest.run(function() {
            myRequest.set('reqId', uuid.v1());
            next();
        });
    });
    

    2º. I wrapped winston library to print get the id of the request and add it to every log, something like this:

    var winston = require('winston');
    var getNamespace = require('continuation-local-storage').getNamespace;
    
    // Wrap Winston logger to print reqId in each log
    var formatMessage = function(message) {
        var myRequest = getNamespace('my request');
        message = myRequest && myRequest.get('reqId') ? message + " reqId: " + myRequest.get('reqId') : message;
        return message;
    };
    
    var logger = {
        log: function(level, message) {
            winstonLogger.log(level, formatMessage(message));
        },
        error: function(message) {
            winstonLogger.error(formatMessage(message));
        },
        warn: function(message) {
            winstonLogger.warn(formatMessage(message));
        },
        verbose: function(message) {
            winstonLogger.verbose(formatMessage(message));
        },
        info: function(message) {
            winstonLogger.info(formatMessage(message));
        },
        debug: function(message) {
            winstonLogger.debug(formatMessage(message));
        },
        silly: function(message) {
            winstonLogger.silly(formatMessage(message));
        }
    };
    module.exports = logger;
    

    With this 2 pieces of code you get it.

    To make it easier, I created a library that implements all this, and you can use it as winston, without being worried about all this stuff: https://github.com/davicente/express-logger-unique-req-id

    If you want to get into it a little bit more, you can take a look to this article: https://solidgeargroup.com/express-logging-global-unique-request-identificator-nodejs