Centralized Error Handling & Reporting for node.js - node.js

I want to have a system which will either send me a text message or email based on severity of error on respective occurrence. I have done some research on the subject but I haven't been able to simplify matters.
All in all my end goal is to get notification whenever something is going wrong with my production server. In case of serious issues which are not caught at all I have used process's uncaughtException and for specific routes which are called via separate API calls I can simply use try catch blocks.
My first issue is I cannot handle errors thrown from different routes directly via my main server file.
Second is I'll have to write same kinda' code in every route for exception handling. If something could just listen to all the errors from main server file then I can do things easily.

You can use an error handling middleware in Express:
app.use(function (err, req, res, next) {
console.error(err.stack);
// do whatever you need to send a notification
res.status(500).send('Internal error');
});
See the documentation on the error handling in Express:
https://expressjs.com/en/guide/error-handling.html
Everything you ask about is explained very well there.

Related

How do you handle errors thrown from third-party middleware in express?

let's take this snippet for example
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.get(...)
# all my routes #
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
app.listen(9000)
....
if body-parser throws an error?
Maybe the client closes the connection or the request payload is too large
the client will receive an error with status code 500 from the default express error handler but it’s probably a error that should return 4xx response .
I thought of putting a middleware right after it and calling res.send with the error and status code 400.
maybe wrap all my 3rd party middle ware with try-catch handler
Or adding in my error handler middleware a huge switch case
And over time adding error thrown from middleware third party middleware and change there status code to 400
All the solutions not really bolt proof and need maintenance over time
What us the best practice any suggestions?
The body-parser module should call next(err) when it encounters an error and you can then intercept that by providing an Express error handler such as:
app.use(function(err, req, res, next) {
console.error(err.stack)
res.status(500).send('Put your content here')
});
When you define this special middleware (with four arguments), then Express will keep track of that separately as an error handler that should be called when/if some request handler calls next(err) or if a synchronous exception is caught by Express.
Express has a default error handler if you do not provide one which you can read about here. But, if you supply one, then yours will take over and you can do whatever you want from the error handler. You can even just log the error and take the user to an error page - you don't have to even send an http error status if it's a web page request. If it's an API, you should probably be using http error statuses.
what is the best practice?
Best practice is to include your own Express error handler where you will be able to intercept all errors that are sent on to next(err).
I thought of putting a middleware right after it and calling res.send with the error and status code 400 or maybe wrap all my 3rd party middle ware with try-catch handler
Your third party middleware needs to behave properly in the Express eco-system. That means that it can throw synchronously and Express will catch it automatically and send to the Express error handler. The code should not throw asynchronously (as is true for all types of code) because nobody can catch those exceptions (unless they are in promise-structured code). You shouldn't have to wrap middleware yourself.
Internal errors should generally not be 4xx errors, but rather 5xx errors. Whether or not you surface an internal error back to the end user depends entirely upon the context. Usually, the user will be shown some sort of general purpose error page. Or, if it's an API, the API will have a scheme for communicating errors and typically the API will return actual http status codes that appropriately map to the type of problem.
after further investigation, this is the best solution suited for me
simply adding another middleware after body parse
https://www.npmjs.com/package/express-body-parser-error-handler

How to create an error handling "interceptor" for NodeJS

