AS3 logging with Log4j

There are several things I miss about FlexBuilder…the debugger, authoring-time error checking, code assistance, and the quick compiles to name a few. But perhaps the first thing you’ll miss when just using the free Flex SDK is your basic trace output window. Initially I had written a simple Ruby script to handle tracing to a terminal window. This was fine for awhile but as some of my projects grew bigger, I wanted more control over logging.

Flex comes with a logging system under the mx.logging package which works similarly to typical logging systems in other languages, it’ll categorize logs, provide log levels, and has some log filtering capabilities. So I changed my tracing class that connects to the Ruby script into a log target. This was much nicer since any code using the standard mx.logging package is now compatible just by add the target.

However something still bothered me, I didn’t like the filtering controls being done in ActionScript. I mean it’s nice to have, but I really don’t see why we have to re-code and re-compile just to view a different log category and/or level. Sure a nice little component could be made to handle this at runtime but that didn’t seem necessary either. Certainly there must be dozens of existing logging apps out there for doing just this.

After some digging, I found Apache’s Chainsaw v2 to be a good fit. It has the filtering features I wanted, it’s cross-platform (interestingly as a webstart on windows and linux but native for osx), it’s by a huge well respected organization, and it’s free. With a little work to create the Log4j based log messages and connection to Chainsaw, this logging target is now a part of my standard workflow and so I thought I’d share.

Features

  • Log category and level filtering done externally at runtime
  • Chainsaw features also include log message filtering by search query, builds category tree, customizing log presentation, and log saving/loading
  • Log events are Log4j XML messages and should be able to tie with other compatible systems

Usage Example

After you’ve added the logging.swc to your project’s library path, the following example will log to Chainsaw.

package nochump.logdemo {
	import flash.display.Sprite;
	import mx.logging.*;
	import nochump.logging.target.Log4jXMLSocketTarget;
	public class LogDemo extends Sprite {
		protected static const logger:ILogger = Log.getLogger("nochump.logdemo.LogDemo");
		Log.addTarget(new Log4jXMLSocketTarget());
		public function LogDemo() {
			logger.debug("Hello debug message");
			logger.info("Hello info message");
			logger.warn("Hello warn message");
			logger.error("Hello error message");
			logger.fatal("Hello fatal message");
		}
	}
}

Before running the swf, fire up Chainsaw v2 and load the supplied log4jconf.xml file when it asks. This creates an XMLSocketReceiver which you should see in the receivers panel. Running the above example shows up in Chainsaw like the following.

ss-chainsaw-logdemo.gif

Download
nochump-logging-10-dist.zip

No Trackbacks

3 Comments

  1. Thanks for this – very useful :)

    I had to make one change to be able to compile it into a Flex 2.0.1 project:

    private const url:String = new LoaderInfo().url;

    became:

    private const url:String = (Application.application as Application).url;

    I’m not sure why your code wouldn’t compile for me but I know that this Application trick doesn’t work in an AS3 (as opposed to Flex) project though…

    Posted June 19, 2007 at 9:34 am | Permalink
  2. PVM

    Great! – Thanks, been looking for something like this!

    Posted June 21, 2007 at 6:02 pm | Permalink
  3. Mario

    Great, thanks for that, but sometimes (regularly) I get following error in the Java Console:

    org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x0) was found in the element content of the document.
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at org.apache.log4j.xml.XMLDecoder.parse(XMLDecoder.java:133)
    at org.apache.log4j.xml.XMLDecoder.decodeEvents(XMLDecoder.java:208)
    at org.apache.log4j.net.XMLSocketNode.run(XMLSocketNode.java:139)
    at java.lang.Thread.run(Unknown Source)

    I think the log message gets lost. What could be the reason for the problem?

    Posted September 11, 2007 at 7:44 am | Permalink