arrow_backward Back to blog

Extending AngularJS’s $log

log$

Have you ever been working with a particularly complicated web application and found that the output you were getting back from $log was difficult to wade through? Perhaps it's a complex XML response (because you're working with a SOAP API), or it's a particularly dense JSON response. Maybe the browser you use as your primary workhorse is working fine, but you found a gnarly bug in handling the response you're getting back from an API and it's failing in one of the other browsers youโ€™re testing?

I recently ran into an issue similar to this; for me, it was while working with a SOAP API. And while the browser I'm using has all of the necessary development tools, emitting the responses I was looking for in an easy-to-read way was just not happening for me. No matter how I went about logging it all out, the response was coming back as a single line of text when emitted to the JavaScript console, and because it was a string I was having trouble easily inspecting it. While I wasn't having browser-specific issues (in this case), needing to add the extra effort of moving over to a view in my debugger was costing me precious turn-around time in trying to debug this response. If I was having this sort of issue with these responses, then the other developers on my team likely were as well.

After doing some research, I came across a fairly light-weight library called vkbeautify, which handles beautifying (as well as minifying) strings that are passed in to the appropriate method. This solved part of my problem: I now had a way to programmatically re-format my XML strings. Now, I could have stopped with simply injecting the library into the application, then just emitting out the formatted strings while I was debugging the issue I was trying to resolve. However, as I mentioned earlier, I'm working as part of a larger team, and I wanted the rest of the team to have this ability as well. Furthermore, I wanted us to be able to selectively emit data into the console in a consistent manner with some sane defaults.

The next logical step was to look at the $log service. Since this is an abstraction of the global console interface (log, info, warn, debug, etc) and it had the benefit of being stubbed so it wouldnโ€™t display in unit tests, it made sense that I should simply extend that service. That way, any developer could call a method of the $log service to emit these nicely formatted strings.

To accomplish this, I created a provider decorator for $log and made it available from within the application. One of the nice things about provider decorators is that you can leverage a reference parent service and then call that serviceโ€™s methods, which was nice because I wanted to leverage the existing infrastructure as much as possible – truly extending the $log service. So, I added a new method (called pretty, a nod to the concept of "pretty printing," which is common in most programming languages), and had that piggy-back on one of the other methods in the service. It looks a bit like this:

angular.module("myApp").config(["$provide", function ($provide) {   $provide.decorator("$log", ["$delegate", function ($delegate) { // $delegate, here, is an internal       reference to $log     $delegate.pretty = function (input, opts) {       var output;       opts = opts || {};       output = vkbeautify[(opts.type || "json")]](input); // use the correct vkbeautify for beautifying the        string - vkbeautify.json, vkbeautify.xml, vkbeautify.sql, etc; defaults to json       $delegate[(opts.output || "log")].call(null, output); // leverage one of the other $log methods to    actually emit the output; defaults to log     };     return $delegate;   }]); }]); 

Now, in our application, when a developer makes a call to $log.pretty(), the input they pass to it is run through vkbeautify with the given data type and output method (defaulting to json and $log.log, respectively). These values can be changed by passing in an Object as the second parameter with a property of type or output set to the desired value. Here are a few examples:

$log.pretty("<div><h1>Hello world</h1></div>", {type: โ€œxmlโ€); // // <div> //   <h1>Hello world</h1> // </div>  $log.pretty("body:{background:#fff;}.rounded_box:{border-radius:20px;}", {type: "css"}); // // body: { //   background: #fff; // } // .rounded_box { //   border-radius: 20px; // }  $log.pretty({jsonObj: {childAry: [1,2,3], childObj: {someProp: "prop"}}}, {output: "info"}); // this would    emit using $log.info; leveraging that type is defaulted to json // // { //   jsonObj: { //     childAry: [ //       1, //       2, //       3, //     ], //     childObj: { //       someProp: "prop" //     } //   } // } 

While I lose the ability to log out multiple items with this method (console.log(var1, var2, var3), for example), I gain the far more important ability to emit nicely formatted output that is easier to scan and understand. The big take-away here is that you can leverage the ability to extend $log to create output necessary to make debugging your code simpler. Think of the existing API as a starting point, and go from there. Chances are good that most use cases are already covered, but there's always something that isn't.

Finally, to help anyone else that finds themselves in this specific situation, Iโ€™ve released this as a package thatโ€™s available on bower. Just run bower install ng-log-pretty and include both vkbeautify and the library itself in your application and youโ€™ll be off and running. You can also check out the code on GitHub.

arrow_backBack

New Project Request