Recently, I had to fix some application that does a lot of logging. But not just a simple debug logging where all of your messages are going to one rotating file on the disk and are examined only when something goes terribly wrong.
Requirements for this application were to log all events of a certain type in a separate log (rotating file) and to send en email if an error condition is encountered.
The original application has used the JDK Logging API to cope with these requirements, but something has gone wrong in the implementation and I had to fix it.
First of all, I have to confess that my default choice for Java logging is certainly the log4j API since it is clean and is capable of doing everything that I’ve needed thus far. As far as commons logging library is in question, I don’t see that this extra layer is useful in applications. Libraries are totally different story for that matter.
So, here’s what I’ve found about JDK Logging API that convinced me to stay with log4j whenever I can:
- There is no way to configure multiple instances of the logger handler class in the properties file - I’ve needed this to configure multiple
FileHandlerinstances that would write to different log files. But unfortunately, it is impossible to do it through the properties file configuration mechanism.
When you are using this mechanism, you first define handlers that you will be using, by specifying their classes.
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
Next, you have to configure every class and set its properites.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
So as you see, there is no standard way to configure multiple
FileHandlerinstances that will write to different files.
For that reason you can, for example, find a custom implementation of
LogManagerin Tomcat called JULI. JULI solves the problem by allowing you to add numbers in front of your class names and treats that “classes” as independent instances. While this is acceptable solution, I didn’t want to go that way and introduce solution which is not standard and widely accepted.
The other solution was to configure logging mechanism programmatically, but that was just out of question.
- JDK Logging API cannot reliably log messages from the shutdown hook - while this is not as important limitation as the previous one, it could be restricting to some applications (like it was this specific application that I have worked on). It seems that the Logging API has its own shutdown hook and because: (quotation from the API)
When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently
you can’t be sure that your messages will be logged.
At this moment I have started thinking of how hard would it be to migrate this application to log4j. And it turns out that it was the easiest solution to all of aforementioned problems.
Here are the steps needed to do this:
- First of all you’ll have to change the method that is used to obtain the appropriate log. So, instead
you’ll have to use
This may look like a hard manual task, but I’m sure that your IDE will help you in a great deal.
- Next, you’ll have to change names of the appropriate log methods, since
debug(), etc. With simple search-replace commands, this also won’t take more then few minutes.
- Now, you can configure your log4j logging mechanism by writing the
log4j.properties) file. I will not elaborate here how to do it, since there are more than enough resources on the Web that explain every detail of log4j.
- Finally, if you have used
javaswitch to instruct your application where to look for the logging configuration, there is one more step you’ll have to do in order to finish this transition.
The typical switch example that is needed to configure JDK Logging API looks like this
So now when we are using
log4j.xml, it should be replaced with something like this
If your application has no special requirements for logging, then it really doesn’t matter which of these two solutions you will use. But for any non-trivial logging the JDK Logging API is too limited to be useful. And as we have seen, even in existing applications it is just a matter of minutes to switch these two libraries.
Have you expirienced some of the limitations of the JDK Logging API? How did you overcome them?