Monday, May 18, 2009

AspectJ for Java logging: suppressing System.out debugging calls - part 7

We have all been there, adding a few System.out calls here and there to our Java code during development to help debug something that defies (bad) logic.

It seems all too common to, ahem, leave some of those calls behind, which introduces several problems in a product. Don't we love to see the occasional "WE ARE HERE!!" graffiti in the server console, or a 50MB trace file that cannot be opened by any text editor?

One way to prevent this problem is to continuously demand that developers pay attention to it, either deleting the offending statements or converting them to a Logger.log call. That approach also has drawbacks in that mistakes are, well, mistakes. A complementary approach to pleading with developers is to intercept the requests to System.out and System.err and route the "println" commands to a trace call.

Here are the changes to the Logging serviceability aspect. I still want to find a way to use the name of method calling System.out.println in the trace calls, but for now, here are the interesting bits:

...

public aspect Logging pertypewithin((my..*) && !Exception+){

/**
* Trace handler for each type.
*/
private static Logger trace = Logger.getLogger("my.project" ) ;

private static TracePrintStream sysoutTrace = null;

...

/**
* After the initialization of all classes in this project.
*/
after(): dcofpClassInitializer() {
String classname = thisJoinPointStaticPart.getSourceLocation()
.getWithinType().getName();
classname = LoggingUtil.normalizeClassName(classname);
trace = Logger.getLogger(classname);
sysoutTrace = new TracePrintStream(trace, "System.out", System.out);
}

...

/**
* Replace calls to SystemOut with trace calls
*/
PrintStream around(): dcofpSystemOutPrintln() {
return sysoutTrace;
}

...

/**
* Inner class used to convert System.out.println calls to trace calls.
*/
public class TracePrintStream extends PrintStream {
...
public void println(String str) {
trace.logp(Level.FINER, trace.getName(), method, str);
}
...
}
}

No comments:

Post a Comment