【问题标题】:Winston Logging with Mongoose DocsWinston 使用 Mongoose Docs 进行日志记录
【发布时间】:2014-11-04 17:44:54
【问题描述】:

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

例子:

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
});

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

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

【问题讨论】:

  • 我也遇到了同样的问题,还没有找到解决办法。你最后解决了吗?
  • 不幸的是,没有,但是,我将尝试以下一些建议的答案。我猜winston 从来没有打算用于漂亮的对象记录。

标签: node.js mongoose winston


【解决方案1】:

我结合了之前答案中的想法,提供了一种相当强大的方法来注销元对象,我已经在生产环境中运行了好几个月,没有任何问题。

一般的想法是覆盖transport.log并将元对象转换为JSON字符串,然后再返回。这确保了元对象作为对象保留,因此可以利用元对象的 winston 优势,例如 prettyPrint

下面是创建新记录器的代码,带有 prettyPrint 选项:

var transport = new (winston.transports.Console)({
  prettyPrint: function(meta) {
    return util.format('%j', meta);
  }
});

var originalLog = transport.log;
transport.log = function(level, msg, meta, callback) {
  if(meta) {
    if(meta instanceof Error) {
      // Errors cannot be stringified.
      meta = meta.toString();

    } else {
      // Keep meta as an object so that winston formats it
      // nicely, but ensure we don't have any weird ObjectIds
      meta = JSON.parse(JSON.stringify(meta));
    }
  }
  return originalLog.call(transport, level, msg, meta, callback);
};

var logger = new (winston.Logger)({
  transports: [transport]
});

您现在可以像这样使用记录器:

logger.debug('My Mongoose document:', doc);

这将输出如下内容:

debug: My Mongoose document: {"_id":"56f0598b130b3cfb16d76b3d","name":"Bob"}

【讨论】:

    【解决方案2】:

    简单的解决方案是将 Mongoose 模型对象转换为 JSON 字符串并将其传递给 winston 函数。对于 Array 你可能需要在循环中调用函数。

    winston.info(JSON.stringify(doc));
    

    【讨论】:

      【解决方案3】:

      警告

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

      简介

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

      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);
      
        ...
      
      }
      

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

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

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

      建议的解决方案

      两种解决方案都强制 winston 将单个对象参数解释为不是元数据,而是作为消息字符串。

      如果您想支持不同的传输层,则必须对其进行修改。

      更改winston源代码

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

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

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

       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 += '}';
          }
      

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

      覆盖winston默认行为

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

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

      【讨论】:

      • 我会尝试这种方法。关键是,一般来说,它不会像 console.log 那样记录对象 此外,在某些情况下,即使只是出于调试目的,我也想输出从我的 docs 集合中打印出单个对象,我有现在求助于 console.log。
      • 感谢您的详细回答。我希望winston 可以作为console.log 工作。
      • @Jehof 很高兴它有帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      • 1970-01-01
      • 2018-06-21
      • 2019-09-29
      • 2015-04-15
      • 2018-12-09
      相关资源
      最近更新 更多