Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Sunday, August 26, 2007

So long, commons-logging, hello SLF4J

I'm finally taking a bit to do something I've wanted to do for a long time: get away from commons-logging and switch over to SLF4J.

Commons-logging has a justified reputation for causing more problems than it solves. It's basic premise, that you should need to be able to switch between logging implementations, is very appealing to framework developers. Who am I to mandate that you use Log4J in your application? Sure, I mandate things like Javassist and a bunch of other dependencies, but for some reason, Log4J is too much. I'm not sure where this mindthink came from, but it is prevalent among framework folks.

Anyway, it's not a bad idea, though 99.99999% of applications use commons-logging as a wrapper around Log4J. I haven't yet met someone who uses JDK logging, or anything home brew. Why would you?

It's the implementation of commons-logging that the problem. First off, it called a "logger" a "log". I think that's just wrong, and (in fact) always preferred the term "category" (now deprecated by Log4J). To my mind, the category or logger is what you logged to, the log itself is the console, or a file, or something that receives the formatted output.

Also, commons-logging's ultra-late binding approach always causes class loader frustration and memory leaks. Every time they claim to get that fixed up, some new variation pops up.

The non-Apache follow on to commons-logging is SLF4J. It does things right: Logger, not Log. Better yet, Logger is an interface (it's a class in Log4J) which makes my EasyMock-addled brain quite happy. Finally, SLF4J takes a very simple, very sane approach: you combine the API JAR with one of several implementation JARs. That's it ... no class loader magic, no dynamic binding. This is an ideal solution for those same 99.99999% of applications out there.

This may cause some minor pain for Tapestry 5 early adopters, as they'll have to switch their (JCL) Log parameters to (SLF4J) Logger. Sorry, T5 is alpha ... but not for long, and this is a kind of last opportunity to make such a large change.

Update: Dion's been laughing from the sidelines but he's missing the point. He's put up a smokescreen that boils down to "just use System.out.println". But that's not what a logging framework is about ... it's about filtering, and organizing, a little bit about formatting, but mostly about being able to control what does log and what doesn't without hacking a lot of code (instead just tweaking a couple of control files).

14 comments:

Massimo said...

You should actually don't care about such a change, i would also say even it's wasn't the case of alpha state.

A bunch of a shell scripts could do the work for us, very happy T5 users!

Carey said...

I have two reasons to use JDK logging:

- No classloader problems! (Unless you define a custom Level.)

- WebSphere Application Server uses JDK logging internally, so we have one place to go to adjust logging levels and files for all applications.

Renat Zubairov said...

That's a very good decisiton. We are using Tapestry 4 together with SLF4J already for a while (under WebSphere) and the primary reason to switch was that WebSphere 5 using commmons-logging which completely break the logging of the applications based on the commons-logging.
commons-logging approach is really PITA in case application container (and it's clasloaders) are already spoiled with some predefiend commons-logging configuration.

POJO said...

I'm also starting to use JDK logging more often.

holger said...

You do not have to change any imports at all for using slf4j; just add the jcl-over-slf jar and enjoy binary clogging compatibility without the associated problems. This will:

- fix all other clogging uses as well
- avoid the need for duplicate jars when other libs want clogging
- allow people to use clogging if they really want to

Filip S. Adamsen said...

Awesome news, Howard!

I've been wanting to use SLF4J for a long time but Tapestry's dependency on Commons Logging held me back.

Now I can finally get rid of it!

Ceki said...

After several months of trepidation, I am glad to hear that Tapestry has taken the plunge and finally migrated to SLF4J. Please do not hesitate to contact slf4j's users list if you encounter any problems.

A.A.A said...

i prefer to use JDK logger for the client side. i see no problems with it. log4j is bloated.

A.A.A said...

BTW, are you living under a rock man.. Tomcat also uses JDK logger ;)

JPOX said...

You say its a big change, but why oh why haven't you abstracted out your own log interface before now ? What log capabilities do you need in your code ... info, warn, error, debug, trace ? isInfoEnabled etc ? So you would have your own Tapestry abstract logging class (or intf) with implementations for Log4J, JDK1.4 logging, or whatever and just call your own class methods internally. That way you don't impose on your users having to have clogging or slf4j in the CLASSPATH and they can use what they want. JPOX codebase has had that for a long time.

Howard said...

An abstraction on an abstraction on an abstraction? Sure, the control freak in my grooved to that idea, but I discarded it a while ago as Not Invented Here Syndrome.

For me logging is important because I strongly feel there should be a separation of concerns: one concern is the creation of loggers and should be the domain of the framework. The other concern is the use of loggers and that's the domain of the application. Dependency injection is used to bridge the two concerns.

alexander said...

NIH syndrome all the way down to hell. I agree with the previous poster. The amount of abstractions that the J*EE camp produces is ridiculous. What exactly is the problem with log4j or any of the other zillion logging frameworks? Bashing JCL as a justification for the zillionth+1 logging "facade" (or whatever) is a pathetic straw man.

The "explanations" given by SLFJ4 are ridiculous : "Suppose a customer doesn't want you to use log4j".. Yeah, you might as well suppose that a customer doesn't want you to use SLF4J, either :-(, so then what? Shall we build a facade-over-a-facade-over-a-proxy and inject the logging framework via Spring? Shall thee come to thy senses at some point?

Ability to switch logging implementations? Woah! Sure as hell this happens *all the time* in real world projects. It's a helluva requirement of paramount importance for customers (sarcasm).

Howard said...

Alexandar,

I totally disagree. There are very good reasons to use different logging frameworks, based on a number of factors. Different application servers, for example, have different logging frameworks built in, and you may not get best results if you graft Log4J on top of a server that really wants to use something else.

SLF4J means that framework authors don't dictate this aspect of your application. Use Tapestry with whatever logging (Log4J, JVM, Logback, etc.).

Raúl K. said...

It looks like somewhere along the way some commenters lost sight that your post was targeted towards *framework* development, i.e. a library meant to solve a specific problem *within* your application.

Fair enough that *applications* built in-house to satisfy a company/group/whatever's own needs won't have the requirement of being able to substitute the underlying logging framework easily. After all, if you've banked on log4j you will probably stick to it for a very long time until the next big thing comes out.

However, isn't it very likely that your app will be based on top of an existing framework like Tapestry, Wicket, Vaadin or whatever? Is it fair that such a framework imposes a logging framework on you?

Let's not even talk about when you combine different frameworks that use different logging backends...