
1. Overview
In this article, we will understand the LogBack with multiple log files. If you like to categorize and write the log statements to different files, then you can do so by using multiple appenders.
2. LogBack multiple log files
Let’s see various use cases for writing log statements to multiple different files.
The following image illustrates the different logging levels and the corresponding logging statements included.
For example, setting the logging level of your project to ERROR will display only error and fatal log statements. Similarly, the logging level debug will display debug, info, warn, error, and fatal log statements.

We have sorted the logging level by descending importance. So, TRACE < DEBUG < INFO < WARN < ERROR < FATAL. The logging level FATAL is of very high importance, whereas the TRACE is of very low importance.
2.1. Debug and error logs to multiple log files
If you like to print debug and error logs in different files, then you can use the below configuration.
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}error.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}error%d{yyyy-MM-dd-HH-mm}.log </fileNamePattern> <maxHistory>7</maxHistory> <totalSizeCap>1MB</totalSizeCap> </rollingPolicy> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n </pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> </appender> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}debug.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}debug%d{yyyy-MM-dd-HH-mm}.log </fileNamePattern> <maxHistory>7</maxHistory> <totalSizeCap>1MB</totalSizeCap> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n </pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="STDOUT" /> </root> </configuration>
In the first place, we have defined the root log level of the project as DEBUG. So it considers only the debug log level and its above levels such as INFO, ERROR, FATAL, WARN.
<root level="DEBUG"> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="STDOUT" /> </root>
We have created three appenders: ConsoleAppender, Debug RollingFileAppender and ERROR RollingFileAppender.
The ConsoleAppender displays the debug and also the above level log statements (WARN, TRACE, INFO) in the console.
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender>
The below DEBUG_FILE appender writes only the debug statements to the debug.log file. Note the LevelFilter accepts only debug log statements and denies everything else.
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> .... <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
The below ERROR_FILE appender uses the ThresholdFilter which allows the mentioned ERROR level and its above levels (FATAL). So this appender will display error and fatal log statements in the file.
<appender name="ERROR_FILE" ... <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> </appender>
2.2. Custom Filter for logging in multiple log files.
In the previous section, the LogBack updated only the debug statements to the debug.log file. Assume, you also want to write the info statements to the debug.log file. It is feasible by using the custom filter.
You can use custom filter to decide which log statements should go to the file. The below custom filter accepts any number of levels like DEBUG, INFO and so on.
package com.tedblob.logback.multiplelog; import java.util.ArrayList; import java.util.List; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.filter.AbstractMatcherFilter; import ch.qos.logback.core.filter.Filter; import ch.qos.logback.core.spi.FilterReply; public class CustomFilter extends AbstractMatcherFilter<ILoggingEvent> { List<Level> levels = new ArrayList<Level>(); @Override public FilterReply decide(ILoggingEvent event) { if (!isStarted()) { return FilterReply.NEUTRAL; } if (levels.contains(event.getLevel())) { return onMatch; } else { return onMismatch; } } public void setLevel(Level level) { levels.add(level); } }
You can use the above CustomFilter in your xml configuration as below. We have declared two levels INFO and DEBUG. Thus, LogBack writes both info and debug statements to the log file.
<filter class="com.tedblob.logback.multiplelog.CustomFilter"> <level>INFO</level> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
The DEBUG_FILE appender writes both the debug and info statements to the log file.
<configuration> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}error.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}error%d{yyyy-MM-dd-HH-mm}.log </fileNamePattern> <maxHistory>7</maxHistory> <totalSizeCap>1MB</totalSizeCap> </rollingPolicy> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n </pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> </appender> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}debug.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}debug%d{yyyy-MM-dd-HH-mm}.log </fileNamePattern> <maxHistory>7</maxHistory> <totalSizeCap>1MB</totalSizeCap> </rollingPolicy> <filter class="com.tedblob.logback.multiplelog.CustomFilter"> <level>INFO</level> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n </pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="DEBUG_FILE" /> </root> </configuration>

3. Conclusion
To sum up, this article focuses on the LogBack logging to multiple log files. We updated the samples to GitHub – Multiple log files and Custom filter for controlling the log statements updated in the log file.