Winston使用Mongoose Docs进行日志记录

iQ.*_*iQ. 8 mongoose node.js winston

我最近刚切换到Winston进行日志记录,并注意到在exec之后记录mongoose docs时出现问题.

例:

Model.find().exec(function (err, docs) {
    console.log(docs) // Prints the collection fine
    winston.info(docs) // Prints a ton on mongoose stuff, related to the query
});
Run Code Online (Sandbox Code Playgroud)

那么基本上我如何让winston日志记录以与从console.log获得的方式相同的方式进行打印?我猜它在通过调用toJSON()进行记录之前必须如何被序列化.

我是否每次都必须手动调用.toJSON()或让人们做其他事情才能自动完成这项工作?

art*_*iak 4

警告

我认为温斯顿的预期用途是首先记录字符串消息和(如果需要)附加元信息。此外,我不太明白为什么你想记录从 mongo 返回的整个集合,而不是 - 比方说 - 只是_ids (假设docs可能很大)。

介绍

我查看了winston来源,以下是相关部分:

温斯顿/logger.js

Logger.prototype.log = function (level) {
  var self = this,
      args = Array.prototype.slice.call(arguments, 1);

  ...

  var callback = typeof args[args.length - 1] === 'function' ? args.pop() : null,
      meta     = typeof args[args.length - 1] === 'object' ? args.pop() : {},
      msg      = util.format.apply(null, args);

  ...

}
Run Code Online (Sandbox Code Playgroud)

基本上,类型的单个参数object被解释为元。控制台传输层(默认)主要在Winston/common.js中定义,以下是元的处理方式:

 ... if (Object.keys(meta).length > 0) {
      output += ' ' + (
        options.prettyPrint
          ? ('\n' + util.inspect(meta, false, null, options.colorize))
          : exports.serialize(meta)
      );
    }
Run Code Online (Sandbox Code Playgroud)

Serialize方法迭代(递归地)对象的所有键以形成最终字符串(而不是调用.toString或类似)。

建议的解决方案

这两种解决方案都迫使温斯顿将单个对象参数解释为消息字符串,而不是元数据。

如果您想支持不同的传输层,则必须修改它们。

更改winston源代码

只需分叉存储库并对源代码进行相关更改即可。有很多方法可以实现它。一种丑陋可能是:

 meta     = args.length === 1 ? {} :
          (typeof args[args.length - 1] === 'object' ? args.pop() : {}),
Run Code Online (Sandbox Code Playgroud)

但更好的是在方法中添加特殊情况,.serialize如果对象是 mangoose 模型,则进行特殊处理,非常幼稚且不正确:

 else if ('_doc' in obj && 'save' in obj){
        var result = [];
        msg += '{'
        for(var key in obj['_doc']){
            result.push (key + ':' + obj['_doc'][key]);
        }
        msg += result.join(', ');
        msg += '}';
    }
Run Code Online (Sandbox Code Playgroud)

(不幸的是,这种方法存在一个问题,因为温斯顿复制了元数据,并且原型链中更高层定义的所有方法都丢失了——否则它就像调用一样简单,obj.toJSON并且肯定会是最优雅和最强大的解决方案)

覆盖温斯顿默认行为

var original = winston.log;
winston.log = function(){
    if(arguments.length === 2){
        original.call(winston, arguments[0], arguments[1], {});
    }
    else {
        original.apply(winston, arguments);
    }
}
Run Code Online (Sandbox Code Playgroud)

说明:arguments[0]定义级别,也是arguments[1]要记录的实际对象。