Monitor and handle exceptions like a boss in angularjs
Why am I writing this
There might have been times where you would have wished to have better control over your error logging system. You might have thought about implementing an exception handling mechanism for your angularjs application but what might have been stopping you is the amount of code that you would have to write to achieve it. Also, the amount of restructuring you might have to do to wrap your code in your exception handling mechanism.
The problem
Lets start with analyzing some code that you might have written or might have come across in your application.
You can view the above code here.
A quick explanation:
This controller has a function doImportantStuff
which basically calls a service doVeryImportantStuff
of suspiciousService
. The options object just tells the service to throw an exception or not. In case it is true, it throws a JavaScript exception which would not be handled in the catch block because the catch block is essentially a reject handler for the promise. It gets executed only when the promise is rejected in the service, not when an exception is thrown.
In case you are wondering, what suspiciousService.js
looks like. Here it is.
You can view the code here
Now a more pragmatic approach would be to wrap your controller code in a try catch block which would mean your code would look like this.
You can view the above code here.
Now your JavaScript exceptions will be caught and logged and if you have an endpoint exposed from your API which logs client side errors, then you can submit errors to the API which will log them to the database.
The Idea
If you are thinking why would you want to log your client side exceptions to your database in the first place? You could implement this as a plugin, for example imagine a situation where you are just unable to fathom what is going wrong for a particular user because he uses a particular browser/OS/Machine etc which your application may not support completely. So you can turn this logging-front-end-exceptions-to-database setting or flag ‘on’ for a while and just have the user repeat those steps, turn the setting to ‘off’ and Voila! You would have exactly the information you need that is going wrong for that user due to him or her using a particular browser/OS/Machine or for whatever reason the user is facing that particular problem.
No need to spend countless hours figuring out what could have gone wrong for the code you have written. Just inject an error logging service that submits your exceptions to database and you will get what to you need to fix that error. This becomes particularly important if your application is running in an environment that cannot be debugged like Outlook desktop add-ins.
All this sounds good but there still is a small problem.
Remember that we wrapped our code in a try catch block? We would need to do that for all our controllers. Now that’s nasty. That’s not neat at all. It reeks of unwanted and ugly code. Now you may want to get around this by applying try catch blocks to your services instead because that is where exceptions really matter and should be logged and known if they occur. As an example, if something is going wrong on the home page but other pages are working fine and all your services have the exception handling plugged in, then the most probable culprit will be the homeController.js
file (or whatever controller you use for the home page for that matter).
In that case the suspiciousService.js
will look like this
But still, even if we move out try catch blocks to our services from our controllers, it is still nasty! Nobody wants to write this sort of code in their sane minds until they have no other way out, isn’t it? There just might be something angularjs has in its kitty that can rescue us.
The solution: Enter the $exceptionHandler
angularjs has a $exceptionHandler
service that you can use in order to delegate all uncaught exceptions to be handled there. However, the default implementation of $exceptionHandler
delegates it to $log.error
which logs it to the browser console. This is not what we signed up for. We need to send this error to our API which will log it to DB or email/notify someone about it. That means we need to modify the implementation of $exceptionHandler
The API endpoint
Before we can modify the $exceptionHandler
, lets take a look at the logger service that will log the exceptions into the database. You can skip this portion if your are not too focused about the API endpoint for now. I have included this for the completeness of the article.
I have implemented this using dot net core API, you can do the same with node and express if you wish.
LogService.cs
is a scoped service that will only get created only when a request to log an exception is encountered.
Modifying $exceptionHandler
As per our use case we modify the $exceptionHandler in this way.
- Our controllers and services are much cleaner with all that try catch block gone.
- All uncaught exceptions are handled and reported and this can be turned on and off as required.
- We have moved towards a more effective exception handling mechanism that is reliable, flexible, maintainable and more importantly gives us the luxury of working on errors faced by users at a time of our choosing as they are already logged or reported.
If you have reached this far, thank you for reading it. I will keep an eye on any feedback or suggestions for this post.