Programmatically configure the LogBack application

I have a logback application defined in logback.xml, this is a DB application, but I'm curious if there is a way to configure appender in java using my own connection pool defined as bean.

I find similar things, but not the actual answer.

+42
java spring javabeans logback
Jun 04 '13 at 6:13
source share
5 answers

Here is a simple example that works for me (note that I use FileAppender in this example)

import org.slf4j.LoggerFactory; 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.classic.spi.ILoggingEvent; import ch.qos.logback.core.FileAppender; public class Loggerutils { public static void main(String[] args) { Logger foo = createLoggerFor("foo", "foo.log"); Logger bar = createLoggerFor("bar", "bar.log"); foo.info("test"); bar.info("bar"); } private static Logger createLoggerFor(String string, String file) { LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); PatternLayoutEncoder ple = new PatternLayoutEncoder(); ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n"); ple.setContext(lc); ple.start(); FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>(); fileAppender.setFile(file); fileAppender.setEncoder(ple); fileAppender.setContext(lc); fileAppender.start(); Logger logger = (Logger) LoggerFactory.getLogger(string); logger.addAppender(fileAppender); logger.setLevel(Level.DEBUG); logger.setAdditive(false); /* set to true if root should log too */ return logger; } } 
+87
Jun 20 '13 at 13:32
source share

Software applications can be configured programmatically. Almost all consoles are tested using software configuration. It follows that in the source code of the logback project there are many examples of software application configuration. For an application with logback-core support, look under logback-core/src/test/java , and for a classic appender log under logback-classic/src/test/java .

+14
Jun 04 '13 at 6:52
source share

Just if someone is looking for a specific example of a software configuration.

Here I configure the ConsoleAppender encoding:

 LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); ConsoleAppender<ILoggingEvent> appender = (ConsoleAppender) lc.getLogger("appconsole").getAppender("STDOUT"); LayoutWrappingEncoder<ILoggingEvent> enc = (LayoutWrappingEncoder<ILoggingEvent>) appender.getEncoder(); enc.setCharset(Charset.forName("utf-8")); 

And my logback.xml:

 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>866</charset> <pattern>[%level] %msg%n</pattern> </encoder> </appender> <logger name="appconsole"> <appender-ref ref="STDOUT" /> </logger> 

Why do I need to program the recorder configuration? Because I am packing my application (Spring Boot) into a jar file. Therefore, the Logback.xml file seems hidden inside the jar. Although, it is inconvenient to unpack and modify it. And I don't need any logback.xml file next to my app.jar. I have only the app.yaml file that contains all the configuration properties for the application.

+2
Apr 6 '17 at 17:13
source share

As a link, when you try to change the code responsible for creating registrars, there are many rules that must be followed for the registrar to work.

These rules have been described in the large and useful article Programming Configuration slf4j / logback :

Now I have experience programming the slf4j / logback software configuration.

Task

The program should open a separate log file for each processed input file.

The solution of the problem

Instead of configuring logback via xml, you need to manually create instances of encoders, add-ons and logs, and then configure and link them together.

Caution 1

Registration fails when trying to share an encoder (i.e. PatternLayoutEncoder) between an application.

Reservation Solution 1

Create a separate encoder for each application.

Caveat 2

The reservation refuses to write anything if the encoders and applications are not connected to the logging protocol.

Reservation Solution 2

Call setContext for each encoder and application passing through the LoggerFactory as a parameter.

Caveat 3

Denial of registration does not allow registering anything if encoders and applications do not start.

Reservation Solution 3

Encoders and applets

must be launched in the correct order, that is, the first encoders and then the applications.

Caveat 4

RollingPolicy objects (i.e. TimeBasedRollingPolicy) generate strange error messages, such as “date format not recognized”, if they are not attached to the same context as the appender.

Reservation Solution 4

calling setContext on a RollingPolicy is the same as calling coders and add-ons.

Here is a working example of a manual log 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) } } 
+2
Sep 08 '17 at 17:03
source share

Not allowed to comment (yet?), I just wanted to add three tips;

  • regarding the warnings above, if you have problems just add a call

     StatusPrinter.print(context); 

    after everything is configured, that is, after adding it adds the root / "Main" appender: it will tell you what is wrong.

  • I really like to separate logging levels in different files; when searching for errors, I start by looking for errors in the file, etc., setting them as

 tot_[app name].log : Level.INFO deb_[app name].log : Level.DEBUG err_[app name].log : Level.ERROR 

using a simple private filter class like

  private static class ThresholdLoggerFilter extends Filter<ILoggingEvent> { private final Level level; private ThresholdLoggerFilter(Level level){ this.level = level; } @Override public FilterReply decide(ILoggingEvent event) { if (event.getLevel().isGreaterOrEqual(level)) { return FilterReply.NEUTRAL; } else { return FilterReply.DENY; } } } 

and then just call myFilter.start() and myAppender.addFilter(myFilter); .

  • Finally, I'm going to put everything together, I usually want to dynamically change the levels of the logs, having some simple interface in the setup, for example

     public interface LoggingService { void setRootLogLevel(Level level); } 

storing the root logging level in some property file, which is controlled in such a way that whenever there is some valid input, I just call this service, implemented as

  @Override public void setRootLogLevel(Level level) { if (context != null && context.isStarted()) { ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level); } } 

with my new root logger level.

0
Dec 03 '17 at
source share



All Articles