Andrey Hihlovskiy

Professional blog on groovy, gradle, Java, Javascript and other stuff.

Programmatic configuration of slf4j/logback

Now I have experience with programmatic configuration of slf4j/logback.
Task
A program must open separate log file for each processed input file.
Solution for task
Instead of configuring logback via xml, the one needs to “manually” instantiate encoders, appenders and loggers, then configure and link them together.
Caveat 1
Logback goes crazy on attempt to share encoder (i.e. PatternLayoutEncoder) between appenders.
Solution for caveat 1
Create separate encoder for each appender.
Caveat 2
Logback refuses to log anything, if encoders and appenders are not associated with logging context.
Solution for caveat 2
Call setContext on each encoder and appender, passing LoggerFactory as a parameter.
Caveat 3
Logback refuses to log anything, if encoders and appenders are not started.
Solution for caveat 3
encoders and appenders need to be started in the correct order, i.e. first encoders, then appenders.
Caveat 4
RollingPolicy objects (i.e. TimeBasedRollingPolicy) produce strange error messages like “date format not recognized”, when they are not attached to the same context as appender.
Solutin for caveat 4
call setContext on RollingPolicy same way as on encoders and appenders.

Here is working example of “manual” logback configuration:

package testpackage
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.rolling.RollingFileAppender
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy
import org.slf4j.LoggerFactory
class TestLogConfig {
public static void main(String[] args) {
LoggerContext logCtx = LoggerFactory.getILoggerFactory()
PatternLayoutEncoder logEncoder = new PatternLayoutEncoder()
logEncoder.setContext(logCtx)
logEncoder.setPattern('%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level – %msg%n')
logEncoder.start()
ConsoleAppender logConsoleAppender = new ConsoleAppender()
logConsoleAppender.setContext(logCtx)
logConsoleAppender.setName('console')
logConsoleAppender.setEncoder(logEncoder)
logConsoleAppender.start()
logEncoder = new PatternLayoutEncoder()
logEncoder.setContext(logCtx)
logEncoder.setPattern('%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level – %msg%n')
logEncoder.start()
RollingFileAppender logFileAppender = new RollingFileAppender()
logFileAppender.setContext(logCtx)
logFileAppender.setName('logFile')
logFileAppender.setEncoder(logEncoder)
logFileAppender.setAppend(true)
logFileAppender.setFile('logs/logfile.log')
TimeBasedRollingPolicy logFilePolicy = new TimeBasedRollingPolicy()
logFilePolicy.setContext(logCtx)
logFilePolicy.setParent(logFileAppender)
logFilePolicy.setFileNamePattern('logs/logfile-%d{yyyy-MM-dd_HH}.log')
logFilePolicy.setMaxHistory(7)
logFilePolicy.start()
logFileAppender.setRollingPolicy(logFilePolicy)
logFileAppender.start()
Logger log = logCtx.getLogger("Main")
log.additive = false
log.level = Level.INFO
log.addAppender(logConsoleAppender)
log.addAppender(logFileAppender)
}
}

view raw
TestLogConfig.groovy
hosted with ❤ by GitHub

My conclusion: logback is much easier to configure via XML. “Manual” configuration is rather tedious task and should be avoided, unless it is dictated by project needs.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: