Scripts, Tools & Methods Developed at Hook
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)
An example output could look like this:
[INFO] [0:00:788] [com.app.LogTesterMain::handleAddedToStage():45] This is an Info output
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
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:
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.
Log.setVerboseFilter(VerboseLevel.CLASS | VerboseLevel.FUNCTION | VerboseLevel.LINE);
[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:
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:
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.
When you are making your own LogTargets you may also want to dispatch a
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
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"]);
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:
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:
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.