Flex in Application Logging
For an LCDS application that we are building, I wanted to be able to display log messages to the screen, such as "Sending request to server" and "Received server response: OK." Although this has little to do with actual functionality, I wanted to document my efforts to create this component.
To utilize the Flex logging framework, we need to provide a Logger and a Log Target. The Logger, of course, does the logging itself based on two factors: (1) its category and (2) the logging level. This is similar to the operation of the popular Java logging framework Log4J. The Log Target defines where the messages are written. Flex comes with the TraceTarget
predefined - this is the target for all trace()
statements. For this example, I will also provide an MXML component that can be used to display log messages on screen.
First, the Logger
class:
public class Logger
{
//~ Instance Attributes -----------------------------------------------
private var logger : ILogger;
//~ Constructor -------------------------------------------------------
/\*\*
\* SingletonEnforcer parameter ensures that only the getInstance
\* method can create an instance of this class.
\*/
public function Logger(category : String, enforcer : SingletonEnforcer) : void
{
this.logger = Log.getLogger(category);
}
//~ Methods -----------------------------------------------------------
public static function getInstance(category : String) : Logger
{
return new Logger(category, new SingletonEnforcer());
}
public static function addTarget(target : ILoggingTarget) : void
{
Log.addTarget(target);
}
public static function removeTarget(target : ILoggingTarget) : void
{
Log.removeTarget(target);
}
public function debug(message : String) : void
{
this.logger.debug(message);
}
// other logging methods by level (e.g. warn, error)
}
With our Logger
class in place, we can now define a LogTarget
class that defines a TextArea
to which the log messages will be written:
// be sure to use the mx\_internal namespace (and import it)
import mx.core.mx\_internal;
use namespace mx\_internal;
public class LogPanelTarget extends LineFormattedTarget
{
private var console : TextArea;
public function LogPanelTarget(console : TextArea)
{
super();
this.console = console;
}
override mx\_internal function internalLog(message : String) : void
{
this.console.text += message + "\\n";
}
}
}
Finally, our LogPanel
MXML component brings everything together by (1) instantiating a new Logger
and (2) providing a TextArea for log messages:
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
width="300" height="300" initialize="init()">
<mx:Script>
<!\[CDATA\[
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.collections.ArrayCollection;
public var open : Boolean = true;
private var target : LogPanelTarget;
\[Bindable\] private var targets : ArrayCollection;
private function init() : void
{
this.target = new LogPanelTarget(output);
// here we define which categories are written to our target
this.target.filters = \["iamjosh.samples.\*"\];
// and here which log levels are written
this.target.level = LogEventLevel.ALL;
this.target.includeCategory = true;
this.target.includeTime = true;
Logger.addTarget(this.target);
}
private function setVerticalPosition() : void
{
this.output.verticalScrollPosition =
this.output.maxVerticalScrollPosition + 1;
}
\]\]>
</mx:Script>
<mx:TextArea id="output" x="0" y="0" width="100%" height="100%"
editable="false" updateComplete="this.setVerticalPosition()"
verticalScrollPolicy="on"/>
</mx:Canvas>
We can now include the LogPanel
component anywhere we wish and log messages from anywhere in our code within the category "iamjosh.samples.*" will be written to it. For example:
public class Foo
{
// notice that we provide a category here, this determines if the log
// message will be written to a give LogTarget
private var logger : Logger = Logger.getInstance("iamjosh.samples.Foo");
public function logSomething() : void
{
this.logger.debug("I log because I can");
}
}
That's it. Although I would prefer to define where my log messages go external to the code, Flex's logging framework is fairly straightforward and easy to work with.
References