Application Debugging: Chapter 18 - Programming Flex 3
Pages: 1, 2

Section 18.5: Logging Using trace() Within an Application

Although not an advanced debugging technique, at one time or another a developer will find a need to trace (also referred to as log) messages from within an application. For this purpose, Flash Player exposes a global trace() method. You can log messages from anywhere within an application simply by calling the trace() method and passing any parameter of type string:

trace("application initialized");

Trace messages are typically displayed by attaching the debugger to an application. With an active FDB debug session, trace messages will be displayed in the console. With Flex Builder, launching a debug session will automatically do this and trace messages will be shown in the Console panel in the debugging perspective (see ).

Example
Figure 18-6: Flex Builder Debugger Console panel

One of the great benefits of using the trace statement in this manner is the ability to receive the messages in real time while an application is running. The trace() method also supports passing in arrays or multiple arguments (rest-style arguments). This can be very useful in dumping data for informational purposes—for example, if you wanted to be able to easily track what children are currently in the Display Child list.

Example 18-1 contains two children. When you click the buttonOne button, the function is called and an array of children is displayed in the output window.

Example 18-1. Calling the clickHandler() function

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
        <![CDATA[

            private function clickHandler():void
            {
                trace("Childrent: "+this.getChildren());
            }

        ]]>
    </mx:Script>
    <mx:Button id="buttonOne" click="clickHandler()" label="Dump Data"/>
    <mx:Label id="labelTwo"/>
</mx:Application>

As with other debugging methods we have seen thus far, using the trace() function requires the Flash Debug Player. Although often you will just use the Flex Builder Debugger to output trace messages, with the debug version of the player you have the option of outputting the trace messages to a file. You may want to use this feature if you are having a hard time isolating user-reported bugs by having the user configure his machine to log all trace calls to a file and allow you to review the logfiles at a later time for clues on what sequence of events may have caused the bug. This also is useful for when a tester isolates a bug in an application and provides corresponding log .

By default, installing the Debug Player does not enable trace logging. You will need to configure the player to enable logging. The configuration filename is mm.cfg. Under Windows XP it is located at C:\Documents and Settings\<user_name>, on Windows Vista it is located at c:\users\<user_name>, on Linux it is located at /home/<user_name>, and under Mac OS X it is located at /Library/Application Support/Macromedia/. For other operating systems and a full list, consult the Flash Player .

Note: As of this writing, the Flash Player documentation relating to debugger configuration was available at http://livedocs.adobe.com/flex/3/html/help.html?content=logging_04.html. The paths to both mm.cfg and can change with different versions of Flash Player. It is advisable that you review the latest documentation on where such files are located according to the player version you are using if you are having difficulty making the examples in this section work.

First review your operating-system-specific path for an existing mm.cfg. If none already exists, you will need to create one in the location appropriate for your operating system. The configuration file is a plain-text file that supports several options. Most important, you will be interested in the ErrorReportingEnable, MaxWarnings, and configuration properties.

A basic mm.cfg file that enables the trace output includes the following:

TraceOutputFileEnable=1

Once the configuration file is updated and saved to the proper location with the filename mm.cfg, the Flash Debug Player will log trace messages to flashlog.txt in the folder specific to your operating system. Under Windows XP, it will be located at , under Windows Vista it is at C:\Users\<username>\AppData\Roaming\Macromedia\Flash Player\Logs, under Mac OS X it is at /Users/<username>/Library/Preferences/Macromedia/Flash Player/Logs/, and under Linux it is at /home/<username>/.macromedia/Flash_Player/Logs/.

Along with enabling trace logging, the Debug Flash Player can also log all runtime errors to the same logfile. You can enable error reporting using ErrorReportingEnable:

TraceOutputFileEnable=1
ErrorReportingEnable=1

Section 18.6: The Logging Framework

The trace() statement can be a powerful method of logging, but if you have been exposed to logging in the past, you likely used some sort of logging framework or built your own. Flex includes a logging framework that offers several benefits over using the trace() statement alone.

The logging framework consists of two main components: the logger and the target. The logger is used by an application to configure the logging framework and to send messages that are output via a target.

