Long, long ago, I posted about my old TraceManager class for supreme debugging, but it was flawed! Hans from ObjectPainters was kind enough to comment with a link to a similar project he had put together. His did not have as much sophistication in its data tracing, but it did have a “FunctionWrapper.” His FuncitonWrapper could modify existing functions in run-time (so you don’t have to) allowing his tracing capabilities to be applied to any function without requiring the programmer to modify actual class files.

Hans was right about the usefulness of a function wrapper, but I didn’t feel like getting into it . . . until now. A couple days ago I brought up my old TraceManager and decided it was time to revamp it.

//Wrap class
traceManager.wrapClass(testClass , “testClass”)
//Run class function
var diff:Number = testClass.Subtract(6 , 3 , “trace:Infinity”)

The testClass.Subtract() function above was not capable of producing sophisticated trace data until the traceManager.wrapClass modified it and every other function in the testClass class.

I’ve taken Hans’ proposal one step further, by creating a ClassWrapper (using the undocumented ASSetPropFlags) that will automatically apply tracing capabilities to all functions within a given class instance. Finally, I feel the TraceManager to be a tool that all actionscripters could use in any project:

TraceManager.zip

I’ve added those 2 new functions, modified formatting a bit, and made a few other slight adjustments. If you used the previous version you probably will barely notice the differences outside of the 2 new wrapper functions. For a review on the basic ideas check out the original post. Now I give you an example of a trace out and will explain use of the new wrappers.

The formatting here makes it look a little wobbly, but I assure you the actual trace out is nice and neat.

TraceManager: traceManager
_________________________________________
Time(seconds):      Depth:  Function:
—————————————–
0.001                   +0       testClass:Subtract : (6,3){
0.001                   +1       .    testClass:LoopFunctions : (6,3){
0.001                   +2       .    .    testClass:Conditional : (6,3,0){
0.001                   +3       .    .    .    testClass:Increment : (3){
0.001                   -3       .    .    .    } (4)
0.001                   +3       .    .    .    testClass:Increment : (0){
0.001                   -3       .    .    .    } (1)
0.001                   -2       .    .    } (4,1)
0.001                   +2       .    .    testClass:Conditional : (6,4,1){
0.001                   +3       .    .    .    testClass:Increment : (4){
0.001                   -3       .    .    .    } (5)
0.001                   +3       .    .    .    testClass:Increment : (1){
0.001                   -3       .    .    .    } (2)
0.001                   -2       .    .    } (5,2)
0.001                   +2       .    .    testClass:Conditional : (6,5,2){
0.001                   +3       .    .    .    testClass:Increment : (5){
0.001                   -3       .    .    .    } (6)
0.001                   +3       .    .    .    testClass:Increment : (2){
0.001                   -3       .    .    .    } (3)
0.001                   -2       .    .    } (6,3)
0.001                   -1       .    } (3)
0.001                   -0       } (3)

0.004                   +0       function1 : (test1){
0.004                   +1       .    function2 : (test1 1){
0.004                   +2       .    .    function3 : (test1 1 2){
0.004                   -2       .    .    } (test1 1 2 3)
0.004                   -1       .    } (test1 1 2 3)
0.004                   -0       } (test1 1 2 3)

0.005                   +0       function1 : (test2){
0.005                   +1       .    function2 : (test2 1){
0.005                   -1       .    } (test2 1 2 3)
0.005                   -0       } (test2 1 2 3)

0.005                   +0       function1 : (test3){
0.005                   -0       } (test3 1 2 3)

This is the trace out you should get after compiling the TraceManager Test fla (contained in TraceManager.zip). The testClass functions listed at the top are used in an unnecessarily complex attempt to subtract the second argument from the first. Obviously a class is overkill for subtraction, but it shows the results of the class wrapper. In the example above, the testClass is used to find 6 – 3 = 3. As you can see, the first arguments are (6,3) and the result displayed at the end of the function is (3). The traceDepth given to the testClass:Subtract function is “trace:Infinity” so every nested function is traced.

Before these traces could be created, the testClass instance had to be updated for tracing using the classWrapper. The following details that portion of the code:

//Importing and initializing TraceManager at the _root level.
import TraceManager
var traceManager:TraceManager = new TraceManager(“traceManager” , true , 0 , undefined , getTimer() / 1000)

//Import new class
import TestClass
//Create class instance
var testClass:TestClass = new TestClass ()
//Wrap class
traceManager.wrapClass(testClass , “testClass”)

//Run class function
var diff:Number = testClass.Subtract(6 , 3 , “trace:Infinity”)

The next group of function traces are due to a single function being run multiple times with different traceDepth values. The first traceDepth is 3, the next is 2, next is 1, and after one is run with a value of 0 and another with a value of undefined. The 0 and undefined values are not traced, so only 3 versions are visible above. As you can see, each trace from function1 displays fewer nested functions than the one before it.

The following is the code that led to the 2nd half of the trace out:

//Defining new functions.
//////////////////////////////////////////////////
function function1(input){
var output = input + ” 1″

output = function2(output)

return output
}

function function2(input){
var output = input + ” 2″

output = function3(output)

return output
}

//This is the last function, with no nested functions in it.
function function3(input){
var output = input + ” 3″

return output
}

//Wrapping functions.
function1 = traceManager.wrapFunction(function1 , “function1”)
function2 = traceManager.wrapFunction(function2 , “function2”)
function3 = traceManager.wrapFunction(function3 , “function3”)

//Running functions
function1(“test1” , “trace:3”)
function1(“test2” , “trace:2”)
function1(“test3” , “trace:1”)
function1(“test4” , “trace:0”)
function1(“test5”)

Notice that these functions were wrapped individually because they were not contained in a class.

One of the added benefits of implementing the wrapper functions is that by flipping the TraceManager onSwitch variable to false, you can prevent the wrapper from engaging and therefore the TraceManager will be prevented from having any effect on your program. You don’t need to remove the code before  publishing, just set onSwitch to false, and TraceManager becomes completely harmless.

Anyway, I’m happy enough with its functionality that I’ll be working it into my standard procedure. Pretty soon I’ll finally be shifting my work to AS3 so there ought to be another version coming up fairly soon.

Let me know if you have any other ideas, Hans!

-Christopher J. Rock

About the author:
Christopher J. Rock (http://)
Film student at California State, Long Beach. I want to make the gaming world a better place.