2013-03-28

Using SLF4J With Tomcat

A few days ago I posted about using getting started with SLF4J, the logging façade framework for Java.

Well, I ran into a surprise using SLF4J with the SimpleLogger implementation while developing a web app in the Eclipse IDE for Java EE Developers edition of Eclipse Juno using an external copy of Apache Tomcat 7.0.39. As my previous post documented, you can configure settings for SimpleLogger by programmatically setting Java System properties.

That works – the first time you run. I found on successive runs that my settings were being ignored. I suspect the System properties are being restored to default thereby wiping out the values I set programmatically since I was not persisting my values. I don't know exactly what is happening. But I'm guessing that because Eclipse is eager to do incremental compiles, and Tomcat is eager to redeploy the changed web app, somewhere in there the System properties in memory are being cleared and reset to the persisted defaults. If so, this would be a feature, not a bug.

I did find a solution to the problem of configuring SimpleLogger for use inside the whirlwind that is Eclipse+Tomcat. The SimpleLogger API doc page mentions that it checks for a class loader resource named simplelogger.properties. Translated to English, that means creating a text file with a few key-value pairs, and placing that file in an appropriate folder to be noticed by Eclipse+Tomcat at runtime.

First, the file.

The .properties format is super simple, defined by the Java platform. Read about it in this Wikipedia page. Start with a plain text file, but in Latin-1 (ISO-8859-1) character encoding rather than the more modern UTF-8 encoding. For our purposes with SimpleLogger, Latin-1 in convenient. But for other purposes, you may want to explore the alternative .properties format using XML and therefore using UTF-8.

Put some comments at the top, each line starting with a hash mark (#). After that, add a key-value pair on each line of text. Unlike Java code, no end-of-line marker is needed. The key-value pair is delimited by your choice of an Equals sign (=), Colon (:), or a Space character. Accordingly, if either your key or value text contains one of those three characters, you must escape such occurrences by a preceding backslash. Notice the escaping in the last line of my example below, for the colons that appear in the time format.

Second, the location.

This page in Tomcat doc explains the complexities of class loaders in Tomcat due to the nature of web servers and servlet containers. Assuming that you, like me, want to keep your settings close to your web app rather than in a global Tomcat-wide scope, then practically that leaves a single location in which to place your properties text file: Your web app folder > WEB-INF > classes folder. In Unix-speak:
/WEB-INF/classes of your web application

In the Eclipse Project Explorer pane, you probably will find a WebContent folder nest inside your project. Expand that to find META-INF and WEB-INF folders. Expand WEB–INF to find the classes folder. If classes folder does not exist, create it.

Third, an example.

Here's an example from my work.

# Settings for the slf4j logging API implementation "SimpleLogger".
# http://www.slf4j.org/apidocs/org/slf4j/impl/SimpleLogger.html
# http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
# http://en.wikipedia.org/wiki/.properties

# By Basil Bourque. 2013-03.
# This example is provided without warranty or guarantee to anyone taking full responsibility for its use.

# Override default of outputting to System.err. Use System.out instead.

# Eclipse (Juno and earlier) has a known bug where System.out & System.err are incorrectly interleaved (out of order). So use one or the other, but not both.
org.slf4j.simpleLogger.logFile=System.out
# Override default of tracking only 'info' and higher. Track all levels of messages.
org.slf4j.simpleLogger.defaultLogLevel=trace
# Drop the package name from the class calling to the logger.
org.slf4j.simpleLogger.showShortLogName=true
# Log the datetime rather than the number of milliseconds into the run of the app.
org.slf4j.simpleLogger.showDateTime=true
# Format the datetime in ISO 8601 format. Escape the colons by prefixing with a backslash.
org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd'T'HH\:mm\:ss.SZ


I would rather see that datetime as Zulu time (UTC time zone), but I can't seem to find the correct format for that. Please comment if you have a solution to that.

For deployment, you will almost certainly want to replace the SimpleLogger implementation with something more robust or flexible such as Logback. But for a quick set up in a new project to use during development, SimpleLogger is handy. Also, there is a plugin for Eclipse for reading logs, called Logback-beagle, but I've not yet tried it.

No comments:

Post a Comment