I'm trying to log JSON data in an array returned from REST API and getting "TypeError: next is not a function" error. Data is logged in a file but getting that error message. Any suggestion is appreciated.
webService.getData({product_id: 'GOOG'}, (error, response, data) => {
if (error) {
// handle the error
} else {
data.forEach(fill => {
if (typeof fill === 'object') {
logger.info(JSON.stringify(fill));
}
})
}
})
I'm logging data returned from REST API
next();
^
TypeError: next is not a function
at WriteStream.onDrain (C:\Users\nash\wsclient\node_modules\winston\lib\winston\transports\file.js:390:3)
at emitNone (events.js:91:20)
at WriteStream.emit (events.js:185:7)
at onwriteDrain (_stream_writable.js:397:12)
at afterWrite (_stream_writable.js:385:5)
at onwrite (_stream_writable.js:378:7)
at WritableState.onwrite (_stream_writable.js:90:5)
at fs.js:2195:5
at FSReqWrap.wrapper [as oncomplete] (fs.js:2162:5)
Can you share the code your using to set up your winston loggers? And which version of winston are you using?
Using @next version. Please see below for Winston config. Thanks.
const winston = require('winston');
const { format } = require('logform');
const logFormat = format.printf(info => {
return `[${info.timestamp}] ${info.level}: ${info.message}`;
});
const logger = winston.createLogger({
level: 'info',
format: format.combine(
format.timestamp(),
logFormat
),
transports: [
new winston.transports.File({ filename: './logs/error.log', level: 'error' }),
new winston.transports.File({ filename: './logs/application.log', maxsize: 104857600 }),
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: format.combine(
format.timestamp(),
logFormat
)
}));
}
I have been able to reproduce the issue mentioned by @nengine by feeding in a very large string into the logger.info() call.
After debugging for a while I noticed a possible "this" context issue with the winston file transport.
File.prototype._onDrain = function onDrain() {
if (--this._drains) return;
var next = this._next;
this._next = noop;
next();
};
I noticed that "this._drains" was undefined and becomes NaN after doing the decrement. "this._next" is also undefined which leads to the error mentioned when executing the "next()" call.
this._dest = fs.createWriteStream(fullpath, this.options)
.on('error', function (err) {
// TODO: what should we do with errors here?
debug(err);
})
.on('drain', this._onDrain)
.on('open', function () {
debug('file open ok', fullpath);
self.emit('open');
self._stream.pipe(self._dest);
});
The code that sets up the drain event listener will cause the "this" context of the "this._onDrain" to be the newly created "fs.createWriteStream" stored in this._dest property instead of the File transport "this" context.
Changing to:
.on('drain', () => this._onDrain()) in the above code seems to solve the issue. By wrapping in an arrow function the "this" context is preserved. This implies that the "this" context is being set wrong when the "this._onDrain" function is called on a "drain" event.
So I believe this is a legitimate bug in the File transport code unless someone thinks otherwise.
Wow thanks for finding this out.
I had encountered the same problem. Thanks @mempf 's solution.
BTW I'd suggest using the fix in my pull request as opposed to the arrow function hack I mentioned above. The arrow function hack can have adverse effects on being able to remove the listener functions.
Fixed by #1104 and published as 3.0.0-rc1 install the new winston@next to get the newest version
Upgraded successfully. Thanks @jcrugzz , have a nice day 馃槂
Much appreciated both @jcrugzz @mempf . Best Wishes.
Most helpful comment
I have been able to reproduce the issue mentioned by @nengine by feeding in a very large string into the logger.info() call.
After debugging for a while I noticed a possible "this" context issue with the winston file transport.
I noticed that "this._drains" was undefined and becomes NaN after doing the decrement. "this._next" is also undefined which leads to the error mentioned when executing the "next()" call.
The code that sets up the drain event listener will cause the "this" context of the "this._onDrain" to be the newly created "fs.createWriteStream" stored in this._dest property instead of the File transport "this" context.
Changing to:
.on('drain', () => this._onDrain())in the above code seems to solve the issue. By wrapping in an arrow function the "this" context is preserved. This implies that the "this" context is being set wrong when the "this._onDrain" function is called on a "drain" event.So I believe this is a legitimate bug in the File transport code unless someone thinks otherwise.