Documentation Menu

AngularJS Error Handling

AngularJS has built in support for logging, exception handling and AJAX calls.

This page shows how to:

AngularJS log messages

AngularJS' standard $log service simply logs to the browser console, which is not much good when your app goes live.

To make AngularJS do JavaScript logging through JSNLog so you can log to the server, simply replace the $log service:

// Create new module logToServer with new $log service
angular.module('logToServer', [])
.service('$log', function () {
    this.log = function (msg) {
        JL('Angular').trace(msg);
    }
    this.debug = function (msg) {
        JL('Angular').debug(msg);
    }
    this.info = function (msg) {
        JL('Angular').info(msg);
    }
    this.warn = function (msg) {
        JL('Angular').warn(msg);
    }
    this.error = function (msg) {
        JL('Angular').error(msg);
    }
});
// When creating your main module, import module logToServer
var app = angular.module('main', ['logToServer']);

Log JavaScript exceptions

To ensure that exceptions are logged with severity FATAL, replace the factory that creates the standard $exceptionHandler service:

angular.module('logToServer', [])
.service('$log', function () {
    ...
})
.factory('$exceptionHandler', function () {
    return function (exception, cause) {
        JL('Angular').fatalException(cause, exception);
        throw exception;
    };
});
var app = angular.module('main', ['logToServer']);

Log AJAX issues

To add JavaScript error handling for AJAX calls, it makes sense to use an AngularJS Interceptor. This allows you to run your own code when the $http service is about to send an AJAX request, after it has received a response, and after detecting an error.

Add a factory to create the interceptor to your logToServer module:

angular.module('logToServer', [])
...
.factory('logToServerInterceptor', ['$q', function ($q) {
    var myInterceptor = {
        'request': function (config) {
            config.msBeforeAjaxCall = new Date().getTime();
            return config;
        },
        'response': function (response) {
            if (response.config.warningAfter) {
                var msAfterAjaxCall = new Date().getTime();
                var timeTakenInMs = 
                      msAfterAjaxCall - response.config.msBeforeAjaxCall;
                if (timeTakenInMs > response.config.warningAfter) {
                    JL('Angular.Ajax').warn({ 
                      timeTakenInMs: timeTakenInMs, 
                      config: response.config, 
                      data: response.data });
                }
            }
            return response;
        },
        'responseError': function (rejection) {
            var errorMessage = "timeout";
            if (rejection && rejection.status && rejection.data) {
                errorMessage = rejection.data.ExceptionMessage;
            }
            JL('Angular.Ajax').fatalException({ 
                      errorMessage: errorMessage, 
                      status: rejection.status, 
                      config: rejection.config }, rejection.data);
            return $q.reject(rejection);
        }
    };
    return myInterceptor;
}]);
var app = angular.module('main', ['logToServer']);

The request function is called before the AJAX request is sent. It gives you access to the config object, which is shared throughout the interceptor. Here it is used to store the current time, so after the response is received it can calculate whether it was too late.

The response function is called after receiving a good response from the server (that is, it has an HTTP code in the 200 range). This is the right place to calculate how long the user had to wait for the response, and to log a warning message if it took too long.

The responseError function is called when an error response was received, or when a timeout happened. You can distinguish between timeout and bad response by looking at rejection.status - it will contain 0 for a timeout, and the HTTP response code in case of an error response.

Don't forget to add the new interceptor to the interceptor pipeline of your main module:

app.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('logToServerInterceptor');
}]);

When you call $http to send an AJAX message, set the timeout and the delay after which a warning log message is sent in milliseconds in the config object, using timeout and warningAfter:

$http({ method: '...', url: '...', data: ..., 
        timeout: 5000, warningAfter: 2000 })
.success(function (data, status, headers, config) {
	...
})
.error(function (data, status, headers, config) {
	...
});