« Predictions for 2007: More of the same | Main | Negative Testing »

DRY Logs, there are better ways

Ruby is having a definate impact on Java, or at least the idioms implemented by Rails. Two of the most commonly mentioned are Coding by Convention, and Don't Repeat Yourself. The last one comes with a nifty acronym as well, DRY.

The problem is, not everything is good dry. Firewood and tinder work better dry, but a dry aquarium? And which of the standards is better, convention or DRYness? According to Dr. Heinz M. Kabutz DRY should win, at least if you extrapolate from the vendetta he has against a very common convention in Java today, the static final LOGGER, where the category of the logger is the full name of the Java class it is in.

His solution to me lacks some real world (i.e. production tested) sensibility. His final solution is to use a parameterless logger factory class. That doesn't sound so bad, until you look under the covers. To determine which class to make the category from, he creates an exception and takes the first element of the stack trace and unwraps the top element of the trace to get the calling class name.

He says that the approach feels like there is some law against it. I've heard it called a code smell; if it feels like you are doing something wrong that could be done a different way, you probably are. This approach won't entirely kill the server. The exception stack trace overhead will only occur during class initialization and will in effect only be felt on the first hit or application startup. If I were to write code like that is would be like giving my toddler the same milk in the morning he went to bed with the night before: likely not lethal but it smells (and kinda chunky too).

There are other ways to do this, one is to use annotations and write an annotation pre-processor. This turns it into a compile time injection field: @InjectLogger static final Logger LOGGER;. no messy initialization code either. Injection is quite trendy, and so are annotations. (Implementation is left as an exercise for the reader, academic speak for "I'm not doing it here").

But in the end, what is so wrong with having private static final LOGGER = new Logger(ClassName.class.getName()) at the top of every file? Has DRY become and end to itself? If you want to get pedantic about it even declarring a logger in each class is repeating yourself. Your language should be smart enough to just add the logger everywhere you are using it, you know, like a mix-in or something.

This is one of the few examples of Coding By Convention you are likely to find "in the wild," mostly because it just works. Yes, this allows for cut and past errors where you leave in some other class as the seed class, but you can write a PMD rule for that. And convention that can be verified by static analysis in my book is a convention that doesn't need to be dried out.

Comments (1)

Kieron Wilkinson:

I agree that it doesn't seem quite "right". I'd love to see how it is done with annotations, or with the SecurityManager as Heinz suggested.

However, you do not need to create an ception, as in Heinz's solution.

Here is an adapted form:

public static Logger create() {
  final Thread t = Thread.currentThread();
  final StackTraceElement directCaller = t.getStackTrace()[2];
  final String className = directCaller.getClassName();
  return Logger.getLogger(className);
}
Slightly less smelly. What do you think?

Post a comment


About

This page contains a single entry from the blog posted on December 30, 2006 5:58 AM.

The previous post in this blog was Predictions for 2007: More of the same.

The next post in this blog is Negative Testing.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33