使用 winston 记录 moment.js

Logging moment.js with winston

我想在我的 Node.js 应用程序中记录一些包含 moment.js 个对象的对象。

var moment = require('moment');
var myObject = {
    anything: 'This is metadata',
    moment: moment()
}

当我使用 console.log(myObject) 将此对象记录到我的控制台时,我得到以下输出:

{ anything: 'This is metadata',
  moment: moment("2017-03-02T09:35:04.612") }

请注意 moment.js 对象如何打印为紧凑且可读的字符串。

现在,当我使用 winston 使用此对象记录事件时……

var winston = require('winston');
winston.configure({
    transports: [
        new (winston.transports.Console)({ prettyPrint: true })
    ]
});
winston.info('Test Log Message', myObject);

…它在我的控制台中转储了一个巨大的对象:

info: Test Log Message 
{ anything: 'This is metadata',
  moment: 
   { _isAMomentObject: true,
     _isUTC: false,
     _pf: 
      { empty: false,
        unusedTokens: [],
        unusedInput: [],
        overflow: -2,
        charsLeftOver: 0,
        nullInput: false,
        invalidMonth: null,
        invalidFormat: false,
        userInvalidated: false,
        iso: false,
        parsedDateParts: [],
        meridiem: null },
     _locale: 
      { _calendar: 
         { sameDay: '[Today at] LT',
           nextDay: '[Tomorrow at] LT',
           nextWeek: 'dddd [at] LT',
           lastDay: '[Yesterday at] LT',
           lastWeek: '[Last] dddd [at] LT',
           sameElse: 'L' },
        _longDateFormat: 
         { LTS: 'h:mm:ss A',
           LT: 'h:mm A',
           L: 'MM/DD/YYYY',
           LL: 'MMMM D, YYYY',
           LLL: 'MMMM D, YYYY h:mm A',
           LLLL: 'dddd, MMMM D, YYYY h:mm A' },

        etc, etc, etc…

这不是我希望在我的日志中看到的内容。我更喜欢 console.log(myObject).

生成的紧凑字符串

请注意我是如何将 prettyPrint 设置为 true 的。根据 winston 的文档,这意味着元数据(我的对象)将使用 util.inspect

打印

prettyPrint: Boolean flag indicating if we should util.inspect the meta (default false).

所以我自然而然地尝试了以下方法:

console.log(require('util').inspect(myObject));

令我惊讶的是,这会输出与 console.log(myObject) 完全相同的字符串。这是否意味着温斯顿没有像我那样使用 util.inspect ?还有什么我想念的吗?

更新

与winston的common.js文件中的this line有关。当我执行以下代码片段时,这会导致我的控制台中出现一个大对象。

var meta = require('cycle').decycle(myObject);
console.log(meta);

您可以添加一个rewriter:

winston.configure({
  transports: [
    new (winston.transports.Console)({ prettyPrint: true })
  ],
  rewriters: [
    (level, msg, meta) => {
      if (moment.isMoment(meta.moment)) {
        meta.moment = meta.moment.toString();
      }
      return meta;
    }
  ]
});

这不是很通用,因为它只适用于名为 moment 的 属性,但很容易使其通用。此外,您可以将 Moment 实例格式化为您喜欢的任何格式,该示例仅调用 toString.

在我摆弄的同时,我找到了完美的解决方案:

var winston = require('winston');
winston.configure({
    rewriters: [
        function (level, msg, meta) {
            return winston.clone(meta);
        }
    ],
    transports: [ new (winston.transports.Console)({
        level: 'debug',
        colorize: true,
        prettyPrint: true
    }) ],
});

通过 copying/cloning 原始元对象并返回它,输出正是我想要的样子,并且像着色这样的传输选项得到了尊重。

结果:

info: Test Log Message  
{ anything: 'This is metadata',
  moment: moment("2017-03-04T19:02:25.578") }

我很惭愧管理员我偶然发现了这个解决方案。我发现我的重写器正在修改我试图记录的实际对象,而没有先复制它。所以我添加了一行来克隆我的元对象,发现不再需要扫描我的对象并自己修改内容了。

如果有人能阐明这一点并且能够解释为什么这个解决方案确实有效,我将不胜感激。