【问题标题】:Winston logger custom format overwriting timestamp温斯顿记录器自定义格式覆盖时间戳
【发布时间】:2021-02-23 19:11:09
【问题描述】:

我在节点应用程序中使用 winston 记录器版本 3.3.3。我有一个用于输出的自定义格式化程序,如下所示:

const winston = require('winston');
const jsonStr = require('fast-safe-stringify');

const customFormat = winston.format.printf(data => {
    const { level, message, timestamp } = data;
    const args = data[Symbol.for('splat')];

    let strArgs = '';

    if (args) {
        strArgs = args.map(jsonStr).join(' ');
    } 

    return `${timestamp} ${level}: ${message} ${strArgs}\n`;
});

logger = winston.createLogger({
    level: 'debug',
    format: winston.format.combine(winston.format.timestamp(), customFormat),
    transports: [new winston.transports.Console()]
});

logger.log('debug', 'hi', 123, { a: 1, b: 'two' });
logger.log('debug', 'hi', { timestamp: 'this is bad' });

这让我可以用不同类型的多个参数记录事物:

logger.log('debug', 'hi', 123, { a: 1, b: 'two' });
> 2020-11-11T19:01:46.942Z debug: hi 123 {"a":1,"b":"two"}

这就是我想要的。问题是,如果我记录一个包含名为 timestamp 的字段的对象,它会覆盖格式化程序中的 timestamp 字段。

logger.log('debug', 'hi', { timestamp: 'this is bad' } );
> this is bad debug: hi {"timestamp":"this is bad"}

所以现在记录器的时间戳是字符串"this is bad",这很糟糕。如果我将data 参数输出到printf() 方法,我会看到:

{
    timestamp: 'this is bad',
    level: 'debug',
    message: 'hi',
    [Symbol(level)]: 'debug',
    [Symbol(splat)]: [ { timestamp: 'this is bad' } ] }
}

所以你可以看到timestamp 字段显然被我传入的参数覆盖了。只有当log() 方法的第三个参数是一个具有名为timestamp 的属性的对象时才会发生这种情况。所以这很好:

logger.log('debug', 'hi', 123, { timestamp: 'this is fine' } );

data: {
    level: 'debug',
    message: 'hi',
    timestamp: '2020-11-11T19:08:27.326Z',
    [Symbol(level)]: 'debug',
    [Symbol(splat)]: [ 123, { timestamp: 'this is fine' } ]
}
> 2020-11-11T19:08:27.326Z debug: hi 123 {"timestamp":"this is fine"}

这是 winston 中的错误还是我的 printf() 方法不对?

请注意,我有一个 git repo 可以重现此问题 here

【问题讨论】:

    标签: node.js logging winston


    【解决方案1】:

    一个简单的解决方案是为timeStamp.format() 中的时间戳添加格式或别名,如下所示

    logger = winston.createLogger({
        level: 'debug',
        format: winston.format.combine(
            winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // can also alias
            customFormat
        ),
        transports: [new winston.transports.Console()]
    });
    
    logger.log('debug', 'hi', { timestamp: 'this is bad' } );
    
    // outputs
    2020-11-19 20:08:36 debug: hi {"timestamp":"this is bad"}
    {
      timestamp: '2020-11-19 20:08:36',
      level: 'debug',
      message: 'hi',
      [Symbol(level)]: 'debug',
      [Symbol(splat)]: [ { timestamp: 'this is bad' } ]
    }
    

    进入解释部分,我实际上不确定为什么 timeStamp 会被覆盖,这很奇怪。

    【讨论】:

    【解决方案2】:

    嘿)我试图重现你的情况,但我无法重现。试试这个代码

    const winston = require('winston');
    
    const customFormat = winston.format.printf((data) => {
      const { level, message, timestamp } = data;
      console.log('data', data);
      const args = data[Symbol.for('splat')];
    
      let strArgs = '';
    
      if (args) {
        console.log('args', args);
        strArgs = args.map((argument) => JSON.stringify(argument)).join(' ');
      }
    
      return `${timestamp} ${level}: ${message} ${strArgs}\n`;
    });
    
    const logger = winston.createLogger({
      format: customFormat,
      transports: [
        new winston.transports.Console({
          level: 'debug',
        }),
      ],
    });
    
    logger.log('debug', 'hi', 123, { a: 1, b: 'two' });
    // logger.log('debug', 'hi', { timestamp: 'this is bad' });
    

    我检查过,在第一种情况下时间戳是未定义的。在第二种情况下,我得到了时间戳:'这很糟糕'。温斯顿没有将他自己的时间戳传递给我的日志信息。

    【讨论】:

    • 那是因为您的format: 属性未指定使用包含时间戳。试试这个(抱歉格式化):const logger = winston.createLogger({ format: winston.format.combine(winston.format.timestamp(), customFormat), transports: [ new winston.transports.Console({ level: 'debug' })]});
    • 我继续在github.com/dland512/winston-formatting-issue提供了一个更完整的代码示例和一个git repo
    猜你喜欢
    • 2012-12-08
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-19
    • 2017-03-23
    • 2018-11-19
    • 1970-01-01
    相关资源
    最近更新 更多