Winston logging object

前端 未结 5 1954
轻奢々
轻奢々 2021-02-13 12:23

I use Winston for my backend logging I cannot log the object without using JSON.stringify which is annoying

logger.debug(`Register ${JSON.stringify(         


        
相关标签:
5条回答
  • 2021-02-13 12:57

    I had to combine the solution provided by @SherloxFR and @Anton.

    const Winston = require('winston');
    const { format } = Winston;
    
    const options = {
        file: {
            ....
            format: format.combine(
                format.splat(), 
                format.json()
            ),
            ...
        },
        console: {
            ...
            format: format.combine(
                format.splat(),
                format.json()
            ),
            ...
        }
    };
    

    You can see that I added both format.splat() and format.json() to the options config in the above code.

    const logger = new Winston.createLogger({
        transports: [
            new Winston.transports.File(options.file),
            new Winston.transports.Console(options.console)
        ],
        exitOnError: false // do not exit on handled exceptions
    });
    

    That is how I used the options config object. You can actually write the format code inside the transports array but I don't like it that way. It's your choice anyway.

    After the configuration like that, the is how I used it in my code

    let myObj = {
       name: "StackOverflow",
    };
    
    logger.info('Content: %o', myObj);
    

    You can also spread it like this if you want

    logger.info('Content: %o', {...myObj});
    

    That's all. Winston should log your object with this set up.

    0 讨论(0)
  • 2021-02-13 13:01

    You are trying to insert a JSON object directly into the string, so it will print [Object Object] without the JSON.stringify.

    This is not fixable by configuring Winston, as this problem happens while the string is generated (before the logger.debug function actually reads it), so a console.log call would print the same thing.

    The first parameter of the logger.* functions is the message (string), then you can pass a metadata object (JSON).

    To use the metadata in your logFormat function, update your Logger instantiation as follow:

    const winston = require('winston')
    const { format, transports } = winston
    const path = require('path')
    
    const logFormat = format.printf(info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`)
    
    const logger = winston.createLogger({
      level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
      format: format.combine(
        format.label({ label: path.basename(process.mainModule.filename) }),
        format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
        // Format the metadata object
        format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] })
      ),
      transports: [
        new transports.Console({
          format: format.combine(
            format.colorize(),
            logFormat
          )
        }),
        new transports.File({
          filename: 'logs/combined.log',
          format: format.combine(
            // Render in one line in your log file.
            // If you use prettyPrint() here it will be really
            // difficult to exploit your logs files afterwards.
            format.json()
          )
        })
      ],
      exitOnError: false
    })
    

    Usage:

    const req = {
      body: {
        name: 'Daniel Duuch',
        email: 'daniel.duuch@greatmail.com',
        password: 'myGreatPassword'
      }
    }
    
    logger.debug(`Register ${req.body.name} with email ${req.body.email}`, { ...req.body, action: 'register' })
    

    Console output:

    2019-05-11 17:05:45 debug [index.js]: Register Daniel Duuch with email daniel.duuch@greatmail.com
    

    Logfile output (prettified by hand, see comment in the transport file format):

    {
      message: 'Register Daniel Duuch with email daniel.duuch@greatmail.com',
      level: 'debug',
      timestamp: '2019-05-11 17:05:45',
      label: 'index.js',
      metadata: {
        name: 'Daniel Duuch',
        email: 'daniel.duuch@greatmail.com',
        password: 'myGreatPassword'
      }
    }
    

    Hope this solves your issue.

    Code for this answer

    0 讨论(0)
  • 2021-02-13 13:01

    You can use format.splat() in your logger config:

    const logger = createLogger({
        format: combine(
            ...
            format.splat(), // <--
            ...
        ),
        ...
    });
    

    ...and log object using string interpolation:

    let myObj = { /* ... */ };
    logger.info('This message will include a complete object: %O', myObj);
    
    0 讨论(0)
  • 2021-02-13 13:03

    Or you just use the

    printf

    function in conjunction with JSON.stringify

    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple(),
        winston.format.printf(context => {
          const msgstr = JSON.stringify(context.message, null, '\t')
          return `[${context.level}]${msgstr}`
        }),
      ),
    })
    
    0 讨论(0)
  • 2021-02-13 13:10

    My solution was to use this kind of formatter:

    const { format } = winston
    const consoleFormat = format.combine(
      format.prettyPrint(),
      format.splat(),
      format.printf((info) => {
        if (typeof info.message === 'object') {
          info.message = JSON.stringify(info.message, null, 3)
        }
    
        return info.message
      })
    )
    

    now all those options works as expected:

    logger.info('plain text')
    logger.info('plain text with object %o', { a:1, b: 2} )
    logger.info({ a:1, b: 2 })
    
    0 讨论(0)
提交回复
热议问题