question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

multiple transports loosing SPLAT/meta

See original GitHub issue

Please tell us about your environment:

  • winston version?
    • winston@2
    • winston@3
  • _node -v outputs: v8.11.3
  • _Operating System? Windows
  • _Language? Typescript

What is the problem?

Adding multiple transports to a logger causes the info-object to loose meta field on all but one transport.:

const Winston = require("winston");
Winston.add(new Winston.transports.Console({
    format: Winston.format.combine(Winston.format(info => {
        info.message = info.message + "Console";
        return info;
    })(), Winston.format.splat(), Winston.format.simple(), Winston.format(info => {
        // console.log(info); // meta is there!
        return info;
    })()),
    handleExceptions: true
}));
Winston.add(new Winston.transports.File({
    filename: "test.log",
    format: Winston.format.combine(Winston.format(info => {
        // console.log(info); // meta is gone :(! and so is SPLAT only a array of length 1
        return info;
    })(), Winston.format.splat(), Winston.format.simple())
}));
for (let index = 0; index < 10; index++) {
    Winston.error("test %s" + index, "blub", "metainfo");
}

Output Console:

error: test blub0Console {"meta":"metainfo"}
error: test blub1Console {"meta":"metainfo"}
error: test blub2Console {"meta":"metainfo"}
error: test blub3Console {"meta":"metainfo"}
error: test blub4Console {"meta":"metainfo"}
error: test blub5Console {"meta":"metainfo"}
error: test blub6Console {"meta":"metainfo"}
error: test blub7Console {"meta":"metainfo"}
error: test blub8Console {"meta":"metainfo"}
error: test blub9Console {"meta":"metainfo"}

Output File:

error: test blub0
error: test blub1
error: test blub2
error: test blub3
error: test blub4
error: test blub5
error: test blub6
error: test blub7
error: test blub8
error: test blub9

Sometimes one transport gets the meta and the other doesn’t and for the next logentry its the other way around.

What do you expect to happen instead?

Each transport should get a clean “new” info object. At least with a full SPLAT. So {“meta”:“metainfo”} is included in File too.

Other information

I tried for a moment to find the issue in debugger, but got lost in the streams. So please excuse me, if this issue belongs more to winston-transports. I try to investigate this further.

It seems the info[SPLAT] is preserved from one Transport to the other, but due to the splat() formatter th metadata is removed. Maybe its more related to the splat() altering the array than i thought…

As a workaround i will push the metadata back to SPLAT after splat():

const splatWorkaround = Winston.format.combine(
  Winston.format.splat(),
  Winston.format(info => {
    if (info.meta && info.meta instanceof Array) info[SPLAT].push(...info.meta);
    else if (info.meta) info[SPLAT].push(info.meta);
    return info;
  })()
);

To get this working i will use this workaround:

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:5
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

4reactions
avalycommented, Nov 15, 2018

I was about to open a new issue regarding this exact same issue, and then I found this one. I’ll post my description as well. 😃


Please tell us about your environment:

  • winston version?
    • winston@3.1.0
  • node -v outputs: v8.12.0
  • Operating System? Linux
  • Language? ES5

What is the problem?

The custom data added by the splat formatter as the field meta in the log message is dropped when all the following conditions are met:

  • when a transport has already consumed the message (i.e. on a second transport)
  • when the first log string does not contain any tokens (i.e. %s)
  • when the custom format is applied on each transport

To replicate the bug, see the code:

https://gist.github.com/avaly/527eee1e061accb7e1f446ca105c3094#file-run-with-bug-js

Which outputs:

{"level":"info","message":"foo","meta":["bar","ham"]}
{"level":"info","message":"foo"}
{"level":"info","message":"with interpolated strings: bar and ham"}
{"level":"info","message":"with interpolated strings: bar and ham"}

What do you expect to happen instead?

Expected output:

{"level":"info","message":"foo","meta":["bar","ham"]}
{"level":"info","message":"foo","meta":["bar","ham"]}
{"level":"info","message":"with interpolated strings: bar and ham"}
{"level":"info","message":"with interpolated strings: bar and ham"}

Other information

If we move the custom format to the top level logger, then the bug does not present itself:

https://gist.github.com/avaly/527eee1e061accb7e1f446ca105c3094#file-run-without-bug-js

But, most of the time, different transports do require different formatting.

2reactions
Fantuscommented, Feb 15, 2019

i think i figured out a workaround for now. You can try adding this to your scripts to make the transport use a “deepclone” instead of making shallow clone

you can try this as a workaround for now:

const deepcopy = require('deepcopy');
const TransportStream = require('winston-transport');
const { LEVEL } = require('triple-beam');

TransportStream.prototype._write = function _write(info, enc, callback) {
    if (this.silent || (info.exception === true && !this.handleExceptions)) {
        return callback(null);
    }

    // Remark: This has to be handled in the base transport now because we
    // cannot conditionally write to our pipe targets as stream. We always
    // prefer any explicit level set on the Transport itself falling back to
    // any level set on the parent.
    const level = this.level || (this.parent && this.parent.level);

    if (!level || this.levels[level] >= this.levels[info[LEVEL]]) {
        if (info && !this.format) {
            return this.log(info, callback);
        }

        let errState;
        let transformed;

        // We trap(and re-throw) any errors generated by the user-provided format, but also
        // guarantee that the streams callback is invoked so that we can continue flowing.
        try {
            transformed = this.format.transform(deepcopy(info), this.format.options);
        } catch (err) {
            errState = err;
        }

        if (errState || !transformed) {
            // eslint-disable-next-line callback-return
            callback();
            if (errState) throw errState;
            return;
        }

        return this.log(transformed, callback);
    }

    return callback(null);
};
Read more comments on GitHub >

github_iconTop Results From Across the Web

Is is just me or is Kensa Sloshing Machine really strong?
According to https://www.splatmeta.ink/xrank Kenso Sloshing Machine is one ... It feels like this weapon is so powerful in so many aspects:
Read more >
Splat Meta
Rank, Diff, %, Prev %, Diff %. 1 Card image cap Kensa .52 Gal, 0, 6.40, 7.35, -0.95. 2 Card image cap E-liter...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found