Retain Console History using Angular’s $log

I’ve started wrap up on a substantial, Angular project that is now being used in production by customers. Overall, the app is working beautifully and errors are limited. I am recording errors to a server side database and I’ve noticed there’s been ‘digest already in progress‘ errors on one of the views. Although I’ve taken steps to try and get around those issues, I haven’t been able to pinpoint how the user is causing those errors.

I began trying to devise a way to track a user as they interact with the application, then use this information to help debug the errors. After poking around the internet, I wanted to use Angular’s  $log (docs) module to not only write messages to the console, but retain those messages. Then, write them to the server when an error occurs. I figured out that this behavior can be easily added without having to touch the window’s  console object by decorating the  $log module.

Decorate Angular’s $log

The first step is to add some functionality to the  $log service to capture history anytime one of the methods are used. Here’s the full code to decorate the  $log service:

The first section I want to touch on is the  wrapper function. Anything that would normally be printed to the console, I want to capture on the stack. The wrapper will take the existing functions on the $log  service and create a new function out of them. This way, anytime they are called, they push an entry onto the history stack that consists of, a time stamp, and all of the arguments that were passed into the original function. For instance, if I did  $log.info('My Stuff', [1, 2, 3], { hello: 'world' }); , it saves it for later. This comes incredibly helpful when you need to see what certain object values were during that action.

The next line is creating the history array, if it doesn’t already exist, on the original object and initializing it with an empty array. Not too much happening there.

Next, we are wrapping the necessary functions that are on the $log  service. Right now, those are log, info, warn, error, and debug. The function check is a safeguard in case any of those aren’t actually functions or if I somehow mistype something. It’s not completely necessary, but keeps it from creating functions where they aren’t needed. Then we are calling the wrapper to create new functions that will retain the history. Simple!

From there, you can continue to use the $log  service the same as you always have. The only difference now is that there’s a history  property that has a traceable history of each time any of those functions were called.

Where does this become useful?

Being able to track a user when an error occurs is always great information to have. I altered the  $exceptionHandler to log my database-backed system on the server. It makes an AJAX call with the exception and some other information. As stated before, I knew what the error was, but didn’t know how it was caused.

Here’s how I integrated this into the $exceptionHandler :

Now my logs become more informative when an error happens on the client. I also make sure to clear out the history after it gets written so that future errors have their own trace. I’m using jQuery here to do the sending of data, but you can also inject Angular’s  $http module to do the call.

I would urge you to make sure the history is cleared at other points in your app. Eventually, that array could grow to a point where your app starts to slow down because of memory usage. Just something to be aware of.

Go Forth and Conquer

Hopefully you find this little technique useful. Being able to see the steps a user took to create an error has allowed me to squish a fair number of those ‘digest already in progress’ errors. The time stamps on each step allow me to see how long they took between each step which may help in debugging in its own right.