Logback を設定して、ロガーのさまざまなレベルをさまざまな宛先に記録するにはどうすればよいですか?
たとえば、次のログバック構成がある場合、INFO
メッセージをSTDOUT
に、_ERROR
メッセージをSTDERR
に記録しますか?
(この例は、例logback-examples/src/main/Java/chapters/configuration/sample4.xml
のバリエーションであることに注意してください 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>
更新:Groovyを使用したすべての構成ベースのアプローチについては、 Dean Hillerの答え を参照してください。
-
Logback filters を使用すると、いくつかの興味深いことができます。以下の設定では、警告メッセージとエラーメッセージのみがstderrに出力され、その他はすべて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;
}
}
}
これが最も簡単な解決策になると思います。
<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>
構成のみに基づく解決策、ThresoldFilterおよびLevelFiltersを使用して物事を維持本当に簡単に理解できる:
<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>
さて、これが私のお気に入りのxml方法です。 Eclipseバージョンに対してこれを行うので、
何らかの理由でSOはこれをすべて適切に表示していませんが、ほとんどがそこにあるようです...
<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>
最も簡単な解決策は、アペンダーでThresholdFilter
を使用することです。
<appender name="..." class="...">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
完全な例:
<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>
更新:Mikeがコメントで指摘したように、ERRORレベルのメッセージは、STDOUTとSTDERRの両方にここに出力されます。ただし、OPの意図は不明です。これが望んでいない場合、マイクの答えを試すことができます。
これは私が使用する構成で、正常に動作し、XML + JaninoEventEvaluatorに基づいています( 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>
Logback.groovyを使用してlogbackを構成しますが、xml configでも同様に実行できます。
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"])
フィルタークラスを作成する必要がないため、GEventEvaluatorを使用する方が簡単だと思います。
英語がおaびします!
これを試して。組み込みのThresholdFilter
とLevelFilter
を使用できます。プログラムで独自のフィルターを作成する必要はありません。この例では、WARNレベルとERRORレベルがSystem.errに記録され、残りが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>
X. Wo SatukとSébastienHelbertの最高の2つの答えの組み合わせに過ぎないため、この答えは信用しません。ThresholdFilter
は素敵ですが、アッパーを設定することはできませんレベルと同様に下位レベル*ですが、「拒否」に設定された2つのLevelFilters
とWARN
およびERROR
を組み合わせることはおやつです。
非常に重要です:STDERRアペンダーの<target>System.err</target>
タグを忘れないでください:省略したため、数分間イライラしていました。
<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>
*ただし、 API にはdecide
というメソッドがありますが、このコンテキストでどのように使用するかはわかりません。
プログラミングは不要です。構成はあなたの人生を楽にします。
以下は、異なるレベルのログを異なるファイルに記録する構成です
<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
レベル「INFO」以上の色付きメッセージをconsoleに、レベル「WARN」以上のメッセージをfileに出力する方法の例。
logback.xmlファイル:
<?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>