I hate to necro, but this is achievable with a DelegatingLogbackAppender
. That appender just holds on to any events until you can configure a proper DBAppender
later on once Spring (and your datasource) is initialized.
In my example, I created a datasource within Grails called logging
, which I reference in the bean configuration. If you want to and are able to create the necessary tables in the root datasource, you could just pass ref(dataSource)
(note the capital S) instead.
The DelegatingLogbackAppender
is also useful if you have created your own custom database appender, as we have, since the canned DBAppender
is so rigid.
There are plenty of reasons to want to put log events in a database. The one that is a requirement for us is that our apps are scaled across tens of instances, which makes searching tens of log files onerous.
logback.groovy (imports omitted)
appender('STDOUT', ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%level %logger - %msg%n"
}
}
appender('DB', DelegatingLogbackAppender)
root(ERROR, ['STDOUT', 'DB'])
resources.groovy (imports omitted)
beans = {
applicationContextHolder(ApplicationContextHolder)
loggerContext(LoggerFactory) { bean ->
bean.factoryMethod = "getILoggerFactory"
}
patternLayoutEncoder(PatternLayoutEncoder) { bean ->
bean.initMethod = 'start'
bean.destroyMethod = 'stop'
context = ref(loggerContext)
pattern = "%level %logger - %msg%n"
}
// Configure a console appender JIC
STDOUT(ConsoleAppender) { bean ->
bean.initMethod = 'start'
bean.destroyMethod = 'stop'
context = ref(loggerContext)
encoder = ref(patternLayoutEncoder)
}
connectionSource(DataSourceConnectionSource) { bean ->
bean.initMethod = 'start'
bean.destroyMethod = 'stop'
context = ref(loggerContext)
dataSource = ref(dataSource_logging)
}
DB(DBAppender) { bean ->
bean.initMethod = 'start'
bean.destroyMethod = 'stop'
context = ref(loggerContext)
connectionSource = ref(connectionSource)
}
}