The logging API lets an application capture
and write messages to a target’s configured output. Typically the
output is equivalent to the global trace() method,
but it can be anything that an active target supports.
The logging API consists of the following parts:
Logger
The logger provides an interface for sending
a message to an active target. Loggers implement the ILogger interface
and call methods on the Log class. The two classes
of information used to filter a message are category and level.
Each logger operates under a category. A category is a string
used to filter all messages sent from that logger. For example,
a logger can be acquired with the category “orange”. Any message
sent using the “orange” logger only reaches those targets that are
listening for the “orange” category. In contrast to the category
that is applied to all messages sent with a logger, the level provides additional
filtering on a per-message basis. For example, to indicate that
an error occurred within the “orange” subsystem, you can use the
error level when logging the message. The supported levels are defined
by the LogEventLevel class. The Flex framework classes that use
the logging API set the category to the fully qualified class name
as a convention.
Log target
The log target defines where log messages
are written. Flex predefines a single log target: TraceTarget,
which is the most commonly used log target. This log target connects
the logging API to the trace system so that log messages are sent
to the same location as the output of the trace() method.
For more information on the trace() method, see Using the global trace() method.
The
destination is where the log message is written. Typically, this is
a file, but it can also be a console or something else, such as
an in-memory object. The default destination for TraceTarget is
the flashlog.txt file. You configure this destination on the client.
The
following example shows a sample relationship between a logger,
a log target, and a destination:
You
can also use the logging API to send messages from custom code you
write. You can do this when you create a set of custom APIs or components
or when you extend the Flex framework classes and you want users
to be able to customize their logging. For more information, see Implementing a custom logger with the logging API.
The following
packages within the Flex framework are the only ones that use the logging
API:
mx.rpc.*
mx.messaging.*
mx.data.*
To configure client-side logging
in MXML or ActionScript, create a TraceTarget object to log messages.
The TraceTarget object logs messages to the same location as the
output of the trace() statements. You can also
use the TraceTarget to specify which classes to log messages for,
and what level of messages to log.
The levels of logging messages are defined
as constants of the LogEventLevel class. The following table lists
the log level constants and their numeric equivalents, and describes
each message level:
Logging level constant (int)
Description
ALL (0)
Designates
that messages of all logging levels should be logged.
DEBUG (2)
Logs internal Flex activities. This is most
useful when debugging an application.
Select the DEBUG logging
level to include DEBUG, INFO, WARN, ERROR,
and FATAL messages in your log files.
INFO (4)
Logs general information.
Select the INFO logging
level to include INFO, WARN, ERROR,
and FATAL messages in your log files.
WARN (6)
Logs a message when the application encounters
a problem. These problems do not cause the application to stop running,
but could lead to further errors.
Select the WARN logging level
to include WARN, ERROR, and FATAL messages
in your log files.
ERROR (8)
Logs a message when a critical service is
not available or a situation has occurred that restricts the use
of the application.
Select
the ERROR logging level to include ERROR and FATAL messages
in your log files.
FATAL (1000)
Logs a message when an event occurs that
results in the failure of the application.
Select the FATAL logging
level to include only FATAL messages in your log
files.
The log level lets you restrict the amount
of messages sent to any running targets. Whatever log level you
specify, all “lower” levels of messages are written to the log.
For example, if you set the log level to DEBUG,
all log levels are included. If you set the log level to WARNING,
only WARNING, ERROR, and FATAL messages
are logged. If you set the log level to the lowest level of message, FATAL,
only FATAL messages are logged.
Using the logging API with data services
The
data services classes are designed to use the logging API to log
client-side and server-side messages.
Enable the logging API with data services
Create a TraceTarget logging
target and set the value of one or more filter properties to include
the classes whose messages you want to log. You can filter the log
messages to a specific class or package. You can use wildcards (*) when
defining a filter.
Set the log level by using the level property
of the log target. You can also add detail to the log file output,
such as the date and time that the event occurred, by using properties
of the log target.
When you create a target within ActionScript, call the Logclass’s addTarget() method
to add the new target to the logging system. Calling the addTarget() method
is not required when you create a target in MXML. As long as the
client is using the debugger version of Flash Player and meets the
requirements described in Configuring the debugger version of Flash Player to record trace() output,
the messages are logged.
The following example configures a TraceTarget logging target
in ActionScript:
<?xml version="1.0"?>
<!-- logging/ActionScriptTraceTarget.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="initLogging();"
height="600">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.logging.targets.*;
import mx.logging.*;
[Bindable]
public var myData:ArrayCollection;
private function initLogging():void {
/* Create a target. */
var logTarget:TraceTarget = new TraceTarget();
/* Log only messages for the classes in the mx.rpc.* and
mx.messaging packages. */
logTarget.filters=["mx.rpc.*","mx.messaging.*"];
/* Log all log levels. */
logTarget.level = LogEventLevel.ALL;
/* Add date, time, category, and log level to the output. */
logTarget.includeDate = true;
logTarget.includeTime = true;
logTarget.includeCategory = true;
logTarget.includeLevel = true;
/* Begin logging. */
Log.addTarget(logTarget);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- HTTPService is in the mx.rpc.http.* package -->
<mx:HTTPService id="srv"
url="../assets/trace_example_data.xml"
useProxy="false"
result="myData=ArrayCollection(srv.lastResult.data.result)"/>
</fx:Declarations>
<mx:LineChart id="chart" dataProvider="{myData}" showDataTips="true">
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="month"/>
</mx:horizontalAxis>
<mx:series>
<mx:LineSeries yField="apple" name="Apple"/>
<mx:LineSeries yField="orange" name="Orange"/>
<mx:LineSeries yField="banana" name="Banana"/>
</mx:series>
</mx:LineChart>
<s:Button id="b1" click="srv.send();" label="Load Data"/>
</s:Application>
The executing SWF file for the previous example is shown below:
In the preceding example, the filters property
is set to log messages for all classes in the mx.rpc and mx.messaging
packages. In this case, it logs messages for the HTTPService class,
which is in the mx.rpc.http.* package.
You can also configure a log target in MXML. When you do this,
though, you must be sure to use an appropriate number (such as 2)
rather than a constant (such as DEBUG) for the
log level.
The following example sets the values of the filters for a TraceTarget
logging target by using MXML syntax:
The executing SWF file for the previous example is shown below:
Implementing a custom logger with the logging API
If you write custom components
or an ActionScript API, you can use the logging API to access the
trace system in the debugger version of Flash Player. You do this by
defining your log target as a TraceTarget,
and then calling methods on your logger when you log messages.
The following example extends a Button control.
It writes log messages for the startup life cycle events, such as initialize and creationComplete,
and the common UI events, such as click and mouseOver.
// logging/MyCustomLogger.as
package { // The empty package.
import mx.controls.Button;
import flash.events.*;
import mx.logging.*;
import mx.logging.targets.*;
public class MyCustomLogger extends Button {
private var myLogger:ILogger;
public function MyCustomLogger() {
super();
initListeners();
initLogger();
}
private function initListeners():void {
// Add event listeners life cycle events.
addEventListener("preinitialize", logLifeCycleEvent);
addEventListener("initialize", logLifeCycleEvent);
addEventListener("creationComplete", logLifeCycleEvent);
addEventListener("updateComplete", logLifeCycleEvent);
// Add event listeners for other common events.
addEventListener("click", logUIEvent);
addEventListener("mouseUp", logUIEvent);
addEventListener("mouseDown", logUIEvent);
addEventListener("mouseOver", logUIEvent);
addEventListener("mouseOut", logUIEvent);
}
private function initLogger():void {
myLogger = Log.getLogger("MyCustomClass");
}
private function logLifeCycleEvent(e:Event):void {
if (Log.isInfo()) {
myLogger.info(" STARTUP: " + e.target + ":" + e.type);
}
}
private function logUIEvent(e:MouseEvent):void {
if (Log.isDebug()) {
myLogger.debug(" EVENT: " + e.target + ":" + e.type);
}
}
}
}
Within the application that uses the MyCustomLogger class, define
a TraceTarget, as the following example shows:
To log a message,
you call the appropriate method of the ILogger interface.
The ILogger interface defines a method for each log level: debug(), info(), warn(), error(),
and fatal(). The logger logs messages from these
calls if their levels are at or under the log target’s logging level.
If the target’s logging level is set to all, the
logger records messages when any of these methods are called.
To improve performance, a static method corresponding to each
level exists on the Log class, which indicates if any targets are
listening for a specific level. Before you log a message, you can
use one of these methods in an if statement to avoid
running the code. The previous example uses the Log.isDebug() and Log.isInfo() static
methods to ensure that the messages are of level INFO or DEBUG before
logging them.
The
previous example logs messages dispatched from any category because
the TraceTarget’s filters property is set to the
wildcard character (*). The framework code sets the category of
the logger to the fully qualified class name of the class in which
logging is being performed. This is by convention only; any String
specified when calling Log.getLogger(x) is the
category required in a filters property to receive
the message.
When you set the filters property for logging
within the Flex framework, you can restrict this to a certain package
or packages, or to other classes. To restrict the logging to your
custom class only, add the category specified when the logger was
acquired (“MyCustomLogger”) to the filters Array,
as the following example shows:
The wildcard character can appear only at the end of a value
in the Array.
The Log.getLogger() method sets the category
of the logger. You pass this method a String that defines the category.
Note: The Flex packages that use the logging API set
the category to the current class name by convention, but it can
be any String that falls within the filters definitions.
The value of the category must fall within the definition of
at least one of the filters for the log message to be logged. For
example, if you set the filters property to something
other than “*” and you use Log.getLogger("MyCustomLogger"),
the filter Array must include an entry that matches MyCustomLogger,
such as “MyCustomLogger” or “My*”.
You can include the logger’s category in your log message, if
you set the logger’s includeCategory property to true.
You can also use the ILogger interface’s log() method
to customize the log message, and you can specify the logging level
in that method. The following example logs messages that use the
log level that is passed into the method:
package { // The empty package.
// logging/MyCustomLogger2.as
import mx.controls.Button;
import flash.events.*;
import flash.events.MouseEvent;
import mx.logging.*;
import mx.logging.targets.*;
public class MyCustomLogger2 extends Button {
private var myLogger:ILogger;
public function MyCustomLogger2() {
super();
initListeners();
initLogger();
}
private function initListeners():void {
// Add event listeners life cycle events.
addEventListener("preinitialize", logLifeCycleEvent);
addEventListener("initialize", logLifeCycleEvent);
addEventListener("creationComplete", logLifeCycleEvent);
addEventListener("updateComplete", logLifeCycleEvent);
// Add event listeners for other common events.
addEventListener("click", logUIEvent);
addEventListener("mouseUp", logUIEvent);
addEventListener("mouseDown", logUIEvent);
addEventListener("mouseOver", logUIEvent);
addEventListener("mouseOut", logUIEvent);
}
private function initLogger():void {
myLogger = Log.getLogger("MyCustomClass");
}
private function logLifeCycleEvent(e:Event):void {
if (Log.isInfo()) {
dynamicLogger(LogEventLevel.INFO, e, "STARTUP");
}
}
private function logUIEvent(e:MouseEvent):void {
if (Log.isDebug()) {
dynamicLogger(LogEventLevel.DEBUG, e, "EVENT");
}
}
private function dynamicLogger(
level:int,
e:Event, prefix:String):void {
var s:String = "__" + prefix + "__" + e.currentTarget +
":" + e.type;
myLogger.log(level, s);
}
}
}