I'd like to log some objects in my Node.js app that contain moment.js objects.
var moment = require('moment');
var myObject = {
anything: 'This is metadata',
moment: moment()
}
When I log this object to my console using console.log(myObject)
I get the following output:
{ anything: 'This is metadata',
moment: moment("2017-03-02T09:35:04.612") }
Note how the moment.js object is printed as a compact and readable string.
Now, when I'm logging an event with this object using winston …
var winston = require('winston');
winston.configure({
transports: [
new (winston.transports.Console)({ prettyPrint: true })
]
});
winston.info('Test Log Message', myObject);
… it dumps a huge object in my console:
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…
This is not something I'd like to see in my logs. I'd prefer the compact string that was produced by console.log(myObject)
.
Note how I've set prettyPrint
to true
. According to winston's documentation this means the meta data (my object) will be printed using util.inspect
prettyPrint: Boolean flag indicating if we should util.inspect the meta (default false).
So naturally I tried the following:
console.log(require('util').inspect(myObject));
To my surprise this outputs the exact same string as console.log(myObject)
. Does this mean winston is not using util.inspect in the way I do? Is there something else I'm missing?
It has something to do with this line in winston's common.js file. When I execute the following snippet, this results in a large object in my console.
var meta = require('cycle').decycle(myObject);
console.log(meta);
While I was fiddling around I found the perfect solution:
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
}) ],
});
By copying/cloning the original meta object and returning it, the output is exactly how I'd like it to be and transport options like colorize are respected.
Result:
info: Test Log Message
{ anything: 'This is metadata',
moment: moment("2017-03-04T19:02:25.578") }
I ashamed to admin I found this solution by accident. I was found out my rewriter was modifying the actual object I was trying to log, without copying it first. So I added a line to clone my meta object and found out that there was no need to scan trough my object and modify the contents myself anymore.
If anyone can shine some light on this and is able to explain why this solution actually works, I'd greatly appreciate it.