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>
I believe this would be the simplest solution:
<configuration>
<contextName>selenium-plugin</contextName>
<!-- Logging configuration -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.out</Target>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] %msg%n</pattern>
</encoder>
</appender>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.err</Target>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="STDERR" />
</root>
</configuration>
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;
}
}
}
Solution based on configuration only, with a ThresoldFilter and LevelFilters to keep things really simple to understand :
<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<encoder>
<pattern>%date %level [%thread] %logger %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>TRACE</level>
<onMatch>ACCEPT</onMatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>DENY</onMatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
</filter>
<encoder>
<pattern>%date %level [%thread] %logger %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="STDERR" />
</root>
</configuration>
okay, here is my favorite xml way of doing it. I do this for the eclipse version so I can
click on stuff to take me to the log statements and
see info and below in black and warn/severe in red
and for some reason SO is not showing this all properly but most seems to be there...
<configuration scan="true" scanPeriod="30 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator">
<expression>
e.level.toInt() <= INFO.toInt()
</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
<encoder>
<pattern>%date{ISO8601} %X{sessionid}-%X{user} %caller{1} %-4level: %message%n</pattern>
</encoder>
</appender>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>warn</level>
</filter>
<encoder>
<pattern>%date{ISO8601} %X{sessionid}-%X{user} %caller{1} %-4level: %message%n</pattern>
</encoder>
<target>System.err</target>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="STDOUT"/>
<appender-ref ref="STDERR"/>
</root>
</configuration>
The simplest solution is to use ThresholdFilter on the appenders:
<appender name="..." class="...">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
Full example:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%d %-5level: %msg%n</pattern>
</encoder>
</appender>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<target>System.err</target>
<encoder>
<pattern>%d %-5level: %msg%n</pattern>
</encoder>
</appender>
<root>
<appender-ref ref="STDOUT" />
<appender-ref ref="STDERR" />
</root>
</configuration>
Update: As Mike pointed out in the comment, messages with ERROR level are printed here both to STDOUT and STDERR. Not sure what was the OP's intent, though. You can try Mike's answer if this is not what you wanted.
This is the configuration that I use, which works fine, it is based on XML + JaninoEventEvaluator (requires the Janino library to be added to Classpath)
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date | [%-5level] in [%file:%line] - %msg %n</pattern>
</encoder>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<expression>
level <= INFO
</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
</appender>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%date | [%-5level] in [%file:%line] - %msg %n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="STDERR" />
</root>
</configuration>
I use logback.groovy to configure my logback but you can do it with xml config as well:
import static ch.qos.logback.classic.Level.*
import static ch.qos.logback.core.spi.FilterReply.DENY
import static ch.qos.logback.core.spi.FilterReply.NEUTRAL
import ch.qos.logback.classic.boolex.GEventEvaluator
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.filter.EvaluatorFilter
def patternExpression = "%date{ISO8601} [%5level] %msg%n"
appender("STDERR", ConsoleAppender) {
filter(EvaluatorFilter) {
evaluator(GEventEvaluator) {
expression = 'e.level.toInt() >= WARN.toInt()'
}
onMatch = NEUTRAL
onMismatch = DENY
}
encoder(PatternLayoutEncoder) {
pattern = patternExpression
}
target = "System.err"
}
appender("STDOUT", ConsoleAppender) {
filter(EvaluatorFilter) {
evaluator(GEventEvaluator) {
expression = 'e.level.toInt() < WARN.toInt()'
}
onMismatch = DENY
onMatch = NEUTRAL
}
encoder(PatternLayoutEncoder) {
pattern = patternExpression
}
target = "System.out"
}
logger("org.hibernate.type", WARN)
logger("org.hibernate", WARN)
logger("org.springframework", WARN)
root(INFO,["STDERR","STDOUT"])
I think to use GEventEvaluator is simplier because there is no need to create filter classes.
I apologize for my English!
I take no credit for this answer, as it's merely a combination of the best two answers above: that of X. Wo Satuk and that of Sébastien Helbert: ThresholdFilter is lovely but you can't configure it to have an upper level as well as a lower level*, but combining it with two LevelFilters set to "DENY" WARN and ERROR works a treat.
Very important: do not forget the <target>System.err</target> tag in the STDERR appender: my omission of it had me frustrated for a few minutes.
<configuration>
<timestamp key="byDay" datePattern="yyyyMMdd'T'HHmmss" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>DENY</onMatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\)
- %msg%n
</pattern>
</encoder>
</appender>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\)
- %msg%n
</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="STDERR" />
</root>
</configuration>
* it does however have a method decide in the API but I haven't a clue how you'd use it in this context.
Try this. You can just use built-in ThresholdFilter and LevelFilter. No need to create your own filters programmically. In this example WARN and ERROR levels are logged to System.err and rest to System.out:
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!-- deny ERROR level -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
</filter>
<!-- deny WARN level -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>DENY</onMatch>
</filter>
<target>System.out</target>
<immediateFlush>true</immediateFlush>
<encoder>
<charset>utf-8</charset>
<pattern>${msg_pattern}</pattern>
</encoder>
</appender>
<appender name="stderr" class="ch.qos.logback.core.ConsoleAppender">
<!-- deny all events with a level below WARN, that is INFO, DEBUG and TRACE -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<target>System.err</target>
<immediateFlush>true</immediateFlush>
<encoder>
<charset>utf-8</charset>
<pattern>${msg_pattern}</pattern>
</encoder>
</appender>
<root level="WARN">
<appender-ref ref="stderr"/>
</root>
<root level="TRACE">
<appender-ref ref="stdout"/>
</root>
No programming needed. configuration make your life easy.
Below is the configuration which logs different level of logs to different files
<property name="DEV_HOME" value="./logs" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} %-5level - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE-ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${DEV_HOME}/app-error.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} %-5level - %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${DEV_HOME}/archived/app-error.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<!--output messages of exact level only -->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILE-INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${DEV_HOME}/app-info.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} %-5level - %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${DEV_HOME}/archived/app-info.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<!--output messages of exact level only -->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILE-DEBUG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${DEV_HOME}/app-debug.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${DEV_HOME}/archived/app-debug.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<!--output messages of exact level only -->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILE-ALL"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${DEV_HOME}/app.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${DEV_HOME}/archived/app.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="com.abc.xyz" level="DEBUG" additivity="true">
<appender-ref ref="FILE-DEBUG" />
<appender-ref ref="FILE-INFO" />
<appender-ref ref="FILE-ERROR" />
<appender-ref ref="FILE-ALL" />
</logger>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<configuration scan="true" scanPeriod="60 seconds">
<appender name="A1" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${storm.log.dir}/${logfile.name}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${storm.log.dir}/${logfile.name}.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>9</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>100MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ} %c{1} [%p] %m%n</pattern>
</encoder>
</appender>
<appender name="ACCESS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${storm.log.dir}/access.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${storm.log.dir}/access.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>9</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>100MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ} %c{1} [%p] %m%n</pattern>
</encoder>
</appender>
<appender name="METRICS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${storm.log.dir}/metrics.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${storm.log.dir}/logs/metrics.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>9</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>2MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d %-8r %m%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="A1"/>
</root>
<logger name="backtype.storm.security.auth.authorizer" additivity="false">
<level value="INFO" />
<appender-ref ref="ACCESS" />
</logger>
<logger name="backtype.storm.metric.LoggingMetricsConsumer" additivity="false" >
<level value="INFO"/>
<appender-ref ref="METRICS"/>
</logger>
</configuration>
So here is the logback file in which I am not printing backtype.storm.metric.LoggingMetricsConsumer info level if i say additivity = "true" then for for all classes in backtype.* this rule will be applied
Example of how to output colored messages of level "INFO" or higher to console and messages of level "WARN" or higher to file.
Your logback.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<!--output messages of exact level only-->
<!--<onMatch>ACCEPT</onMatch>-->
<!--<onMismatch>DENY</onMismatch>-->
</filter>
<encoder>
<pattern>%d{yyyy-MMM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n
</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myfile.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<append>true</append>
<encoder>
<pattern>%d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE"/>
</root>
</configuration>
I tried the following logback-test.xml
<configuration>
<root level="INFO">
<appender class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} | %-5level | %thread | %logger{1} | %m%n</pattern>
</encoder>
</appender>
</root>
<root level="DEBUG">
<appender class="ch.qos.logback.core.FileAppender">
<file>logs/integration.log</file>
<encoder>
<pattern>%d{ISO8601} | %-5level | %thread | %logger{1} | %m%n</pattern>
</encoder>
</appender>
</root>
</configuration>
but console is still at DEBUG level. Does anyone know what I am doing wrong?
you should consider using LevelFilter. So you set root level as debug and then apply level filter for your appenders. Here is an example configuration:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="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>
<file>myFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>myFile.%i.log.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10 MB</maxFileSize>
</triggeringPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d{ISO8601} [%t] %-5p %c{0} - %m%n</Pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
Read more in this article: https://amitstechblog.wordpress.com/2014/09/27/logging-different-log-levels-to-different-appenders-with-logback/
I would like to see all info level output from console, and ONLY warn output from file.
Info level output on console is clearly shown, but all Info output is saved on file too, not only warn level output.
Here is my logback configuration. Any wrong in here?
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{20} [%mdc{threadid}] - [%mdc{useroid} : %mdc{sessionid}]%msg%n</pattern>
</encoder>
</appender>
<appender name="consoleFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<prudent>true</prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/console.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level | %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console" />
</root>
<root level="WARN">
<appender-ref ref="consoleFileAppender" />
</root>
For your purpose I suggest to use filters in your appender. More specifically, if you want to see only INFO on console you can add a specific LevelFilter in your console appender, if you want to see all logs equals or above to INFO, you can use ThresholdFilter.
Here there is a possible solution for your task:
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{20} [%mdc{threadid}] - [%mdc{useroid} : %mdc{sessionid}]%msg%n</pattern>
</encoder>
</appender>
<appender name="FileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<prudent>true</prudent>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/console.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level | %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="FileAppender" />
</root>
I am using SLF4j and logback to log messages. It works fine and writes to configured file. But when I build a executable jar and try to run from prompt as java -jar executableFile. It neither writes to configured file, also displays tons of debug messages on console.
this my logback.xml:
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{ISO8601} %-5level %logger{36} %X{sourceThread} - %msg%n</pattern>
</encoder>
</appender>-->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/LogWriter/log-test.log </file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>/var/log/LogWriter/log-test.log.%i.log.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%date{ISO8601} %-5level %logger{36} %X{sourceThread} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
The reason is that your main class is not finding logback.xml, so logback uses the default appender - the console in this case. You need to make sure that when packing the jar, the logback.xml is in the correct place.
I am trying to write logs in two files, in one file I am ok to get the logs of any level, and in other file I am looking for only INFO level. Is this possible?
<configuration>
<appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
<file>c:/log/myLogFile.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder>
<pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="EVENTS_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>c:/log/myLogFile-event.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>../logs/cweo-app-event-%i.log.gz</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>30</maxIndex>
</rollingPolicy>
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>100MB</maxFileSize>
</triggeringPolicy>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<!-- <logger name="event" level="DEBUG"> <appender-ref ref="EVENTS_FILE"
/> </logger> -->
<root>
<appender-ref ref="fileAppender" />
<appender-ref ref="EVENTS_FILE" />
</root>
This is my logback.xml where in EVENTS_FILE I want to print only INFO messages nothing else.
Don't use ThresholdFilter, use LevelFilter.
LevelFilter provides equality testing, unlike ThresholdFilter. See Filters.
In this case:
<appender name="EVENTS_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>c:/log/myLogFile-event.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>