Email Updates RSS Subscribe
Line

This blog is created and maintained by the technical team at Hook in an effort to preserve and share the insights and experience gained during the research and testing phases of our development process. Often, much of this information is lost or hidden once a project is completed. These articles aim to revisit, expand and/or review the concepts that seem worth exploring further. The site also serves as a platform for releasing tools developed internally to help streamline ad development.

Launch
Line

Hook is a digital production company that develops interactive content for industry leading agencies and their brands. For more information visit www.byhook.com.

Line

Logs: They're better than bad, they're good!

Line
Posted on April 5th, 2010 by Jake
Line

AS3:
Download Library
Download Full Example
Download Documentation

AS2:
This version is a bit crippled due to the fact that we can’t get a direct stack trace from the Error class.
For A specific list of missing features, please see the bottom of this post:
Download AS2 Library
Download AS2 Full Example

Ok, I’ll be the first to admit… logging isn’t the most exciting topic out there especially compared to some of the other hotness on this site:
Kutout – An application for cutting out images and Fuzzy Physics – 3.1: Rigid Body Dynamics, pt 1

But it is one of those things that can be helpful for debugging. Now, Flash’s trace() does its thing, and its fine, but many times its not really adequate for the real tricky bugs. Everyone knows this and everyone talks about making a better system, but like I said, there isn’t much glory to be had so it usually doesn’t get written. So we made one for you!

