Last Updated: February 25, 2016
·
2.075K
· tomjakubowski

decorate Angular's $log service to debug long Promise chains

I often find myself needing to log values from the middle of a long promise chain to debug intermediate transformations. But writing:

somePromise
  .then(transformValue)
  .then(function (val) {
    $log.log(val);
    return val;
  })
  .then(function (val) {
    // do something with the transformed value
  });

is a drag. Fortunately Angular exposes a great decorator feature which allows you to modify existing services to suit your needs:

app.config(function ($provide) {
  /**
   * Decorates the $log service to make it a callable function
   * which returns the value of its first argument. Useful for
   * 'tapping' into Promise chains.
   */
  $provide.decorator('$log', function ($delegate) {
    var better$log = function (x) {
      $delegate.log.apply($delegate, arguments);
      return x;
    };

    // copy the original $log properties back onto the enhanced $log
    angular.extend(better$log, $delegate);
    return better$log;
  });
});

This makes it easy to log the intermediate values of a long Promise chain, while maintaining the existing $log service API:

app.controller('AppCtrl', function ($scope, $http, $log) {
  $scope.getGists = function () {
    $log.log('Logging like normal?', true);
    $http.get('https://api.github.com/')
      .then($log)
      .then(function (res) {
        return $http.get(res.data.public_gists_url);
      })
      .then($log)
      .then(function (res) {
        $scope.gists = res.data;
      });
  };
});

As a nice side-effect, you get a shorter and more convenient way to use $log from anywhere (just call it!). A working Plunker is available here.