Search code examples
node.jswinston

Node Winston instantiate each instance with a name


This is my winston logger class:

const winston = require('winston');
const config = require('../config');
const env = process.env;

winston.setLevels({
    debug:0,
    info: 1,
    silly:2,
    warn: 3,
    error:4,
});

winston.addColors({
    debug: 'green',
    info:  'cyan',
    silly: 'magenta',
    warn:  'yellow',
    error: 'red'
});

let transports = [];
transports.push(new (winston.transports.File)({filename: config.logger.fileName}));
if (env.CONSOLE == 'true' || config.logger.consoleLog) {
    transports.push(new (winston.transports.Console)({colorize:true}));
}

winston.configure({
    transports: transports
});

if (config.logger.debug || env.DEBUG == 'true') {
    winston.level = 'debug';
}


module.exports = winston;

I use this like so:

const logger = require('src/logger');
logger.info("Hello there");

The problem is all files would then append to the same file without any distinction; I want to be able to set the "name" so that in my log, I see something like "[Name1] ..." "[Name2] ..." etc.

How do I accomplish this?


Solution

  • Winston has a concept of 'categories'. But there is no easy way to put the category name into a log message.

    Here is a workaround that leverages 'label' property to achieve this:

    'use strict';
    
    const winston = require('winston');
    
    winston.setLevels({
    	debug: 0,
    	info: 1,
    	silly: 2,
    	warn: 3,
    	error: 4,
    });
    
    winston.addColors({
    	debug: 'green',
    	info: 'cyan',
    	silly: 'magenta',
    	warn: 'yellow',
    	error: 'red'
    });
    
    const getLogger = function (category) {
    	//If we call .get it'll create a default logger
    	//We don't need a default one, we want to configure the
    	//transports/labels, so we check if it exists
    	//and return only if it's configured properly
    	if (winston.loggers[category]) {
    		return winston.loggers.get(category);
    	}
    
    	//Apply your logic to identify log level here.
    	let level = 'silly';
    
    	//Set up the transports you need (omit console if needed)
    	let transports = [
    		new (winston.transports.File)({
    			filename: './logs.txt',
    			//Notice this 'label' property
    			label: category,
    			level
    		}),
    		new (winston.transports.Console)({
    			colorize: true,
    			label: category,
    			level
    		})
    	];
    
    	return winston.loggers.add(category, {transports});
    };
    
    module.exports = {getLogger};
    
    const generalLogger = getLogger('general');
    const appleLogger = getLogger('apple');
    const orangeLogger = getLogger('orange');
    
    generalLogger.log('info', 'general logger');
    appleLogger.log('info', 'apple logger');
    orangeLogger.log('info', 'orange logger');

    So you export getLogger instead of just winston and then you'll get log messages like these:

    info: [general] general logger
    info: [apple] apple logger
    info: [orange] orange logger
    

    {"level":"info","message":"general logger","label":"general","timestamp":"2017-03-06T07:08:04.959Z"}
    {"level":"info","message":"apple logger","label":"apple","timestamp":"2017-03-06T07:08:04.962Z"}
    {"level":"info","message":"orange logger","label":"orange","timestamp":"2017-03-06T07:08:04.963Z"}

    Hope this helps. Also here's a similar thread.