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 TraceTarget
, 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.
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.
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.
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.