5

What follows is the method I use to handle/log all the possible exceptions in an Express application. Any other way?

Error handling it's a delicate issue especially when dealing with Express. Let's start from the easiest scenario. Imagine that our app is the following:

console.log(ciao.ciao);    // EEERRROOORRR

Launching the application from the console we get the following:

console.log(ciao.ciao);
            ^
ReferenceError: ciao is not defined

Note that the above case it's an example of un Uncaught Exception due to the fact that there is not code written by us executed in consequence of the error. To handle the error above we could do the following:

process.on('uncaughtException', function (err) {    
    console.log('error', ' * we did it, we handled the error * ', err.stack.trim());    
    process.exit(1);    
});

console.log(ciao.ciao);       // EEERRROOORRR

If we launch now the application we get:

error  * we did it, we handled the error *  ReferenceError: ciao is not defined

Attention please!!! "process.on('uncaughtException'..." will be DEPRACATED!!!

In order to be ready when the deprecation occurs it's better for us to use the Exception Handler of our favorite logger wich is the powerful and superpopular winston. Our application becomes:

var winston = require('winston');

var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({ handleExceptions: true }),
  ]
});

console.log(ciao.ciao);         // EEERRROOORRR

and it's output is the following:

error: uncaughtException: ciao is not defined date=Wed Oct 22 2014 16:26:53 GMT+0200 (ora legale Europa occidentale), pid=8052, uid=null, gid=null, cwd=c:\Projects\Eclipse\WEBSITE\node_taxiapplication, execPath=C:\Program Files\nodejs\node.exe, version=v0.10.26, argv=[node, c:\Projects\Eclipse\WEBSI
TE\node_taxiapplication\test2.js], rss=13479936, heapTotal=7130752, heapUsed=2760024, loadavg=[0, 0, 0],... 

The great winston outputs a lot of meaningful information to help us to manage the error, have a look at the pid parameter or at the memory information (rss, heapTotal,...). Another good thing done by winston is to exit the application wich is good in case of uncaught exception.

Let's make our application an Express Server Our application becomes:

var winston = require('winston');
var express = require('express');
var app = express();

var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({ handleExceptions: true }),
  ]
});

app.get('/', function(req, res, next) { 
    console.log(ciao.ciao);         // EEERRROOORRR
});

app.listen(3000);

Launching the server and asking to the browser http://localhost:3000 we get on the browser:

ReferenceError: ciao is not defined at Object.handle (c:\Projects\Eclipse\WEBSITE\node_taxiapplicatio...

and the app it's still running which is not a good idea when there is an error on a web server.

Where the hell is the winston Exception Handler?

Winston haven't handled the error above because it's been handled by Express, this due to the fact that the error is in the scope of the Express route handler that follows:

function(req, res, next) { 
    console.log(ciao.ciao);         // EEERRROOORRR
});

So winston is out of the game in case of error inside of an Express route handler

What we want to achieve is to log also this error using winston and the application to exit but to reach our goal we need our code to be executed when an error occurs "inside" Express. To do so we are going to use Express error middleware as follows:

var winston = require('winston');
var express = require('express');
var app = express();

var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({ handleExceptions: true }),
  ]
});

app.get('/', function(req, res, next) { 
    console.log(ciao.ciao);         // EEERRROOORRR
});

app.use(function(err, req, res, next) { 
    logger.log('error', ' * logged by winston * ', err.stack.trim());   

    process.exit(1);
});

app.listen(3000);

If we ask to our browser http://localhost:3000 we obtain that the application exits and on the console we get the following which is throwed by winston:

error:  * logged by winston *  ReferenceError: ciao is not defined

Unfortunately in this case we are not able to get all the informations which are outputted by winston when he directly handles an exception but at list we have control also on the errors handled by Express.

But I want all the informations given by winston when it handles directly the exception

Ok, let's try! We have to find a way to make Express lose control on the Exception. We said above that Express handles Exceptions when these occur in the scope of a route handler:

app.get('/', function(req, res, next) { 
    console.log(ciao.ciao);
});

Let's check what happens when the error occurs inside an asynchronous function contained in an Express route handler:

app.get('/', function(req, res, next) {
    setTimeout(function () {
        console.log(ciao.ciao);
    }); 
});

Launching the app:

var winston = require('winston');
var express = require('express');
var app = express();

var logger = new (winston.Logger)({
                        transports: [ new (winston.transports.Console)({ handleExceptions: true }) ]
});

app.get('/', function(req, res, next) {
    setTimeout(function () {
        console.log(ciao.ciao);                             // EEERRROOORRR
    }, 1);  
});

app.listen(3000);

and requesting http://localhost:3000 we observe the app exiting and on the console:

error: uncaughtException: ciao is not defined date=Thu Oct 23 2014 09:52:01 GMT+0200 (ora legale Europa occidentale), pid=5952, uid=null, gid=null, cwd=c:\Projects\Eclipse\WEBSITE\node_taxiapplication, execPath=C:\Program Files\nodejs\node.exe, version=v0.10.26, argv=[node, c:\Projects\Eclipse\WEBSI
TE\node_taxiapplication\test2.js], rss=18325504, heapTotal=15453568, heapUsed=4883192,

Hej, Express didn't handled the above error but winston did (we have the memory details in the output). This because the error didn't occur inside an Express scope but inside an asynchronous function scope. Hence what we need is to transform an error in the Express scope in an error in the scope of an asynchronous function. Hej we can do that, in fact we are already able to run our code to manage an Express error. Our strategy is to insert an asynchronous setTimeout (1ms delay) inside the Express error middleware (where there is our code to handle Express errors) and inside the setTimeout to throw the same error arrived to the middleware as argument.

var winston = require('winston');
var express = require('express');
var app = express();

var logger = new (winston.Logger)({
                        transports: [ new (winston.transports.Console)({ handleExceptions: true }) ]
});

app.get('/', function(req, res, next) {
        console.log(ciao.ciao);                             // EEERRROOORRR
});

app.use(function(err, req, res, next) { 
    res.send('Arrrghhh!!! The Server is at the moment down.');
    setTimeout(function () {
        throw new Error(err.stack.trim());                                   // <<<--- TRICK
    }, 1);
});

app.listen(3000);

Requesting http://localhost:3000 we have on the browser the response "Arrrghhh!!!...", the application exits and on the console we obtain:

error: uncaughtException: ReferenceError: ciao is not defined date=Thu Oct 23 2014 10:00:51 GMT+0200 (ora legale Europa occidentale), pid=5792, uid=null, gid=null, cwd=c:\Projects\Eclipse\WEBSITE\node_taxiapplication, execPath=C:\Program Files\nodejs\node.exe, version=v0.10.26, argv=[node, c:\Projec
ts\Eclipse\WEBSITE\node_taxiapplication\test2.js], rss=18489344, heapTotal=15453568, heapUsed=5115092,...

We obtained that all the errors are logged/managed through winston: the application exits and the log of the error contains many useful informations which could help in solving the problem.

matteo
  • 1,635
  • 1
  • 15
  • 26

1 Answers1

0

try this to handle errors better.

https://github.com/expressjs/errorhandler or

https://www.npmjs.org/package/express-error-handler

azero0
  • 2,220
  • 3
  • 20
  • 31