The thing that sort of kicked this all off was when we stumbled across dtrace.as from the folks at BreakTryCatch (http://www.breaktrycatch.com/). They had a great idea to get access to the stacktrace at the current point of execution in the code. Make a new Error object and call the getStackTrace() method on that Error object. This will give you all the info you need to make better and more useful output. The key is to take that stack trace, and parse it down into the bits you need. So we took parts of the dtrace code and added a bunch of features and convenience bits to it so everyone can log until their hearts are content.

So what are these features I hear you ask? (I swear its not the voices this time)

  • Logging Levels that you can filter your output with
  • Verbose Levels that you can customize your output with
  • Log Targets that will allow you to write to the browser console, text fields, normal flash output, and whatever else you want
  • Output enabling and disabling
  • Displaying a stack trace and any point in the code without throwing an error.

An example output could look like this:

The line of code to produce this looks like this:

Log.log("This is an Info output");

The first section of the output is the Logging or Debug level. Currently there are four different levels:

DebugLevel.INFO
DebugLevel.WARNING
DebugLevel.ERROR
DebugLevel.STACKTRACE

And there is a convenience setting

DebugLevel.ALL

The next part of the output is the time the log method was called in the code: Minutes:Seconds:Milliseconds from the start of execution of the swf.

The third section is the class name of the calling method, the method where the Log call was issued, and lastly (if “Permit Debugging” is turned on for the swf) the line number the Log call was issued.

The final section is the arguments that were passed to the Log.log() call.

Now that we know what the output can look like, lets talk about how to customize it.

There are two main classes for logging things. First is the Logger class, which is just a singleton that does most of the heavy lifting, and the Log class which is utility class used to access the Logger singleton. The Logger singleton should never be accessed directly, you should always go through the Log class.

The first option for customizing your output is to filter on different Debug Levels. To set which debug levels are shown in the output you can set the filter as follows:

Log.setLevelFilter(DebugLevel.WARNING | DebugLevel.ERROR);

The Logger will now only show output that is a WARNING or an ERROR. If you want to show all Debug levels you can use:

Log.setLevelFilter(DebugLevel.ALL);

Now in order to output things at a specific level you can use the following methods:

Log.log("This is a DebugLevel.INFO output");
Log.logWarning("This is a DebugLevel.WARNING output");
Log.logError("This is a DebugLevel.ERROR output");
Log.logError("This error, throws an exception", true);            //Notice the last parameter can be set to true in order to throw an actual error.
Log.stackTrace("This is a forced stack trace at the DebugLevel.STACKTRACE output level.");

The next way of customizing your output is to use the Verbose Levels. These allow you to include or exclude different parts of the output.
For instance:

Log.setVerboseFilter(VerboseLevel.CLASS | VerboseLevel.FUNCTION | VerboseLevel.LINE);

Will produce:

[LogTesterMain::handleAddedToStage():45] This is an Info output

Notice that the Debug Level, Time, and Class Path sections are missing. Things included in the bit mask filter will be shown in the output, the other sections will be ignored.
The available Vebose Levels are:

  • VerboseLevel.NORMAL
    this only shows the passed in arguments, akin to the standard trace()
  • VerboseLevel.CLASSPATH
    this will show the qualified class path of the class where the Log method was called.
  • VerboseLevel.CLASS
    this will show the class name of the method that called the Log method.
  • VerboseLevel.FUNCTION
    this will show the name of the function that called the Log method.
  • VerboseLevel.LINE
    this will show the line number of the Log method, assuming that “permit debugging” is turned on in the publish settings for the swf.
  • VerboseLevel.TIME
    this will show the amount of time that has passed since the start of execution of the swf up to the Log call.
  • VerboseLevel.LEVEL
    this will show the Debug Level that the output was set to.

As with the DebugLevels there is also a convenience VerboseLevel.ALL that will show all available sections.

The final way of customizing your output is to decide where your output goes. In this system, these places are called LogTargets. Included targets are:

  • TraceTarget
  • BrowserConsoleTarget
  • TextFieldTarget
  • MonsterDebuggerTarget

Creating your own targets however is trivial, as they simply need to comply with the ILogTarget interface, which consists of three methods:

function output(...args):void;
function get enabled():Boolean;
function set enabled(value:Boolean):void;

To add a new LogTarget to the Logger you can do the following:

Log.addLogTarget(new TraceTarget());
Log.addLogTarget(new TextFieldTarget(_testField));
Log.addLogTarget(new BrowserConsoleTarget());

This will add three new targets to the system. Any time any of the Log.log() type methods are called, all three of those targets will have their output() method called. The formatted output will be passed into that call, for the target to do whatever it wants to with that data.

The TraceTarget class simply calls trace() with the output that was passed to it.

The TextFieldTarget class takes a TextField passed to the constructor which it then uses to append output to.

The BrowserConsoleTarget uses JavaScript injection to set up a function that will log out to the browser console, assuming the browser has a console to write to. If the browser does not, (for instance IE) then it just ignores the call. To find out more about JavaScript injection, there is a great write up here: http://www.actionscript.org/resources/articles/745/1/JavaScript-and-VBScript-Injection-in-ActionScript-3/Page1.html

When you are making your own LogTargets you may also want to dispatch a

LogEvent.TARGET_UPDATED

if you want to stay consistent with the target classes we wrote.

The last feature is a simple one. You can enable and disable output by calling

Log.enable(true)

This will turn logging on and Log.enable(false) will turn logging off. You can also enable and disable specific LogTargets by calling

myLogTarget.enabled = true

(or false to disable it).

That pretty much covers it. As always, if you have any questions or issues or whatever, please leave a comment!

*** NEWLY ADDED FEATURES ***
We have recently added the ability to “tag” logs, and filter by tag.

To filter by tags, we first need to set the list of tags we care to see. This can be done in a couple of ways. The first is the Log.addTag() method and the second is the Log.setTagFilterList():

Log.setTagFilterList(["@test", "@test3", "@warnTagTest"]);
Log.addTag("@test");
Log.addTag("@testTag");

Please note that all tags must start with an “@” sign.

Next we set whether or not we want to see logs that are un-tagged:

Log.showUntagged(true);

That will show logs that don’t have tags, in addition to the logs that match our tag list.

Lastly we make a log call that has a tag:

Log.log("This is a tagged log", "@testTag");

As long as the tag string is the last argument passed in, and it starts with an “@” sign, it will be treated as a tag.

Now, if the tag list is empty, then all tags are shown, and if a log has a tag that is not in the list, it will not be shown.

*** MISSING AS2 FEATURES ***
A minor change that was made is the main log call. Log.info() is used instead of Log.log in the AS2 version.

The major feature that is missing is the ParsedStackTrace object. With is missing we are unable to display third section of the log, which contains:
Class Name
Class Path
Function Name

The timing of the log is also slightly different for the AS2 version. In the AS3 version the log time is grabbed at the beginning of the log cycle and stored way. In the AS2 version, the time is newly grabbed for each log call. All this means is that the times in the AS2 calls will be slightly different than the AS3 calls.

Line
4 Responses to “Logs: They're better than bad, they're good!”
  1. Excellent faceook Blog topic every one can get lots of information for any topics from this blog nice work keep it up.

  2. [...] example is built on top of the library we started with the other Facebook Post as well as with our Logging Library which can be found here on the labs site. There are a few improvements that we have made to the [...]

  3. [...] The Log Collector gathers all of the log statements produced from the swf being tested. To make use of this however, you will need to use our Logging Library, and the LCTarget log target. You can grab the library here: http://labs.byhook.com/2010/04/05/logs-theyre-better-than-bad-theyre-good/ [...]


Leave a Reply

*

Line
Line
Pony