1
votes

I'm new to using Spring, SLF4J, & Logback. I'm trying to implement a custom Database Appender that will only log specific types of exceptions to a database during Spring Batch processing.

So far I've started to setup a Logback Database Appender that extends the AppenderBase class and then an initializer that extends the InitializingBean in spring so it adds the appender to the root logger once Spring has initialized (So I can use my DB information from spring.xml).

How can I set this appender/logger up so I can only log certain exceptions to my custom tables?

EDIT: After doing some more research, let me ask an additional question to verify. If I were to create a custom logger like "SpecialExceptionLogger", can I just add the DB Appender to that specific logger and then use that logger when I get the special exceptions?

3

3 Answers

2
votes

Your requirement of "appender using Spring's DB info" is a bit strange. Logging is already available during Spring startup, and in case the log during the startup needs to go thru that appender, it won't work because your appender cannot be properly configured yet. I'd recommend you configure your appender separately (although it is not impossible to achieve what you look for)

For your other questions:

If I were to create a custom logger like "SpecialExceptionLogger", can I just add the DB Appender to that specific logger and then use that logger when I get the special exceptions?

Of course you can. It should be basics of using Logback. Make sure you read the documents to learn the basics first.

XML will look like (not real one, just give you idea)

<appender name="dbAppender" ...> ... </appender>
<logger name="SpecialExceptionLogger">
    <appender-ref ref="dbAppender"/>
</logger>

How can I set this appender/logger up so I can only log certain exceptions to my custom tables

I believe filter in Logback can achieve what you need. You can find it in an existing answer in StackOverflow

1
votes

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)
    }
}
0
votes

In logback config.xml, you should specify the Appender class name like below.

<appender name="CUSTOM_DB_APPENDER" class="my.custom.DBAppender" />

Check http://logback.qos.ch/manual/configuration.html for more configuration options