Search code examples
node.jsfeathersjswinstonfeathers-service

Show Correlation Id Using Winston in Feathersjs


I want to logging in FeathersJS using winston. But, I want to logging with "correlation id". I want to find how I should create the logger, I want to make just log with the message, not supply with correlation id. Here is an example.

log.info('Here is a log');

// output [Info] [correlation-id] : Here is a log

I want to know, how the best approach to make my logger injected with correlation id that different each request?


Solution

  • I have a solution with my question. But I'm still not sure this will effective. I use library such as

    • cls-hooked (for scoped an request)
    • uuid (for generated an id)

    Here is my changes after I first time generate FeathersJS Project.

    In src/logger.js, I use getNamespace and also get a variable from namespace. Here is my example:

    const { createLogger, format, transports } = require('winston');
    const getNamespace = require('cls-hooked').getNamespace;
    
    const myFormat = format.printf(({level, message, timestamp}) => {
      const loggerNamespace = getNamespace('logger');
      return `[${timestamp}] [${level}] [${loggerNamespace.get('correlationId')}]: ${message}`;
    });
    
    // Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston
    const logger = createLogger({
      // To see more detailed errors, change this to 'debug'
      level: 'info',
      format: format.combine(
        format.timestamp(),
        format.splat(),
        myFormat
      ),
      transports: [
        new transports.Console()
      ],
    });
    
    module.exports = logger;
    

    After this, I finished setup my logger to get correlationId, now to make correlation each my request, I use middleware to make this happen. I will add new middleware to control correlationId in src/middleware/correlation.js. Here is my example:

    const uuidv4 = require('uuid/v4');
    
    function correlation(namespace) {
      return (req, res, next) => {
        const correlationId = uuidv4();
        req.feathers.correlationId = correlationId;
        namespace.run(() => {
          namespace.set('correlationId', correlationId);
          next();
        });
      }
    }
    
    module.exports = correlation;
    

    After I created my own middleware, I will register that into global middleware in src/middleware/index.js. Here is my changes,

    const createNameSpace = require('cls-hooked').createNamespace;
    const correlation = require('./correlation');
    const logNameSpace = createNameSpace('logger');
    
    // eslint-disable-next-line no-unused-vars
    module.exports = function (app) {
      // Add your custom middleware here. Remember that
      // in Express, the order matters.
      app.use(correlation(logNameSpace));
    };
    

    Until this changes, you already setup logger to get correlationId. For example, I created an hook and will add log there. I place that in src/hooks/logsHooks Here my example:

    // Use this hook to manipulate incoming or outgoing data.
    // For more information on hooks see: http://docs.feathersjs.com/api/hooks.html
    const logger = require('../logger');
    // eslint-disable-next-line no-unused-vars
    module.exports = function (options = {}) {
      return async context => {
        logger.info('Test my correlation Id');
        let i = 0;
        function recursive() {
          setTimeout(() => {
            logger.debug(`My Itteration ${i}, let it request finish than run this background`);
            i++;
            if (i < 50) {
              recursive();
            }
          }, 5000);
        }
        recursive();
        return context;
      };
    };
    

    When I setup that, I think that is already meet my requirement. But I still need to test this with another case. I just test with some simple case.