Log Levels in Flash

One of the biggest problems with ActionScript 1.0, as we all know, is the lack of both compile- and run-time validation. Make some small typo, omit a “this”, or get your scoping mixed up inside of a callback, and you’re looking at anywhere from 5 minutes to hours of hunting through your code line by line, if not character by character, trying to figure out why your application is not behaving as expected. One solution is to use ActionScript 2.0, however for those instances when 2.0 is not an option, here are some debugging tips.

First, check out Mike Chamber’s post entitled “Detecting Misspelled Variable Names in ActionScript” which discusses the use of __resolve to trap errors. Second, trace liberally, and use log levels.

I have gotten in the habit of putting a trace at the top of every function, like this:

Foo.prototype.getSomething = function(){trace("Foo.getSomething()");};

If arguments are passed in, I might even trace those out, as well. This kind of tracing, or logging, basically gives you a very detailed trail to follow when debugging your applications. I have even seen people in the Java world log leaving every function as well as entering it. That’s a little extreme for my taste, but I do admit to seeing the value.

The problem is that this level of logging can get very verbose very quickly, and is often much more than you need, especially in the latter stages of building your application when 1) you have a lot of functions and function calls in place, and 2) the app is already working well enough that you usually don’t need to follow its execution function by function. At this point, you usually just want to see specifics, and you don’t want to read through hundreds of traces to find the one piece of output you are looking for.

To handle this issue, I started using “log levels”. Log levels let you control the verbosity of your output, and scale it back or crank it up in order to suite the kind of debugging you need to do. This is a common practice in the Java world, especially with logging packages like log4j. A Flash solution, however, needs to be very lightweight so as not to add unnecessary overhead and increasing file size significantly.

The solution I came up with involves “tagging” all you trace messages with one of two labels: either “verbose” or “debug”. (So far, I have found that using only two log levels is sufficient, however there is no reason you couldn’t use more.) The syntax of my trace statement now look like this:

trace(log("Foo.getSomething()", this.VERBOSE));trace(log("Foo.getSomething(): first arg: " + myArg, this.DEBUG));

The log function is in the logging classes superclass (called “Screen”). Screen contains the following code:

Screen.prototype.DEBUG = 0;Screen.prototype.VERBOSE = 1;Screen.prototype.LOG_LEVEL = this.DEBUG;Screen.prototype.log = function(msg, level){if (this.LOG_LEVEL >= level){return msg;}};

When my LOG_LEVEL variable is set to DEBUG (or 0), I only see “debug” messages, and when it’s set to VERBOSE (or 1), I see both debug and verbose messages. The more “restrictive” or specific the log message, the lower the constant value should be. For instances, if I wanted to add an “info” level, my variables would look like this:

Screen.prototype.INFO = 0;Screen.prototype.DEBUG = 1;Screen.prototype.VERBOSE = 2;

Nesting the call to “log” inside the trace function may seem unnecessarily complicated as opposed to something like this:

Call to log:

log("Foo.getSomething()", this.VERBOSE);

Log implementation:

Screen.prototype.log = function(msg, level){if (this.LOG_LEVEL >= level){trace(msg);}};

The reason I chose to do it the seemingly more complex way is so that I can remove all my debugging statements from my entire application (and all the overhead they create) just by checking the “Omit trace actions” checkbox under Publish Settings. Not only are the trace statements removed, but so is everything contained within them, so the call to log() is gone, as well as the sometimes very long strings being created to send to the log function. The only thing left in the movie is the log function itself, which is small enough to be negligible.

This appears to be an extremely ideal logging solution since it gives you fine-grained control over the quality and amount of logging messages without adding any overhead to production code.