Winston用Mongoose Docslogging
我最近刚刚切换到Winston进行日志logging,并注意到一个问题,当执行后loggingmongoose文档。
例:
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日志logging打印相同的方式,你从console.log? 我猜它必须如何被序列化之前通过调用toJSON()logging。
我每次都必须手动调用.toJSON(),还是让别人做了其他的事情来自动完成这个工作?
警告
我认为winston的预期用途是首先将string消息logging下来(如果需要的话)以及其他元信息。 而且,我不明白为什么你想logging从mongo返回的整个集合,而不是说 – 只是_id
s(假设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); ... }
基本上,typesobject
单个参数被解释为元。 控制台传输层(默认)主要是在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方法迭代(recursion)在对象的所有键上以形成最终的string(而不是调用.toString
或类似的)。
build议的解决scheme
这两个解决scheme都强制winston将单个对象参数解释为不作为元,而是作为消息string。
如果您要支持不同的传输层,则必须修改它们。
更改Winston源代码
只需分叉回购,并对源代码进行相关更改即可。 有很多方法来完成它。 一个丑陋可能是:
meta = args.length === 1 ? {} : (typeof args[args.length - 1] === 'object' ? args.pop() : {}),
但是如果对象是mangoose模型,那么在.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]
是要logging的实际对象。
我已经在前面的答案中结合了这些想法,提供了一个相当健壮的方法来注销元对象,我已经在生产中运行了好几个月,没有任何问题。
总的想法是覆盖transport.log
并将元对象转换为JSONstring,然后再返回。 这确保了元对象被保存为一个对象,因此可以利用诸如prettyPrint
等元对象的winston优点。
以下是创build新logging器的代码,带有一个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] });
您现在可以像这样使用logging器:
logger.debug('My Mongoose document:', doc);
这将输出如下所示:
debug: My Mongoose document: {"_id":"56f0598b130b3cfb16d76b3d","name":"Bob"}
简单的解决scheme是将Mongoose模型对象转换为JSONstring,并将其传递给winston函数。 对于数组,您可能必须在循环中调用函数。
winston.info(JSON.stringify(doc));