Comment configurer Logback pour enregistrer différents niveaux pour un enregistreur vers différentes destinations?
Par exemple, étant donné la configuration suivante de Logback, Logback enregistrera-t-il les messages INFO
dans STDOUT
et ERROR
dans STDERR
?
(Notez que cet exemple est une variante de l'exemple logback-examples/src/main/Java/chapters/configuration/sample4.xml
présenté dans Chapitre 3: Configuration de la journalisation ).
<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>
Mise à jour: pour une approche basée sur la configuration avec Groovy, voir Réponse de Dean Hiller .
-
Vous pouvez faire des choses intéressantes avec Filtres de journal . La configuration ci-dessous n’imprimera que les messages d’avertissement et d’erreur sur stderr et tout le reste sur 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;
}
}
}
Je crois que ce serait la solution la plus simple:
<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>
Solution basée uniquement sur la configuration, avec ThresoldFilter et LevelFilters pour simplifier les choses:
<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>
ok, voici ma façon préférée de le faire xml. Je fais cela pour la version Eclipse afin que je puisse
et pour une raison quelconque SO ne montre pas tout cela correctement, mais la plupart semblent être là.
<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>
La solution la plus simple consiste à utiliser ThresholdFilter
sur les ajouts:
<appender name="..." class="...">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
Exemple complet:
<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>
Mise à jour: Comme Mike l'a souligné dans le commentaire, les messages avec le niveau ERROR sont imprimés ici pour STDOUT et STDERR. Je ne sais pas quelle était l'intention du PO, cependant. Vous pouvez essayer la réponse de Mike si ce n'est pas ce que vous vouliez.
C’est la configuration que j’utilise, qui fonctionne très bien, elle est basée sur XML + JaninoEventEvaluator (nécessite l’ajout de la bibliothèque Janino à 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>
J'utilise logback.groovy pour configurer mon journal, mais vous pouvez aussi le faire avec la configuration xml:
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"])
Je pense que l'utilisation de GEventEvaluator est plus simple car il n'est pas nécessaire de créer des classes de filtres.
Je m'excuse pour mon anglais!
Essaye ça. Vous pouvez simplement utiliser ThresholdFilter
et LevelFilter
intégrés. Pas besoin de créer vos propres filtres par programmation. Dans cet exemple, les niveaux WARN et ERROR sont consignés dans System.err et restent dans 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>
Je ne prends aucun crédit pour cette réponse, car il s’agit simplement d’une combinaison des deux meilleures réponses ci-dessus: celle de X. Wo Satuk et celle de Sébastien Helbert: ThresholdFilter
niveau ainsi qu’un niveau inférieur *, mais en le combinant avec deux options LevelFilters
, paramétré sur "DENY" WARN
et ERROR
, fait des merveilles.
Très important: n'oubliez pas la balise <target>System.err</target>
dans l'appendeur STDERR: mon omission m'avait frustré pendant quelques 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>
* il a cependant une méthode decide
dans le API mais je ne sais pas comment vous l'utiliseriez dans ce contexte.
Aucune programmation nécessaire. la configuration vous rend la vie facile.
Vous trouverez ci-dessous la configuration qui enregistre différents niveaux de journaux dans différents fichiers.
<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
Exemple de sortie de messages colorés de niveau "INFO" ou supérieurs vers console et de messages de niveau "WARN" ou supérieurs vers fichier .
Votre logback.xml fichier:
<?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>