A target is used to specify where log messages are output. They can be output to any mechanism that Flash Player supports. The logging framework includes a , which inherits from LineFormattedTarget and AbstractTarget and implements the ILoggingTarget interface.

TraceTarget internally sends messages via the global trace() function. This will often be the target you use. Here's an example using the logging framework with TraceTarget:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initializeHandler()">
        <mx:Script>
        <![CDATA[
            import mx.logging.Log;
            import mx.logging.targets.TraceTarget;

            private var _target:TraceTarget;

            private function initializeHandler():void
            {
                _target = new TraceTarget();
                _target.includeTime = true;
                _target.includeLevel = true;
                _target.includeCategory = true;
                Log.addTarget(_target);
            }

            private function sendToLog():void
            {
                Log.getLogger("com.oreilly.programmingflex.MainClass").info("Log
Message");
            }
        ]]>
    </mx:Script>
    <mx:Button click="sendToLog()" label="Log Message"/>
</mx:Application>

In this example, clicking on a button will send a message in the same manner as calling trace() would. The main distinction to just using trace() is the ability to configure the target to include extra information, define a category for a message, and have different levels of errors.

Note: The Flex framework internally uses the logging framework within the mx.rpc.* package with the WebService, RemoteObject, and HTTPService components. This allows you to retrieve details of the communication between the Flex client and the server. We will cover debugging remote data communication later in this chapter.

A target can support extra functionality. In the preceding example, the date, category, and level were enabled. This will instruct the target to include the time, category of message, and level with the messages. The built-in targets support other properties that you may want to explore.

Specifying the Logging Options

A log message must define two values: the level of the message, which we discussed, and the category. The category is required to define the origins of a message and, in return, allow you to filter what is displayed by the logging framework. In the preceding example, the category was com.oreilly.programmingflex.MainClass. It is a good idea to specify a category based on the package and class, as this will allow you to easily filter and identify the origins of logged messages.

The built-in targets support the ability to filter the messages so that only messages you are interested in are displayed. This is useful in cases where you're interested only in log messages that are within a certain package, and it's achieved via the filters property of the target. The filters property accepts an array of categories. A category filter can be any text value, but it is recommended that you follow package-naming conventions. You may also specify an * (wildcard) filter—for example, the following category filter of com.oreilly.* will instruct the target to output all messages in the com.oreilly package and within its subpackages:

_target.filters = ["com.oreilly.*"];

You also can define multiple filters as well as redefine the filters at any time. Setting the level is achieved in a similar manner.

The default logging level is ALL, but you can define another level by setting the level property:

_target.level = LogEventLevel.FATAL;

The logger supports sending several levels of messages with the debug(), info(), warn(), error(), and fatal() methods. Alternatively, you can call the log() method of the logger and pass in a log level. You can find the different levels with the constant values LogEventLevel.FATAL, LogEventLevel.ERROR, LogEventLevel.WARN, LogEventLevel.INFO, and LogEventLevel.DEBUG. This can be useful if you want to output all messages during development and debugging, but limit what is output in a production environment. When you set a log level, all messages in that level and above are logged. For example, setting the level to WARN will log all messages with that level as well as messages with a FATAL or ERROR level.

Defining a Custom Target

If the built-in targets are not sufficient, you can define your own. To define your own target you need to implement the ILoggingTarget interface. For convenience, the logging framework includes the AbstractTarget class, which already implements a default set of behaviors that you can easily subclass to define your own target. Example 18-2 is a custom target that will send a message to a remote server via the Socket class rather than via trace().

Example 18-2. Custom target sending a message to a remote server via the Socket class

package com.oreilly.programmingflex.logging.targets
{
    import flash.net.Socket;
    import mx.logging.LogEvent;
    import mx.logging.AbstractTarget;

    public class SocketTarget extends AbstractTarget
    {
        private var _host:String;
        private var _port:int;
        private var _socket:Socket;

        public function SocketTarget(host:String = "localhost",port:int = 18080)
        {
            _host = host;
            _port = port;
            //This example omits the error handling. For production you will
            //need to handle errors when creating the socket and when sending
            //messages
            _socket = new Socket(host,port);
            super();
        }

        override public function logEvent(event:LogEvent):void
        {
            _socket.writeUTF(event.message);
            _socket.flush();
        }
    }
}

Example 18-3 is updated to use the new SocketTarget.

Example 18-3. Example 18-2 updated to use the new SocketTarget

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initializeHandler()">
    <mx:Script>
        <![CDATA[
            import com.oreilly.programmingflex.logging.targets.SocketTarget;
            import mx.logging.Log;

            private var _target:SocketTarget;

            private function initializeHandler():void
            {
                _target = new SocketTarget();
                Log.addTarget(_target);
            }

            private function sendToLog():void
            {
                Log.getLogger("com.oreilly.programmingflex.MainClass").info("Log
Message");
            }
        ]]>
    </mx:Script>
    <mx:Button click="sendToLog()" label="Log Message"/>
</mx:Application>

With Flex's built-in logging framework, you will be able to log messages, easily change options so that you can more easily debug an application, and integrate the framework within your application.

Section 18.7: Debugging Remote Data

Although you can use the debugger to inspect data after Flex has received it and before Flex sends it, you may want to find out more details regarding what data is being sent and received. You can achieve this by using the logging framework or a data inspector.

Debugging with the Flex Logging Framework

The WebService, HTTPService, and RemoteObject components use the Flex logging framework, which can greatly assist debugging applications. Messages are automatically logged to the Flex logging framework, so you won't need to enable the components to explicitly begin logging. Messages that are logged are within the mx.messaging.* filter. Example 18-4 is an HTTPService call with a TraceTarget that will show only log messages related to the server calls.

Example 18-4. HTTPService call with a TraceTarget that shows log messages related to server calls

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initializeHandler()">
        <mx:Script>
        <![CDATA[
            import mx.logging.Log;
            import mx.logging.targets.TraceTarget;

            private var _target:TraceTarget;

            private function initializeHandler():void
            {
                _target = new TraceTarget();
                _target.includeTime = true;
                _target.includeLevel = true;
                _target.includeCategory = true;
                _target.filters = ["mx.messaging.*"];
                Log.addTarget(_target);
            }

            private function sendToLog():void
            {
                Log.getLogger("com.oreilly.programmingflex.Logging").
info("Log Message");
            }
        ]]>
    </mx:Script>
    <mx:Button click="sendToLog()" label="Log Message"/>
    <mx:Button click="service.send();" label="Send HTTPService"/>
    <mx:HTTPService id="service" url="http://www.w3c.org"/>
</mx:Application>

This example will log messages from the HTTPService but not from the button click handler, which can be very useful when you are working with a larger application and you are interested in viewing only the log information from the mx.rpc components. The server component logs useful information on both the data that is being sent and received, as well as the information that can be used for profiling messaging performance. For the WebService component, this can be especially useful in gauging Flex's performance in terms of serializing and deserializing SOAP messages.

Debugging Using a Data Inspector

When debugging network programming code, using a data inspector (packet sniffing tools or a proxy) is invaluable. With Flex, these tools can also be very useful. Adobe does not provide such a built-in tool, but many tools exist that work with Flex. If you are already comfortable with a tool, you can continue to use that tool.

Some common network debugging tools include the following:

Charles
This cross-platform proxy tool for debugging RPC communication also supports AMF3 (http://www.charlesproxy.com/).
ServiceCapture
This cross-platform proxy tool for debugging RPC communication supports AMF3 as well (http://kevinlangdon.com/serviceCapture).
Wireshark (similar to Ethereal)
This is a feature-complete packet sniffer that is capable of inspecting all traffic for both real-time applications as well as RPC (http://www.wireshark.org).
Fiddler
This is a quick HTTP proxy debugger that is free. It supports RPC debugging, but does not support AMF3 (http://www.fiddlertool.com).

Section 18.8: Summary

In many ways, a development platform is only as good as the debugging capabilities available to the developer. In this chapter, we covered many of the methods you can use to debug Flex applications.

This excerpt is from Programming Flex 3. If you want to try your hand at developing rich Internet applications with Adobe's Flex 3, and already have experience with frameworks such as .NET or Java, this is the ideal book to get you started. Programming Flex 3 gives you a solid understanding of Flex 3's core concepts, and valuable insight into how, why, and when to use specific Flex features. Learn to get the most from this amazing and sophisticated technology.

buy button