Tuesday, November 11, 2008

Migrating from JCL+Log4j to SLF4J+Logback

For my OSS project I went through the exercise of migrating from Apache Commons Logging (JCL) and Log4J to the Simple Logging Facade for Java (SLF4J) and Logback.

Logback is considered to be the successor of Log4J and is being developed by the same developer that originally developed Log4J. In return SL4J serves as a replacement for JCL.

There are already quite a few projects that use SL4J including Hibernate, Mule and Jetty to name just a few.

The migration process has been quite easy. The necessary code changes are minimal. They are virtually the same as before and the new way of declaring your loggers is:

* Logger Declaration.
private final static Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

For converting your old log4j.properties file to logback's logback.xml equivalent, there is an online converter available. It worked quiet well, I had to do only one minor tweak for my config file.

The nice thing about SLF4J is that it provides various components that help you bridge older logging libraries such as JCL and Log4J. Therefore, even your third-party libraries that don't support SLF4J and Logback directly will ultimately use them when using those bridging components. The result: No need to have Log4J of JCL in your classpath. Nice.

The only potential headache is that if you are using Maven for your dependency management, then your direct dependencies often have transitive dependencies that include JCL.

Well, you could manually exclude the JCL depency for each of your dependencies but what a pain, even when dealing with a moderately sized project. Luckily there is a workaround available: "commons-logging version 99.0-does-not-exist". It basically downloads a fake 0 byte JCL jar. Not necessarily pretty, but hey, it works as promised.

Furthermore, I hit one more minor issue with the Jawr library: the current version is using Log4J directly. The developer of Jawr promised that in the near future they will migrate to....well...unfortunately not SL4J but rather JCL. Anyway, by using the log4j-over-slf4j bridge I was able to work around that issue, too.

Well there is one task left for my project's logging framework conversion: I have a section in my web application that allows you accessing your loggers dynamically, which also permits you to adjust log levels dynamically at run-time. So far I was using Log4J directly to implement the necessary functionality...but that is worth another blog entry another time.


The sweet summer said...

I'm dealing with JAWR and Logback using by using the log4j-over-slf4j bridge as well but no success.

I can see in my log file that:
log4j:WARN No appenders could be found for logger (net.jawr.web.servlet.JawrRequestHandler).

this is my logback.xml
<appender class="ch.qos.logback.core.ConsoleAppender" name="STDOUTAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss},%p,%c, %t, %L, %ex, %M %m%n</pattern>
<logger name="net.jawr" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="STDOUTAppender" />

should I do anything else to do things work?

Any help would be much appreciated.

Anonymous said...

That means log4j is still in your classpath somewhere and is being used in preference to the bridge. Prove this by doing a Class.forName on one of the classes in log4j but not in the bridge.