Saturday, May 28, 2011

Groovy 1.8 Logging

One of the great features in Groovy 1.8 is the introduction of logging capability.  You get the following annotations:
  • @Log for java.util.logging
  • @Commons for Commons-Logging
  • @Log4j for Log4J
  • @Slf4j for SLF4J
You can add one of these annotations to any class, and your class automatically will pick up a log property to use.  In Groovy 1.7/Grails 1.3.x, adding logging to a non-Grails managed class is straight forward as well, you just add a simple statement:

    private static final log = LogFactory.getLog(this)

However, so an annotation to eliminate one line isn't a big deal - what is a big deal is what the groovy "log.X" methods compile into.  From the release notes: you wind up with "log.info" turns into:

if (log.isLoggable(Level.INFO)) {
    log.info 'whatever your message was'
}


This subtle change is a great performance booster -- you get a quick boolean check, to avoid a bunch fo string buff/string concat operations, followed by actually sending the log message down into the log system itself - only to be filtered out by the level.

I've seen very verbose and 'noisy' logging by Java applications reduce performance by 10-20% depending on how enthusiastic you are about logging and how resource constrained your platform is.  Likely not an issue for bigger setups - but being a little performance conscious here or there can go a long way.

Edit (7-6-11): Used the @Slf4j annotation in Groovy SPARQL, it appears to pick up the dependencies automatically which is also nice. 

When doing this, I just had to make sure I had the latest Groovy-Eclipse for Groovy 1.8 source editing.  Otherwise, uninitialized "log" variables are errors in Groovy 1.7.x. 

Friday, May 27, 2011

How to Launch Spring Batch from Quartz in Grails

Here is a quick tip on how to launch Spring Batch from a Quartz job in Grails.  Why would you want to do this?  To periodically run batch jobs in your Grails application.

You will likely want this to be a non-concurrent Quartz job, so that you don't have concurrent batch processing going on.  Other then that, the Quartz job needs the job bean to run, and a job launcher.  Those can be configured in your standard Spring Batch way in the resources.xml file in Grails.




Other notes:
  • TaskExecutor configuration works great, and I would love to see GPars as a mechanism to define task executors for Spring Batch
  • There were no issues using Groovy classes as implementors of ItemReader, ItemProcessor, or ItemWriter in Spring Batch
  • There were no issues having Spring Batch beans, step scoped, injected with Grails managed beans
  • Grails transaction manager did not appear to be picked up by Spring Batch, so I declared a ResourcelessTransactionManager
  • Do not forget to use StepScope, so you can re-use other beans in your Grails configuration directly in your configured jobs, simply delcare with: 
<bean class="org.springframework.batch.core.scope.StepScope" />