The holy Grail of logging?

So, it’s been awhile since I last posted. Besides some personal time, one of the big reasons that I have been posting less is that we have been heads-down in releasing a new set of features. Many of them involve a set of services built using the Grails framework.

An editorial about Grails is probably due at some point once we get past the honeymoon period. (Right now, things are great!) But, I thought that we needed to post about our issues with Logging and Grails, and how a little upgrade makes all the difference.

In Grails 1.0.x, we struggled mightily to get logging to behave for us. We deploy our app as a WAR file inside of Tomcat, and simply want most of our logging to go to a named log file in the standard Tomcat log directory. All of our environments generally had their Tomcat installed in a different directory. This is especially true of our “test” environments, as we are heavy CI users with many flavors of testing.

Our Grails 1.0.x setup was kludgy to say the least. I won’t even post sample setup files, but suffice it to say, we needed to map all of our logging to two different files. One file was available using grails commands like grails test-app or grails run-app, which could pick up local environment variables (like CATALINA_HOME). The other log file tended to be available when we used a pre-constructed WAR file, which required a fixed Linux path available on most of our production and production-testing environments.

All of this Grails 1.0.x kludginess centered around the fact that creating WAR files compiled your Config.groovy into a Log4J properties file, rather than using the original Groovy class. Consequently, it was very difficult to use that WAR file on many different machines (with potentially different file system setups.)

Now, along came Grails 1.1, which among many other things included a new Log4J DSL to the Config.groovy. So when using the new Log4J DSL, you actually embed your configuration as a closure that the run-time app evaluates at startup. Consequently, you can use Groovy snippets to gather runtime properties to define your Log4J setup.

This made our configuration quick and easy:

log4j = {
     appenders {
         rollingFile name:"mainLog", file: System.getenv("CATALINA_HOME") +"/logs/appName.log", layout:pattern(conversionPattern: '%d %-5p [%t] %c{2} - %m%n')
     root {
         warn 'mainLog'
         additivity = true

     error  'org.codehaus.groovy',  // all

     warn   'org.mortbay.log'
     info   ''
     info   ''