Search code examples
javalogginglogback

logback: Two appenders, multiple loggers, different levels


I want to have two log files in my application (Spring Integration), debug.log and main.log. I want to run main.log at an INFO level and debug.log at a DEBUG level. This is doable with filters on the appenders. I want to log different levels to the appenders based on the source. In other words

<logger name="org.springframework" level="ERROR">
    <appender-ref ref="main" />
</logger>
<logger name="org.springframework" level="DEBUG">
    <appender-ref ref="debug" />
</logger>
<logger name="com.myapp" level="INFO">
    <appender-ref ref="main" />
</logger>
<logger name="com.myapp" level="DEBUG">
    <appender-ref ref="debug" />
</logger>

So to summarise:

  1. Spring logger
    • main -> ERROR
    • debug -> DEBUG
  2. com.myapp logger
    • main -> INFO
    • debug -> DEBUG

Because of this I have to have the loggers running at DEBUG and a threshold filter on an appender isn't fine grained enough.

Update Added clarity to the question


Solution

  • Create a ThresholdLoggerFilter class which can be put on an appender like:

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <filter class="com.myapp.ThresholdLoggerFilter">
            <logger>org.springframework</logger>
            <level>ERROR</level>
        </filter>
    </appender>
    

    The following code works

    package com.myapp;
    
    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import ch.qos.logback.core.filter.Filter;
    import ch.qos.logback.core.spi.FilterReply;
    
    public class ThresholdLoggerFilter extends Filter<ILoggingEvent> {
        private Level level;
        private String logger;
    
        @Override
        public FilterReply decide(ILoggingEvent event) {
            if (!isStarted()) {
                return FilterReply.NEUTRAL;
            }
    
            if (!event.getLoggerName().startsWith(logger))
                return FilterReply.NEUTRAL;
    
            if (event.getLevel().isGreaterOrEqual(level)) {
                return FilterReply.NEUTRAL;
            } else {
                return FilterReply.DENY;
            }
        }
    
        public void setLevel(Level level) {
            this.level = level;
        }
    
        public void setLogger(String logger) {
            this.logger = logger;
        }
    
        public void start() {
            if (this.level != null && this.logger != null) {
                super.start();
            }
        }
    }