如何像 console.log 那样在 winston 中记录 JavaScript 对象和数组?

How to log JavaScript objects and arrays in winston as console.log does?

我在查看顶级 Node 日志记录系统:npmloglog4jsbunyanwinston 并决定使用 winston npm 每月下载。

我想设置的是自定义记录器,我可以在开发环境中使用它 logger.debug(...),它不会在生产环境中记录任何内容。这对我很有帮助,所以当我在开发环境中时,我不需要写任何东西,因为我会看到所有的输出。

这是我现在拥有的:

var level = 'debug';
if (process.env.NODE_ENV !== 'development'){
  level = 'production'; // this will never be logged!
}

var logger = new winston.Logger({
  transports: [
    // some other loggings
    new winston.transports.Console({
      name: 'debug-console',
      level: level,
      prettyPrint: true,
      handleExceptions: true,
      json: false,
      colorize: true
    })

  ],
  exitOnError: false // don't crush no error
});

当我尝试记录 JavaScript Object 或 Javascript Array 时出现问题。对于 Object,我需要做 toJSON(),对于 Array,我需要先 JSON.stringify(),然后 JSON.parse()

一直写这个方法并不好,只是为了记录我想要的东西。此外,它甚至不是资源友好的,因为这些格式化方法需要在 logger.debug() 意识到它正在生产之前执行,并且它不应该首先记录它(基本上,它在函数调用之前评估参数) .我只是喜欢老式的 console.log() 记录 JavaScript 对象和数组。

现在,当我写这个问题时,我发现有一种方法可以描述每个 winston transports 对象的 custom format。是这样做的方式,还是有其他方式?

我的建议是在 winston 之上编写你自己的抽象,它有一个方便的方法来打印你的对象以进行调试。

您也可以查看此回复以了解如何开发该方法的提示。

尝试将 prettyPrint 参数更改为

prettyPrint: function ( object ){
    return JSON.stringify(object);
}

使用内置的 Node.js 函数 util.format 以与 console.log 相同的方式将您的对象转换为字符串。

logger.log("info", "Starting up with config %j", config);

Winstons 使用内置的 utils.format 库。 https://nodejs.org/dist/latest/docs/api/util.html#util_util_format_format_args

正如 Leo 在他的 , Winston makes use of String Interpolation provided by util.format 中指出的那样:

const winston = require("winston");                                                                                                                                                                                                    
const logger = new winston.Logger({                                                                                                                                                                                                    
  transports: [                                                                                                                                                                                                                        
    // some other loggings                                                                                                                                                                                                             
    new winston.transports.Console({                                                                                                                                                                                                   
      name: "debug-console",                                                                                                                                                                                                           
      level: process.env.LOGLEVEL || "info",                                                                                                                                                                                           
      prettyPrint: true,                                                                                                                                                                                                               
      handleExceptions: true,                                                                                                                                                                                                          
      json: false,                                                                                                                                                                                                                     
      colorize: true                                                                                                                                                                                                                   
    })                                                                                                                                                                                                                                 
  ],                                                                                                                                                                                                                                   
  exitOnError: false // don't crush no error                                                                                                                                                                                           
});                                                                                                                                                                                                                                    

const nestedObj = {                                                                                                                                                                                                                    
  foo: {                                                                                                                                                                                                                               
    bar: {                                                                                                                                                                                                                             
      baz: "example"                                                                                                                                                                                                                   
    }                                                                                                                                                                                                                                  
  }                                                                                                                                                                                                                                    
};                                                                                                                                                                                                                                     

const myString = "foo";                                                                                                                                                                                                                

logger.log("info", "my nested object: %j. My string: %s", nestedObj, myString);                                                                                                                                                                                                                                  

调用logger.log时,您可以定义将被适当替换的占位符。 %j 将替换为 JSON.stringify(nestedObj)

的等价物

Winston > 3 你可以使用

logger.log('%o', { lol: 123 }')

总之... 无法接受我必须始终使用 %o 并制定了这个简单的解决方案:

const prettyJson = format.printf(info => {
  if (info.message.constructor === Object) {
    info.message = JSON.stringify(info.message, null, 4)
  }
  return `${info.level}: ${info.message}`
})

const logger = createLogger({
  level: 'info',
  format: format.combine(
    format.colorize(),
    format.prettyPrint(),
    format.splat(),
    format.simple(),
    prettyJson,
  ),
  transports: [
    new transports.Console({})
  ],
})

所以这个记录器....

  logger.info({ hi: 123 })

...在控制台中转换成这个

info: {
    "hi": 123
}

而不是做

prettyPrint: function ( object ){
    return JSON.stringify(object)
}

最好搭配utils-deep-clone套餐

// initialize package on the top
const { toJSON } = require('utils-deep-clone')


// and now in your `prettyPrint` parameter do this
prettyPrint: function ( object ){
    return toJSON(object)
}

如果你选择JSON.stringify,你将无法打印错误

console.log(JSON.stringify(new Error('some error')))
// output will '{}'

尝试对对象使用 util.inspect。它也能正确处理循环引用。 @radon-rosborough 已经给出了这个答案,但我想添加一个例子。请看下面

const customTransports = [
    new winston.transports.Console({
        format: combine(
            timestamp({
                format: 'DD-MMM-YYYY HH:MM:SS'
            }),
            label({
                label: file
            }),
            prettyPrint(),
            format.splat(),
            simple(),
            printf( (msg)=> {
                let message = msg.message;

                return colorize().colorize(msg.level, `${ msg.level } :  ${msg.timestamp} :  ${ msg.label } : \n`) + `${ util.inspect(message,{
                    depth: 2,
                    compact:true,
                    colors: true,
                } )}`;
            })
        )
    })
]