So I did a lot of digging around the internet, and I have been unable to come up with the answer to my problem. My goal is that I want to print any errors that are logged to the console into a database. However, I have gone far enough into my project that it would be a pain to go back into my try...catch... blocks and edit them with an error extender, or to just create my own function in the catch area.
I wanted to know: is there a specific way to create an error interception in NodeJS? I mean, I assume that whenever an error is logged to the console, the code fires some sort of event, and I guess I am looking for something like:
process.on(error, async (e) => { // my code here })
Is that at all possible? Is there a module that will allow me to do this? For context, I am running the latest version of Node/NPM on a headless Ubuntu 18.04 server, and am using pm2 to control my program processes.
You can use middleware at the end of the main file of your app
var bodyParser = require('body-parser');
app.use(bodyParser());
...
...
app.use(function(err, req, res, next) {
// Error handler logic
});
You can find more about this in the express documentation https://expressjs.com/en/guide/error-handling.html

How to add express middleware at the end of the chain that gets invoked no matter what (OK/FAIL responses)?

Is there a way to add middleware to the end of an express app or router chain that gets called to track whether or not the res / response was sent or not?
I mean, regardless of if:
A response is sent (string, JSON, etc.)
A static served file.
No file found in the static folder.
A catch-all callback was reached.
An error middleware was reached.
Example
For instance, if I wanted to log everything...
whether a response was successful or not, ie: it served a file via a express.static( ... ) middleware, some data fetched from a DB, or a custom middleware, or again... if it failed / threw an error...,
is there a way to invoke a callback at the very end?
So far from what I can understand, it seems like, by design, if a static file gets served successfully (via express.static), it doesn't call next(), so the chain stops there.
And for any custom-made middlewares using res.send(), you normally wouldn't want to call next() afterwards since it could cause some undesirable side-effects (errors with headers getting resent).
For error-handlers, that's easier since all unsuccessful responses can be caught here.
But how can it output both successful / unsuccessful responses? Could this be something that should be done without middlewares?
The solution I went with ended up being slightly different from this one by #idbehold, but in a nutshell, at the very top of the express app middleware chain, I had to hook a callback to the res Response object's finish event which gets triggered for most (all?) HTTP status-codes I needed to track a successfully served request.
app.use( ( req, res, next ) => {
res.on( 'finish', () => {
var codeStr = String( res.statusCode );
codeStr = codeStr[res.statusCode < 400 ? 'green' : 'red'];
var output = [req.method.green, req.fullUrl().green, codeStr];
trace( output.join( ' ' ) );
} );
next();
});
I can now get things like:
EDIT
Alright! So provided you also have an error-handler at the "end" of your middleware chain that serves something with an error 404 code, that will trigger the finish event on the res object.
Example of such an error-handler:
app.use( ( err, req, res, next ) => {
trace( "Error!".red );
trace( err );
res.status( 404 ).send(); // Triggers 'finish' on res.
})
There's a conceptual difficulty with the asynchronous architecture of node.js and Express for doing this. I'll describe the general problem and then discuss a few possible work-arounds.
First, each Express handler can be asynchronous. Thus, it gets called and returns pretty much immediately and nobody outside of that world knows whether it is still waiting for some asynchronous operation to finish before eventually sending its response or if it just failed to do anything. You literally can't tell from the outside world.
Second, you can monitor a given request to see if it either calls an error handler or if it sends a response. There is no way to monitor a request handler to see if it just failed to send anything because of the reason above - you have no way of knowing if its still waiting for some asynchronous thing to finish.
So, here's the best I could recommend:
Hook res.end() to see when it gets called. This is an indication that the response is now done (whether error or success). You can see an example of doing that in the express-afterware module that Medet linked in an above comment. The general idea is that you'd have your own middleware somewhere very early in the chain that overrides res.end() so you can see when its called. That early middleware would just install the override and call next() to continue the handler chain. Then, when the response is finished, your override would see that res.end() got called. This should work for all cases where the response is sent.
Then, you still need to handle cases where no response is sent (which is probably due to faulty code since all requests should get a response eventually). The only way I know of to do that is to implement some sort of timeout for a request. You can either use a built-in mechanism server.setTimeout() or you can implement your own inside your middleware (same middleware as describe in step 1). Then, after some timeout that you specify, if no response has yet been sent, you would take over and send some error response.
Install your own error middlewares early in the chain that will see and log all errors. Note that res.end() will still be called so the behavior in step 1 will still be triggered even for errors (error responses still call res.end()).
You can trigger a piece of code at the end of a request by using the finish event of the response object. The finish event is emitted when the response has been sent to the client and all the data has been flushed to the network.
app.use(function(req, res, next) {
res.on('finish', function() {
console.log('Request finished');
});
next();
});

Passing errors to client in express

How do you pass nice error messages to clients in express?
app.use(errorHandler);
function errorHandler(err, req, res, next) {
res.send(err);
}
app.post('/login', usernameIsValid, pwdIsValid, createToken);
In usernameIsValid I create a new Error with a message and status and call next(err). Now this bypasses pwdIsValid and createToken like it should BUT the weird thing is my errorHandler logs the error without a console.log. Am I using the default error handler in express somewhere? How do I turn it off? I have tried both production and development for NODE_ENV.
On the client xhr.responseText is my error.message + what looks like a stack trace? I've even tried just to send err.message but it looks the same.
One way to handle this mess is to make each middleware (if there is an error) create an error string like req.data.err = "invalid username" and then make sure each following middleware checks req.data.err if the string is present. But this is tedious as hell >_<
I solved it. You need to apply the error handler app.use(errorHandler) dead last after all other routes. This disables the built-in error handler. Now you may pass pretty error messages to the client.
Read more here.
edit: process.env.NODE_ENV does not matter.
From the express documentation site
If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
So if you want to avoid the stacktrace you only need to execute your application with the NODE_ENV set to production.
Run you application as follows:
$ NODE_ENV=production node file.js

How do you catch all errors in SailsJS

I'm new to Node and Sails and have been struggling with this problem for a couple of weeks now. I need to log (eventually to a file or database) all errors that occur in our Sails app. I have found a couple of answers that come close to solving this, but none seem to work 100%. I have setup things based off of the answer from this question
When using Sails v0.9.16 I setup my logging in the config/500.js file, but when using test code...
t.t;
... in my controller, Sails just prints out "ReferenceError: t is not defined". It never goes to 500.js. In Sails v0.10.0-rc5 the same test code will get to my custom 500 middleware (shown below).
Problem is in Sails v0.10.0-rc5 it appears that the middleware Router handles 400 error message before getting to my custom 400 middleware.
We have not committed to which version we are going to use, but getting this to work in one or the other would probably make up our minds.
So how do I get all errors that happen? If I am on the right track, what am I missing to get this to work?
Thanks in advance!
Not much code to show for v0.9.16...I don't think I changed anything other than adding a sails.log in the 500.js file...
Below is the custom middleware setup for v0.10.0-rc5 ...
loadMiddleware: function(app, defaultMiddleware, sails) {
// Use the middleware in the correct order
app.use(defaultMiddleware.startRequestTimer);
app.use(defaultMiddleware.cookieParser);
app.use(defaultMiddleware.session);
app.use(defaultMiddleware.bodyParser);
app.use(defaultMiddleware.handleBodyParserError);
app.use(defaultMiddleware.methodOverride);
app.use(defaultMiddleware.poweredBy);
app.use(defaultMiddleware.router); //400s do not make it past this...
app.use(defaultMiddleware.www);
app.use(defaultMiddleware.favicon);
app.use(function(req, res, next ) {
sails.log("400 error caught in middleware - " + err.stack);
next();
});
app.use(function(err, req, res, next){
sails.log("500 error caught in middleware - " + err.stack);
next(err);
});
}
In Sails v0.10, you have custom responses to handle errors, so you don't need to provide custom middleware as in your example. By default, most errors (i.e. those not specifically triggered by res.forbidden(), res.notFound() or another handler) will be served by the serverError response that lives in api/responses/serverError.js. You can customize this to do whatever you like.
If you've upgraded a v0.9 app to v0.10, you might not have the api/responses folder. No problem; just use sails new whatever in an empty directory to generate a new v0.10 project and copy the api/responses folder from the new project to your old one!

Resources