Sunday, June 08, 2008

Java Logging Frameworks - why to use sl4j?
One of my friend was asking why should I with sl4j over log4j & java logging. My answer was "because it was written by the same author who wrote log4j & is now adopted by finest java framework authors (Tapestry & Wicket)" sl4j is the best available way to solve logging problems. It's latest & hence best suited for any new projects. This way some decisions are easy & safe to make. Logging is one of the most boring & non-debatable topic. At least for issues like this it's best to follow the best minds. During my initial days of coding I have seen mindless java wrappers over existing logging frameworks without any value addition. Log4j is definitely superior option to standard java logging both in terms of speed & availability of appenders. But when we write client apps or want to make our jar size compact & cannot afford to include log4j.jar java logging might be still better option which is rare case anyway. With log4j , in order to bypass the expensive string concatenation if statement was necessary. It would have been nice if APIs to provide some features that would alleviate things like this, and maybe make it easier to toggle the display of log statements for code readability.
if (log.isDebugEnabled()){
log.debug("Logging " + String.valueOf(a) + "some information :"+someBigEntity.toString());
}

I never liked double if conditions. Less if conditions directly proportional to good code quality.
sl4j utilizes parameterized messaging (like logger.debug("The new value {} is replacing {}.", newValue, oldValue);) & does'nt have class loader & memory leak problem. As JVM is becoming smarter & smarter with every new version, micro bench marking knowledge are becoming totally irrelevant. The experience is becoming baggage & anti pattern most of the time as for micro bench marking is concerned.

Here is one experiment I did with latest JVM with decompilation .

public class JavaLogTest {
// Get status from Logger.isDebugEnabled();
private static final boolean DEBUG=false;
public static void main(String[] args) {
if(DEBUG) {
System.out.println("Performance issue");
debug("Some Big"+"Concatenation here"+"& also creation of objects.... "+new java.util.Date()+" which is not good for performance");
}
debug("testing"+" ! testing again");

debug("testing"+new Integer(10).toString() +new java.util.Date());
}
public static void debug(String str){
System.out.println(str);
}
}

I decompiled the class with decompiler & here is the result what I got;

import java.io.PrintStream;
java.util.Date;
public class JavaLogTest{
private static final boolean DEBUG = false;
public JavaLogTest() { }
public static void main(String args[]) {

debug("testing ! testing again");
debug((new StringBuilder()).append("testing").append((new Integer(10)).toString()).append(new Date()).toString());
}
public static void debug(String s) {

System.out.println(s);
}
}

& the results were interesting;
1. It doesn't make sense to use StringBuffer for appending, JVM is intelligent to make use of StringBuilder which is not synchronized also
2. When we append strings only there is no need to use if statement even with log4j
3. We can take out the code from the byte code (pre-processor directive DEBUG) which can reduce the total jar size
I found scala solution for this was interesting. Dynamic languages indeed bring lot of paradigm shift in thinking!

1 comment:

Anonymous said...

Excellent! Great job.

Bookmark and Share