Logging Like it’s 2011

Earlier this year I revisited how I was logging things in Java, and decided I would try a hybrid approach.  I’m reporting back to say that it’s been successful. There are basically two ways I do it now:

Use java.util.Logging for libraries

It turns out that there’s nothing actually wrong with JUL aside from its limitations in terms of configuration.  It has different names than the Ceki Gülcü loggers (warning() instead of warn(), finest() instead of trace(), etc.) but otherwise works the same.  The configuration side of things I can’t even speak do as I haven’t had to configure it, I never use the actual JUL output.

Use Logback for applications

As suspected, Logback is basically just a new version of Log4J.  It’s got some niceties like MDCInsertingServletFilter that means I don’t have to write that filter myself anymore, and it’s supposedly faster and more stable, so there’s no reason I can see not to use it.  I also like that it has a format for condensing class names without completely losing the package names, so it goes from “com.efsavage.application.servlet.LoginServlet” to “c.e.a.s.LoginServlet” instead of just “LoginServlet”.

Why use two?

I like the fact that my libraries have zero logging dependencies and configuration, so I can always pop them into another app without adding baggage or conflicts or much additional configuration.  I can upgrade the logger in one application without having to deal with version conflicts of my other apps and having to do classpath exclusions and that type of nastiness.

Tip

If you do it this way, and you see your JUL logging showing up twice, you can edit the default logging config in your JDK installation, or if you prefer to leave that untouched as I do, try this (via Java Bits):

java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers();
for (int i = 0; i < handlers.length; i++) {
rootLogger.removeHandler(handlers[i]);
}
SLF4JBridgeHandler.install();

This basically yankts out the default logger and let’s SLF4J do it’s thing alone.  In a webapp you’ll probably throw this in your context listener or startup servlet where you previously did your log4j config.

Logging Like it’s 2002

I’ve been going through my old code, looking for stuff that might be worth sharing. At the same time, I’ve been maven-izing my builds, and decided I should revisit each dependency, as some of this code is so old the dependencies are very out of date and/or included in the JDK now. Which brings me to log4j.

I’ve literally used log4j on everything I can ever remember doing in Java, but not anymore. Don’t get me wrong, I have no problem with it, and may continue to use it in my applications (if I don’t like logback), but I won’t be including it in any libraries anymore. After 8 years, I’ve finally adopted JUL. Here’s the options and why I chose JUL:

JUL (java.util.logging)

Pros

I’ll start with the victor, because the reason is the simplest. No dependency or version issues, one less thing to download, guaranteed to be there. There is also plenty of code out there to use one of the other frameworks to do your actual logging, so the config isn’t really a burden on the developers using the library.

Cons

Not sure yet. It’s not widely used, but I think that’s because there are far more Java frameworks/applications out there than libraries. There is also a performance issue with SLF4J when you have JUL logging set to a low level, but you shouldn’t need to run (presumably stable) libraries in debug or trace when performance is an issue (e.g. in production), only when you’re trying to debug something. The JUL’s actually logging isn’t really relevant here, as I think most applications will just be running it’s output through their own logging framework.

log4j

Pros

Works great, very stable, hasn’t changed in long enough that you only have version issues when you’re dealing with REALLY old code.

Cons

Less people are using it, more projects are going to SLF4J/Logback. These new frameworks do add some nice features, and log4j is basically abandoned, so I think it’s time to stop doing anything new with it.

commons logging

Pros

None?

Cons

I’ve always been against commons logging, because 99% of the time, it was just used to wrap log4j. The logic was that you could plug custom logging into it, but you can do that with log4j already, so it’s basically an abstraction of an extensible framework, with zero added value. Actually you have less value because you lose things like MDC. At this point it’s like a virus that just won’t go away, and always seems to end up in the classpath somehow. As far as I’m concerned, I consider this a completely superseded library.

logback

Pros

From what I can gather, logback really is (as claimed on their website) the continuation of log4j. Not having used it, I can only assume this is a good thing, and it just adds new features like parameterization. I’m going to try logback in my next application, and since logback includes slf4j, I will access my library logging that way.

Cons

It’s not really in wide usage yet, which means that a library requiring it is going to add an extra dependency.

slf4j

Pros

If logback is the modern version of log4j, slf4j is the supposedly useful version of commons logging, and supposedly improved version of JUL. It’s not a logger per se, it’s just an API/facade. It has the ability to combine multiple logging APIs and legacy frameworks into one stream, which is why it seems to be getting traction on complex applications.

Cons

I’ve had some serious versioning issues with slf4j, due to some methods being removed or changed, so you end up with older code throwing errors when you use a newer version, thus requiring that you only use the old version and introduce the chance for strange errors in code expecting the newer version. For this reason, I don’t feel very comfortable specifying any version of slf4j, and I will leave it to the user to add it if they wish.

Conclusion

So JUL seems like the best choice for a stable, single-purpose library to use, as it’s the least imposing on whatever uses it. It should be noted that I haven’t actually used JUL yet in a real app, so perhaps I will find out that there’s an actual reason for its lack of popularity. If that’s the case, I will likely use slf4j, and try and find out which methods cause issues so I can avoid them, and not be the person someone else curses for requiring it.