Search code examples
javascriptnode.jsloggingexceptionwinston

Why does Winstonjs ExceptionHandler silence my node errors?


I've got a program written in Node in which I use Winstonjs for logging. I also have an exceptionHandler so that the node exceptions/errors also reach my logs. I now have a problem though. When I run the script from the command line using node index.js (instead of pm2) the script ends silently when it has an error.

Have a look at my example code below. I added three console.log()s which try to log an undefined variable. When I run the script using node index.js it gives me a ReferenceError for the first wrong console.log(undefinedVariable) as expected. When I now remove that first and/or the second console.log, the script ends silently.

"use strict";

let winston = require('winston');
const path = require('path');

const PRODUCTION = false;

// LOGGING
const myFormat = winston.format.printf(info => {
    return `${info.timestamp} ${info.level}: ${info.message}`;
});

console.log(undefinedVariable);  // THIS GIVES A REFERENCE ERROR

const logger = winston.createLogger({
    level: 'debug',
    format: winston.format.combine(winston.format.timestamp(), myFormat),
    transports: [
        new winston.transports.File({filename: 'logs/error.log', level: 'error'}),
        new winston.transports.File({filename: 'logs/combined.log'}),
    ],
    exceptionHandlers: [
        new winston.transports.File({ filename: 'logs/exceptions.log' }),
        new winston.transports.File({ filename: 'logs/combined.log' })
    ]
});

console.log(undefinedVariable);  // THIS DOES NOT GIVE A REFERENCE ERROR, BUT ENDS THE SCRIPT SILENTLY

if (!PRODUCTION) {
    // If we're not in production then also log to the `console`
    logger.add(new winston.transports.Console(
        {format: winston.format.combine(winston.format.timestamp(), myFormat), level: 'debug'}
    ));
}

console.log(undefinedVariable);  // THIS ALSO DOES NOT GIVE A REFERENCE ERROR, BUT ENDS THE SCRIPT SILENTLY

function log(message, level='debug'){
    // Levels: error, warn, info, verbose, debug, silly
    const e = new Error();
    const regex = /\((.*):(\d+):(\d+)\)$/
    const match = regex.exec(e.stack.split("\n")[2]);
    let log_source = path.basename(match[1]) + ':' + match[2];  // eg: index.js:285

    if (typeof message === 'object'){
        message = JSON.stringify(message);
    }
    logger[level](log_source + ' - ' + message);
}

I'm running Winstonjs version 3.0.0-rc5. I know it's not the final 3.0 release yet, but I guess I'm simply making a mistake here.

Does anybody know what I'm doing wrong here? All tips are welcome!


Solution

  • If you see Handling Uncaught Exceptions with winston doc

    you can set exitOnError = false

    By default, winston will exit after logging an uncaughtException. If this is not the behavior you want, set exitOnError = false

    And also add to yours transports new winston.transports.Console({ handleExceptions: true }) for show it in console.