Skip to content

_writev doesn't wait for chunk log callbacks before calling its own callback #49

@laganojunior

Description

@laganojunior

Function in question:

winston-transport/index.js

Lines 117 to 166 in 46db8f3

TransportStream.prototype._writev = function _writev(chunks, callback) {
if (this.logv) {
const infos = chunks.filter(this._accept, this);
if (!infos.length) {
return callback(null);
}
// Remark (indexzero): from a performance perspective if Transport
// implementers do choose to implement logv should we make it their
// responsibility to invoke their format?
return this.logv(infos, callback);
}
for (let i = 0; i < chunks.length; i++) {
if (!this._accept(chunks[i])) continue;
if (chunks[i].chunk && !this.format) {
this.log(chunks[i].chunk, chunks[i].callback);
continue;
}
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(
Object.assign({}, chunks[i].chunk),
this.format.options
);
} catch (err) {
errState = err;
}
if (errState || !transformed) {
// eslint-disable-next-line callback-return
chunks[i].callback();
if (errState) {
// eslint-disable-next-line callback-return
callback(null);
throw errState;
}
} else {
this.log(transformed, chunks[i].callback);
}
}
return callback(null);
};

This implementation of _writev calls callback before all the callbacks of this.log(chunks[i]...) are called. This means that the transport stream may seem finished even if the underlying implementation hasn't finished writing out all the chunks yet.

We ran into this when we saw that during tests that when we close a winston logger, we would sometimes see a finish event be emitted from the logger before our transport finished writing its files.

We're currently working around this by implementing our own logv for our transport since that gives us control over calling the callback to _writev only when each chunk is finished.

I'm happy to try to construct a minimal example and/or provide a merge request to fix this. I just want to check here if this is something that's done by design or otherwise known.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions