Hack 81 Debug with trace( )

figs/moderate.gif figs/hack81.gif

The trace( ) action displays text in the Output panel. Use the trace( ) action to maximum effect as a debugging tool.

Although the debugger (WindowDevelopment PanelsDebugger and ControlDebug Movie) is useful for real-time debugging, it is often easier to use the trace( ) action to display output in the Output panel. However, trace( ) accepts only one expression for output. To display more (and more useful data), use string concatenation (the + operator) to build a more complex expression for output.

Suppose you want to output information on the following data:

var x:Number = 10;

var y:Number = 20;

var z:Array = [10, 20, 30, 40];

var w:Object = {p1:10, p2:"hello", p3:true};

If x and y contain coordinates, you might display them in (x, y) format on a single line using:

trace("(" + x + ", " + y + ")");

which displays:

(10, 20)

You can use multiple trace( ) statements or the "\n" escape sequence to split the output over more than one line. This:

trace("x is: " + x);

trace("y is: " + y);

and this:

trace("x is: " + x + "\n" + "y is: " + y + "\n");

both display:

 x is: 10

 y is: 20

When working with arrays, simply tracing the array (i.e., passing the array to the trace( ) function) will display a list of all the elements in the array. Assuming the earlier value assigned for z, this code:

trace(z)

displays:

10,20,30,40

Notice that there are no spaces in the output display for array contents. To format the output in a more appealing manner, you can specify a delimiter using the Array.join( ) method:

trace (z.join(", ");

which displays:

10, 20, 30, 40

This code:

trace (z.join("\n");

adds line breaks between items:

10

20

30

40

When working with objects, you need to use a for...in loop to view the enumerable properties of the object. Assuming the earlier value assigned for w, this code:

for (var i in w) {

  trace("w." + i + " = " + w [i]);

}

displays:

w.p1 = 10

w.p2 = hello

w.p3 = true

Note that the nonenumerable properties (such as built-in methods and properties that ActionScript has hidden) can be displayed using the undocumented ASSetPropFlags( ) function [Hack #82] .

Often your ActionScript doesn't do what you hoped and you don't know why. The culprit is often an invalid instance (you think that a variable holds a valid movie clip or object instance when in fact it does not), which could be caused by a programming error or because you mistyped (or forgot) the instance name in the Properties panel. Unfortunately, the Flash Player fails silently if it can't perform an operation because the specified instance is invalid. This can be a difficult problem to debug because:

  • It usually occurs when you are creating movie clips dynamically or when you have a full timeline hierarchy, so the debugger may be too cluttered to make the problem apparent.

  • Although the instance may be shown in the debugger, it may not have existed at the start of the frame, or the variable may not have the scope you expect. To debug this type of problem with the debugger, you have to set breakpoints and manually step through the code, line by line, which can be time consuming.

An easier way to see whether your instance is valid at the point your code expects it is to use a trace( ) debugging statement of the form:

for (var i in this) {

  if (i.indexOf("myClip", 0) != -1) {

    trace(myClip._name + " is on timeline " + this);

  }

}

If the instance myClip can be seen on the main timeline, the line will display "myClip is on timeline _level0" in the Output panel. Otherwise, it will display nothing. Notice that the output message is very precise about what was found and where, the hallmark of a good debug message. The message "found it!" may not mean that much six months down the line. Similarly, make sure that each of your trace( ) statements prints out different text to distinguish which trace( ) statement was reached. For example, this code displays the type of the incoming argument. If incoming is an object, it displays, "Incoming object in checkObject( ) is of type: object."

function checkObject(incoming) {

  trace("Incoming object in checkObject( ) is of type: " 

    + typeof incoming);

}

You can add an identifying string and a ">" to your trace( ) messages in order to make the program's execution and results easier to understand:

survey.fla > Starting up.

xmlutils   > Loaded.

view       > Loaded. Let's draw  the display.

display    > Drawing.

Final Thoughts

Debugging information is usually required at authoring time only, and you can force Flash to omit all trace( ) actions by checking the Omit Trace Actions option under FilePublish SettingsFlash. This prevents trace( ) statements from being exported and is the same as globally commenting out all trace( ) statements in the FLA.

For more complex debugging and to prevent being overwhelmed by the output from trace( ) statements, you can create a custom, centralized tracing function. Then, you can manually comment out the body of the debugging function when you publish the final site. (For optimal performance, you could comment out each individual function invocation.)

The following code shows a simple system to assign a verbosity level to debugging messages. Debugging messages are queued using the function cTrace(message, priority). If priority is below the verboseLevel threshold, the message is not displayed in the Output panel. In the following example, both messages are seen if you set verboseLevel to 0, but only the first is seen if you set verboseLevel to 1.

cTrace = function (message, priority) {

  if (priority >= verboseLevel) {

    trace(message);

  }

};

// Usage:

verboseLevel = 1;

cTrace("Important message", 1);    // Displayed

cTrace("Low-priority message", 0); // Not displayed

Another enhancement would be to create message filtering. For example, if you have a file with many errors, you may want to fix the most important issues first, followed by the less important ones. The following code hides all messages that are of a lower priority than the last most important one. This allows you to hone in on the debug information that is most likely needed to fix your code. In the following example, the last message is not seen because a higher priority error appears to be the one causing the problem.

For example, if the very important message was, "XML file not loading," the less important message, "Unexpected characters found in XML file," would be filtered out until you have the XML loading in the first place!

cTrace = function (message, priority) {

  if (priority >= verboseLevel) {

    verboseLevel = priority;

    trace(message);

  }

};

// Usage:

verboseLevel = 0;

cTrace("XML file not loading", 2);

cTrace("Unexpected characters found in XML file", 1);

Finally, you can also output messages using text fields if you want to test outside the authoring environment (such as in the browser). The following code modifies the previous listing to redirect diagnostics information to a text field instance, myText, presumed to exist on the Stage (changes are shown in bold). The easiest way to stop such output is to change the layer the text field is on into a guide layer.

cTrace = function (message, priority) {

  if (priority > verboseLevel) {

    verboseLevel = priority;

    myText.text += message + "\n";

  }

};