Winston: Error objects inside object or array are discarded during logging

Created on 18 May 2016  路  6Comments  路  Source: winstonjs/winston

e.g.
not working

   // err object was created by new Error('failed')
   winston.error('An error happened:', { error: err, bar:  "foo" });
   // => An error happened: { error: {}, bar: "foo" }
   winston.error('An error happened:', { errors: [err, err, err] });
   // => An error happened: { errors: [{},{},{}] }

works well, if top level is Error itself

winston.error('An error happened:', err);

Most helpful comment

I was facing the same issue so i wrote this package, utils-deep-clone. Check it out.

P.S. I didn't do it in winston itself because i saw the PR's section and i guess it's a dead project.

All 6 comments

Shouldnt the correct syntax be
'''
// err object was created by new Error('failed')
winston.error('An error happened: %j', { error: err, bar: "foo" });
// => An error happened: { error: {}, bar: "foo" }
winston.error('An error happened: %j', { errors: [err, err, err] });
// => An error happened: { errors: [{},{},{}] }
'''
Not sure about winstons implementation but doing console.log("",var) is different from console.log("%s/j",var); I think in the previous case console logger just concatenates the two objects while the the latter it actually typecasts the variable and interpolates it with its corresponding placeholder.

https://github.com/winstonjs/winston#string-interpolation
Has a more precise description

I got the same issue - it seems to be caused by the naive cloning done in the cycle library's decycle function (https://github.com/dscape/cycle/blob/ab67ce90e8fa2efdb8f21074661366ec56f6a724/cycle.js#L91) - Error properties are non-enumerable and so nothing gets copied into the "clone" (it returns {}).

This is called from within winston to process the metadata on each log call here - https://github.com/winstonjs/winston/blob/de69bccf957cca2247ef529c2b66c88059adbae6/lib/winston/common.js#L142 .

It would seem like an upstream PR to cycle would be the correct fix, either to iterate non-enumerable properties or perform some other more robust form of cloning. If you just wanted to fix it for your usage, a rewriter can do the job - you have to essentially 'pre-clone' the error objects before they get passed to cycle.

Here's a crude rewriter using lodash 3.x's merge (mergeWith in 4.x) with a customiser which addresses the issue:

rewriters.push(function(level, msg, meta) {
    return _.merge({}, meta, function errorCloner(objValue, srcValue) {
        if(srcValue instanceof Error) {
            var clone = {};

            // Make sure we clone both enumerable and non-enumerable properties on errors
            Object.getOwnPropertyNames(srcValue).forEach(function(prop) {
                var value = srcValue[prop];

                clone[prop] = value && typeof value === 'object' ?
                   // Recurse for objects, to handle inner exceptions
                    _.mergeWith({}, value, errorCloner) :
                    value;
            });

            return clone;
        }
    });
});

Hopefully that might be of some use to anyone else who gets the same problem.

This is effectively the same bug from https://github.com/winstonjs/winston/issues/280 (cycle cloning an error object to be empty because error properties are non-enumerable). That took a year to fix. We're just 15 months from this original report to today. Or you could say it's been 4 years and the original bug has only been partially fixed.

I was facing the same issue so i wrote this package, utils-deep-clone. Check it out.

P.S. I didn't do it in winston itself because i saw the PR's section and i guess it's a dead project.

I was facing the same issue so i wrote this package, utils-deep-clone. Check it out.

P.S. I didn't do it in winston itself because i saw the PR's section and i guess it's a dead project.

sounds good, Thanks Atishay!

Was this page helpful?
0 / 5 - 0 ratings