Written on
Logging by Convention
Each Grails application uses a custom Log4J DSL [0] to configure logging settings. In a blank Grails application thegrails-app/conf
directory contains the Config.groovy
file, which declares the log4j
variable:
log4j = {
// Example of changing the log pattern for the default console
// appender:
//
//appenders {
// console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n')
//}
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails.web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
warn 'org.mortbay.log'
}
grails create-service com.ast.service.Some
Leading to the following generated Groovy code:
package com.ast.service
class SomeService {
boolean transactional = true
def serviceMethod() {
}
}
getLog
method injected on application bootstrap. The magic happens in LoggingGrailsPlugin
which is currently part of the grails-core module:
// ...
def addLogMethod(artefactClass, handler) {
def type = GrailsNameUtils.getPropertyNameRepresentation(handler.type)
def logName = "grails.app.${type}.${artefactClass.name}".toString()
def log = LogFactory.getLog(logName)
artefactClass.metaClass.getLog << {-> log}
}
// ...
getLog
method returning a log
object of type org.apache.commons.logging.Log
. But take a look at the log name which is used to create the log object with Apache Commons Logging LogFactory
:
def logName = "grails.app.${type}.${artefactClass.name}".toString()
INFO
logging on all application artefacts, developers just have to add the following line in Config.groovy
:
log4j = {
// ...
info 'grails.app'
// ...
}
ERROR
level and more detailed levels only for separate packages. We would modify the Log4J configuration to look like:
log4j = {
// ...
// maby defining additional appenders here
// ...
root {
error()
}
// ...
INFO
logging output of com.ast.service.SomeService
the following configuration snippet would not work:
log4j = {
// ...
info 'com.ast.service.MyService'
// ...
}
LoggingGrailsPlugin
prefixes the artefacts type and class name with grails.app
. The actual log
instance's log name in MyService
was therefore configured to
grails.app.service.MyService
As a consequence, to enable logging on INFO
level we should better use
log4j = {
// ...
info 'grails.app.service.com.ast.service.MyService'
// ...
}