The Toolbox: Introduction & Log4J

In my own semantics, software development is a blend between a conventional profession and a craft. As a craftsman, I have a preferred set of tools with which I build and create. Of course, as a contract developer, I don’t always get to use what I want, but these days I more often find myself in a position to do so. I figure it might be useful to others, especially those just getting into the game, to see what an experienced developer actually uses, and why. So let’s start with an easy one, Log4J.



Log4J.There are essentially 3 major choices when it comes to logging in Java. Log4J, Commons Logging, and Java Logging. My current preference is Log4J. Why?

Commons Logging is an abstraction layer, and defaults to using Log4J for its actual logging. The main idea behind CL is that you aren’t tied to a specific logger. I think CL is flawed in two ways:

1. Log4J is itself extensible. Writing a custom appender (the piece that actually writes the log message) is a fairly trivial task, and if your project makes such a fundamental shift as to change its logging API, writing a bridge appender is a negligible amount of effort. So if you’re going to be using Log4J anyways, as most projects do, why add unnecessary complexity?
2. Commons Logging is always more difficult to configure. I honestly can’t figure out why, but almost every project I’ve worked on that uses CL has had issues, especially when you have a mix of libraries which do or do not use it.

Java Logging, added several years ago in Java 1.4, was supposed to eliminate the need for third party logging APIs. It was, and remains, a good idea, but it does not make a compelling case to switch from the vastly more popular Log4J. Last time I checked, the standard logging API was missing a rolling file appender, which is essential for any production environment. It is also slightly less flexible to configure, but the main reason it has largely been irrelevant is that it doesn’t offer anything that Log4J does not.

What would make me switch?

I’m a very heavy logger. I will often write code with as many log statements as regular lines of code, and of course most of these statements are debug/trace level. The problem this introduces is performance. Let’s look at this example:

Person person = PersonFactory.getPerson(name);
log.debug("Found " + person.getName());
precinct.register(person);

The problem is that even if logging is at a level above debug, getName() will be invoked. In practice these statements rarely do anything expensive, but it can be the proverbial death by a thousand cuts. The Log4J way to avoid this is to do the following:

Person person = PersonFactory.getPerson(name);
if(log.isDebugEnabled()) {
log.debug("Found " + person.getName());
}
precinct.register(person);

Messy huh? What I would like to see is the ability for the java compiler to skip these statements entirely, without the cruft currently required. If this ended up being some special case that required the use of the standard logging API, I would switch. The slick way to do this would be to have the ability to annotate methods for lazy reads of parameters being passed to them, but that, as Alton Brown would say, is another show.