18

Is there a possibility to save the current module name in order to be printed automatically in winston log entries when they are called later?

Currently, when I want to print the module name in logs, I have to add it manually:

var logHeader = 'mymodule'

log.info(logHeader + 'Hello')

For example, with debug, you can do (ignore the log format feature %s for now):

var debug = require('debug')('http')
  , name = 'My App'

debug('booting %s', name);

This will prin http prefix before the log:

http booting My App

Can this be done in winston? I have searched in the documentation but I couldn't find anything relevant.

Alexandru Irimiea
  • 2,513
  • 4
  • 26
  • 46

4 Answers4

29

I found a better way to do this.

I added an additional layer over the winston logger, in this case a function, that keeps the module name for each module that needs the logger. So when a module requires my new logger, it actually calls the exported function with the module name, in this case __filename.

log.js

var winston = require('winston')

var winstonLogger = new (winston.Logger)({
    transports: [
        new (winston.transports.File) ({
            filename: 'MyLogs.txt',
            handleExceptions: true,
            humanReadableUnhandledException: true,
            level: 'info',
            timestamp: true,
            json: false
        }),
        new (winston.transports.Console) ({
            level: 'info',
            prettyPrint: true,
            colorize: true,
            timestamp: true
        })
    ]
})

module.exports = function(fileName) {    
    var myLogger = {
        error: function(text) {
            winstonLogger.error(fileName + ': ' + text)
        },
        info: function(text) {
            winstonLogger.info(fileName + ': ' + text)
        }
    }

    return myLogger
}

module1.js

var log = require('log')(__filename)

log.info('Info log example')

info: C:\Users\user1\project\module1.js: Info log example

module2.js

var log = require('log')(__filename)

log.error('Error log example')

error: C:\Users\user1\project\module2.js: Error log example

Also, this way, I didn't need to change anywhere the way I submit a text log; log.info('text') stays exactly like before.

Alexandru Irimiea
  • 2,513
  • 4
  • 26
  • 46
  • 1
    Thank you. I thought about this solution and tried to find if anyone else did it and your solution is much better than what was in my mind. – refaelio Apr 02 '18 at 09:16
  • this works fine until you need to log objects, then the output is something like `path-to-file: [Object object]` – Purefan Apr 15 '23 at 23:15
28

This is what Child Loggers are for. They might not have been available when this question was asked, but for future reference, you can create your main logger instance and then export a function that creates a child logger with some default options.

// logging.js
const winston = require('winston') 

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      format: winston.format.printf(options => {
        // you can pass any custom variable in options by calling
        // logger.log({level: 'debug', message: 'hi', moduleName: 'my_module' })
        return `[${options.moduleName}] ${options.level}: ${options.message}$`;
      })
    })
  ]
});

module.exports = function(name) {
  // set the default moduleName of the child
  return logger.child({moduleName: name});
}

Then at the top of each module, import the child using:

// my_module.js
const logger = require('./logging.js')('my_module_name');

logger.error('computer says no');
// output:
// [my_module_name] error: computer says no
Papooch
  • 1,372
  • 11
  • 17
  • 1
    You can also export additional loggers and simply import then individually. `export const databaseLogger = logger.child({ label: 'database' });` – Matthew Nov 14 '21 at 17:42
  • This is great, and I'm gonna start using it, but it doesn't handle well with exceptionHandlers configuration - https://github.com/winstonjs/winston/issues/1693 , that's a shame, cause it means that if a dev forgets to try catch and the code throws, the logs won't be consistent – Alonzzo2 Jun 09 '22 at 11:21
  • actually I can change the format of the exception log but it seems there's no options.moduleName (what we overrode) in the case of an exception, so I made some changes: module.exports = moduleName => { this.moduleName = moduleName; return logger; }; and the format now uses this.moduleName instead of options.moduleName – Alonzzo2 Jun 09 '22 at 11:36
3

You can specify a custom log format with Winston -

var moduleName = 'myModule';

var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({
      formatter: function(options) {
        // Return string will be passed to logger. 
        return moduleName + ' - ' + (options.message ? options.message : '')
      }
    })
  ]
});


logger.info('This is a log message');

This will print -

myModule - This is a log message

So your module name will be appended to every log messsage.

Jyotman Singh
  • 10,792
  • 8
  • 39
  • 55
1

With winston v3.3.3 you can do this by using winston.format.label and a customization of winston.format.printf:

const winston = require('winston');

const logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.label({label: 'mymodule'}),
    winston.format.printf(({label, message}) => {
      return `${label}: ${message}`;
    })
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.info('Hello, World!'); // prints "mymodule: Hello, World!"
Benny Code
  • 51,456
  • 28
  • 233
  • 198