Error tracking in angular

Hi everyone,

I had some hard times figure out how to track errors in javascript/angular and improving it.
So I share with you my code snippet.

Feel free to criticize or suggest some improvments :wink:

// catch exceptions in angular
$provide.decorator('$exceptionHandler', ['$delegate', function($delegate){
  return function(exception, cause){
    $delegate(exception, cause);

    var data = {
      type: 'angular',
      url: window.location.hash,
      localtime: Date.now()
    };
    if(cause)               { data.cause    = cause;              }
    if(exception){
      if(exception.message) { data.message  = exception.message;  }
      if(exception.name)    { data.name     = exception.name;     }
      if(exception.stack)   { data.stack    = exception.stack;    }
    }

    if(debug){
      console.log('exception', data);
      window.alert('Error: '+data.message);
    } else {
      track('exception', data);
    }
  };
}]);
// catch exceptions out of angular
window.onerror = function(message, url, line, col, error){
  var stopPropagation = debug ? false : true;
  var data = {
    type: 'javascript',
    url: window.location.hash,
    localtime: Date.now()
  };
  if(message)       { data.message      = message;      }
  if(url)           { data.fileName     = url;          }
  if(line)          { data.lineNumber   = line;         }
  if(col)           { data.columnNumber = col;          }
  if(error){
    if(error.name)  { data.name         = error.name;   }
    if(error.stack) { data.stack        = error.stack;  }
  }

  if(debug){
    console.log('exception', data);
    window.alert('Error: '+data.message);
  } else {
    track('exception', data);
  }
  return stopPropagation;
};

This code goes in the config method of angular.

debug is a global constant in my app (.constant('debug', true))
track(event, data) is a custom method sending data to my server

I hope it will help you :smiley:

9 Likes

This is just what I was looking for, thanks! I was using the onerror method for non-angular errors - I will add in the Angular error handler too.

I also go one step further and send the unhandled exceptions to Telerik Analytics (I am using AppBuilder and Ionic) so I can get notified of them

And what are the advantages against the javascript console of the browser?
There you can see stacktrace, error message and so on?

It’s for production debug !

Yes, the user cannot see the exception in a Cordova app but i do want to be alerted to them (there’s a lot of JS Error monitoring tools - I chose Telerik (Free for 2 projects) but there’s Sentry, TrackJS etc)

hmm, but i do not get it^^.

You make console.logs and alerts what is different to oridany error tracking?
You have to connect your device with the running app to a mac or other pc with chrome debugging.
If an error occur you will also get notified in the console?

In other case there is also in angularjs the possibility to use try, catch, finally blocks for sensitive data.

You should store errors in production in logs or something else.

There are some services which provide such functionalities to have access to your apps and logs like rodneyjoyce mentioned.

The idea is that if users are getting unhandled exceptions (ie. something went wrong that you did not think of) then your app is either going to stop working OR it will not alert the user and no one will ever know (but something might be gravely wrong).

So how do you report these to the App Developer if 1000 users have installed your app?

The easiest way is with a global error handler for uncaughter errors and to post them to an Error tracking service…

If you KNOW something is going to cause an exception then you can handle it in a local try/catch etc. (I still log these to my Telerik dashboard so I know how many times it was handled)

1 Like

Very good summary.

That is what i ment… you need a service or something that tracks the errors in production to debug them manually. With the error handle of loicknuchel you do not win something.

It is like ordinary debugging an app and hopefully find the errors.

Greetz.

Ok, I get the misunderstanding…

The code I posted do not send directly errors to a service.
This is the track(event, data) method which is responsible of that and I didn’t provide implementation (because it could be very sepcific !).

So, my code catch all errors, format them and send them to the track method. Then you can send it wherever you want with ajax calls (tracking service, custom backend…).

1 Like

@loicknuchel is there some smarter way to set the debug variable perhaps?

With .constant('debug', true) you debug var is avaiable everywhere in your angular app and it could be injected when you need it.
If you want, you can create a more complex object such as :
.constant('config', { debug; true, version: '1.0.0' })

Or, you can define it globally in scope :
window.debug = true;

Thanks, but I was thinking more of not having to change it manually when I build and deploy (I am a little new to Ionic and JS build Tasks - is this something for Grunt or similar to update when you do your final build?

Ok…

This could be cool but I didn’t investigate too far this way…
I’m interested if you find something :wink:

Ok, will let you know when I figure it out!

Question on your code (which I have now implemented - thanks): When do exceptions get caught by Angular, and when do they get caught by the global onerror handler? I tried to throw an error inside of a service and was surprised to see that it got caught by the onerror message, NOT the angular one. When I throw an error in a controller then it does get caught by the Angular one as I would expect.

Exceptions are caught by angular when they are angular exceptions.

For exemple, try to use an undeclared service or filter…

Ok, I see, I thought it was to do with where they were caught or in what stage of the life cycle…

@loicknuchel thanks for this. I have been having a hard time getting window.error to work correctly from an app running on an Android 4.4+ device and even just in the Chrome browser using ionic serve.

Have you run into anything similar? Even just something like this:

window.onerror = function (message, url, lineNumber, columnNumber, error) {
    window.alert('error');
};

I am testing by just running dragon() from a controller which is a non-existant function

So I found out what was happening. Apparently you can’t trigger onerror from the console directly unless with a setTimeout. For the app my Google Analytics events were just taking about 3 minute to show up. Hope this helps someone else.

You can try https://www.atatus.com/ which provides advanced error tracking for Cordova apps.

I tried to use this and cant get it to work.

Here is my function:

app.config(function($provide) {$provide.decorator("$exceptionHandler", function($delegate, $injector) {
return function(exception, cause) {

    $delegate(exception, cause);

    var data = {
        type: 'angular',
        url: window.location.hash,
        localtime: Date.now()
    };
    if(cause)               { data.cause    = cause;              }
    if(exception){
        if(exception.message) { data.message  = exception.message;  }
        if(exception.name)    { data.name     = exception.name;     }
        if(exception.stack)   { data.stack    = exception.stack;    }
    }

    if(true){
        console.log('exception', data);
        window.alert('Error: '+data.message);
    } else {
        //track('exception', data);
    }
};});});

In my controller I do an alert with an undefined variable:

alert(y);

When I debug with safari, connected to my device, I see in the console:

ReferenceError: Can’t find variable: y

I have set a breakpoint inside the decorator function and it never gets called. I also inserted an alert into the decorator function to see the exception, but still no dice. What am I missing? Can somebody help? I have been working on this for the past 3 hours.

Thanks,