How to track Angular.js exceptions automatically

| 4 min. (747 words)

One of the areas where Angular.js has made great gains is the usefulness of the exceptions it throws, as the messages often indicate exactly why your code broke. The problem with having a huge client-side web app running on a multitude of browsers across the world is that these exceptions are lost, and with it the chance to fix up the bug and win back a user.

AngularJS logo

It is especially important to receive these exceptions when dealing with cross-browser and device issues, as while your app may perform rock-solid on your dev machine, the browsers on your user’s machines are guaranteed to be different creating an unfeasibly large testing surface.

The solution is an automatic exception tracking service, and Raygun makes this easy by receiving every exception your Angular web app throws, without you doing a thing. It’s really quick to set up, too - follow the steps below to hook Raygun into your app.

Installation

Standard method

Add the following code snippet to the <head>, as high up in the document as possible:

<script type="text/javascript">
  !function(a,b,c,d,e,f,g,h){a.RaygunObject=e,a[e]=a[e]||function(){
  (a[e].o=a[e].o||[]).push(arguments)},f=b.createElement(c),g=b.getElementsByTagName(c)[0],
  f.async=1,f.src=d,g.parentNode.insertBefore(f,g),h=a.onerror,a.onerror=function(b,c,d,f,g){
  h&&h(b,c,d,f,g),g||(g=new Error(b)),a[e].q=a[e].q||[],a[e].q.push({
  e:g})}}(window,document,"script","//cdn.raygun.io/raygun4js/raygun.min.js","rg4js");
</script>

Alternative method

Download the Raygun4JS provider script and add it to your project. There are three delivery channels:

Via NPM

npm install raygun4js

From NuGet - in Visual Studio, open up the Package Manager Console and type

Install-Package raygun4js

Manual download

Grab the dev version here, or the minified production version here.

Configuration

Next, reference the script - if you’re using static HTML add something like <script src="js/raygun.js" type="text/javascript"></script> or add it to your module loader/minifier.

Finally, call the following code before your main Angular logic to set up Raygun4JS:

rg4js('apiKey', 'YOUR_API_KEY');

You get an API key for each app you create in Raygun, which is available in your Raygun dashboard - there’s a free 30-day trial available for you to test it out.

Catching exceptions in Angular

There are at least two options for injecting an unhandled exception function into Angular.js modules, with a decorator or a factory. Both of these provide your specified implementation of $exceptionHandler, which we will use to send to Raygun via the Raygun4JS provider we referenced above.

Using a decorator

The Decorator pattern is great for injecting behaviour onto arbitrary services ensuring separation of concerns among other desirable properties, and is the preferred way for logging and exception handling as it doesn’t override the original behaviour. In Angular.js this is available on the $provide service, which we will use to implement our own $exceptionHandler function:

app.config(function ($provide) {
  $provide.decorator("$exceptionHandler", ['$delegate', function($delegate) {
    return function (exception, cause) {
      rg4js('send', { 
        error: exception
      });
      $delegate(exception, cause);
    }
  }])
});

The $delegate is the instance of the exception handler, which we call to get the original behavior of outputting to the console.

You can also make as many other services available as required:

$provide.decorator("$exceptionHandler", ['$delegate', '$log', function($delegate, $log) {
  return function (exception, cause) {
    $log.debug('Sending to Raygun');
    rg4js('send', {
      error: exception
    });
    $delegate(exception, cause);
  }
}])

Depending on what sort of error gets thrown within Angular logic, the cause parameter can be populated. If one occurs within a factory or service you may get the scope available on that parameter, which you can transmit to Raygun as custom data, along with anything else you need, by replacing the send call above:

rg4js('send', {
  error: exception,
  customData: {
    cause: cause
  }
});

Using a factory

A quick way for getting Raygun into your app’s exception handler is to override it using a factory, although this removes the original console logging, and you’ll need to store the original value then call it again if you want this functionality.

app.factory('$exceptionHandler', function () {
  return function (exception) {
    rg4js('send', {
      error: exception
    });
  }
});

Manually sending errors

Raygun4JS also gives you the ability to manually track errors easily at any time, like this:

rg4js('send', {
  error: new Error('my custom error')
});

There’s also a bunch of other useful tools available on the provider, including unique user tracking, version tracking, tags and more - check out the documentation here for all the details.

Raygun even tracks jQuery Ajax errors in your Angular app without any extra effort needed from you, so you get full coverage out-of-the-box.

Ready to get Raygun?

As mentioned above there’s a free 14-day, no-credit-card trial available here, so grab yours and check out how your web app is really performing for your users. If you have any questions about this post leave them in the comments below, otherwise happy error blasting!