Explain Codes LogoExplain Codes Logo

How can I configure Logback to log different levels for a logger to different destinations?

java
logging
logback
configuration
Alex KataevbyAlex Kataev·Jan 25, 2025
TLDR

To route logs of different levels to separate destinations in Logback, configure two appenders with level-specific filters. For example, to divert INFO logs to console and DEBUG logs to a file, use the <filter> element within each <appender> element. Here is a simplified setup for such a distinction:

<configuration> <!-- Console appender for INFO, because brevity is the soul of wit --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <!-- Encoder, like a secret agent, omitted for now --> </appender> <!-- File appender for DEBUG, more verbose than a politician --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <!-- Encoder and rolling policy are having a coffee break, so they're omitted --> </appender> <!-- Logger configuration, the puppet master of our log circus --> <logger name="com.yourpackage" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </logger> </configuration>

Modify the <logger> name to match your package. This guarantees INFO will output to console and DEBUG to the specified log file.

Beyond Basics: Tailoring your Logback

The quick & dirty example above separates INFO from DEBUG logs. But coding life is rarely straightforward and requires custom setups (and probably more coffee). How about logging ERROR level messages to STDERR or even external destinations like Slack or email? With the might of <target> and custom filters, we reach our logging nirvana.

Splitting the log stream between STDOUT and STDERR

Directing ERROR to STDERR and INFO to STDOUT in Logback needs two ConsoleAppender instances, each with its own target:

<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender"> <target>System.err</target> <!-- Error logs go here, it's like a VIP section for grumpy logs --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- Encoder, not to mix up with Enigma --> </appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- The chatty INFO logs go here --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- Here be Encoder --> </appender>

Achieving beauty in log form

An effective encoding pattern is at the heart of good log design. You just do it once and ensure coherence across all your appenders:

<encoder> <!-- Just like at an airport: date, level, thread, logger and message --> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder>

Taming Logback with filters and evaluators

If ThresholdFilter is a helpful assistant, custom filters and evaluators are like having a personal concierge. They let you dictate intricate criteria for log distribution. Empower your logging with them to truly rule your application’s logs.

Context matters: Logging in larger applications

Working with a large application? Different modules might require their own logging ecosystems. ContextName assigns different logging contexts to parts of your application:

<configuration scan="true" scanPeriod="30 seconds" debug="false"> <!-- Define the context name --> <contextName>myAppName</contextName> <!-- Define the appenders and their configurations here --> <!-- ... --> </configuration>

Power of Groovy: Dynamic logging setup

Take a break from XML and jump into Groovy configurations. Coding conditions based on your environment or real-time changes are just a few benefits of this dynamic flavor. Logback in style with Groovy.

Troubleshooting like a pro: Internal status data

Logback can report its internal status, invaluable when troubleshooting your configuration:

<configuration> <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" /> <!-- Rest of configuration goes here --> </configuration>