Gobliins Gobliins - 2 months ago 13
Node.js Question

Winston logger throws ENOENT

My Code:

import winston from 'winston';

Meteor.startup(() => {
const env = process.env.NODE_ENV || 'development';
const tsFormat = () => (new Date()).toLocaleTimeString();
const logDir = 'log';
const logger1 = new (winston.Logger)({
transports: [
// colorize the output to the console
new (winston.transports.Console)({
timestamp: tsFormat,
colorize: true,
level: 'info',
}),
new (winston.transports.File)({
filename: `${logDir}/results.log`,
timestamp: tsFormat,
level: env === 'development' ? 'debug' : 'info',
}),
],
});
logger1.info('Hello world');
//logger1.warn('Warning message');
//logger1.debug('Debugging info');
});


Output:

I20170717-11:39:11.027(2)? 11:39:10 - info: Hello world
W20170717-11:39:11.150(2)? (STDERR)
W20170717-11:39:11.151(2)? (STDERR) events.js:72
W20170717-11:39:11.152(2)? (STDERR) throw er; // Unhandled 'error' event
W20170717-11:39:11.152(2)? (STDERR) ^
W20170717-11:39:11.153(2)? (STDERR) Error: ENOENT, open 'log/results.log'


The results.log is not even created

Update: When i use only a filename without a path then it works).

Related but not helped solving:

Node.js, can't open files. Error: ENOENT, stat './path/to/file'

What is the problem?

Answer Source

Winston doesn't actually create the directory where you want the logfile to go, which is why you get the ENOENT.

(I'm not very familiar with Meteor, but the following instructions work on "plain" Node.js)

You can create the directory manually before instantiating Winston to make sure it exists, using fs.mkdirSync, although that would only go one level deep (it won't create intermediate directories, if there are any in the path).

There's also mkdirp.sync(), which does create intermediate directories.

Using the synchronous versions is a bit easier, and since it's an operation that only occurs once during the start of the app, it's not a bottleneck.