Search code examples
javalogginglogback

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


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

For example, given the following Logback configuration, will Logback record INFO messages to STDOUT and ERROR messages to STDERR?

(Note that this example is a variation of example logback-examples/src/main/java/chapters/configuration/sample4.xml shown in Chapter 3: Logback 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="STDERR"
   class="ch.qos.logback.core.ConsoleAppender">
   <encoder>
     <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      </pattern>
    </encoder>
    <target>System.err</target>
  </appender>
  <!-- What is the effective level of "chapters.configuration"? -->
  <logger name="chapters.configuration" level="INFO" additivity="false">
    <appender-ref ref="STDOUT" />
  </logger>
  <logger name="chapters.configuration" level="ERROR" additivity="false">
    <appender-ref ref="STDERR" />
  </logger>

  <!-- turn OFF all logging (children can override) -->
  <root level="OFF">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Solution

  • Update: For an all configuration based approach using Groovy see Dean Hiller's answer.

    --

    You can do some interesting things with Logback filters. The below configuration will only print warn and error messages to stderr, and everything else to stdout.

    logback.xml

    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
      <target>System.out</target>
      <filter class="com.foo.StdOutFilter" />
       ...
    </appender>
    
    <appender name="stderr" class="ch.qos.logback.core.ConsoleAppender">
      <target>System.err</target>
      <filter class="com.foo.ErrOutFilter" />
       ...
    </appender>
    
    <logger name="mylogger" level="debug">
        <appender-ref ref="stdout" />
        <appender-ref ref="stderr" />
    </logger>
    

    com.foo.StdOutFilter

    public class StdOutFilter extends ch.qos.logback.core.filter.AbstractMatcherFilter
    {
    
        @Override
        public FilterReply decide(Object event)
        {
            if (!isStarted())
            {
                return FilterReply.NEUTRAL;
            }
    
            LoggingEvent loggingEvent = (LoggingEvent) event;
    
            List<Level> eventsToKeep = Arrays.asList(Level.TRACE, Level.DEBUG, Level.INFO);
            if (eventsToKeep.contains(loggingEvent.getLevel()))
            {
                return FilterReply.NEUTRAL;
            }
            else
            {
                return FilterReply.DENY;
            }
        }
    
    }
    

    com.foo.ErrOutFilter

    public class ErrOutFilter extends ch.qos.logback.core.filter.AbstractMatcherFilter
    {
    
        @Override
        public FilterReply decide(Object event)
        {
            if (!isStarted())
            {
                return FilterReply.NEUTRAL;
            }
    
            LoggingEvent loggingEvent = (LoggingEvent) event;
    
            List<Level> eventsToKeep = Arrays.asList(Level.WARN, Level.ERROR);
            if (eventsToKeep.contains(loggingEvent.getLevel()))
            {
                return FilterReply.NEUTRAL;
            }
            else
            {
                return FilterReply.DENY;
            }
        }
    
    }