Ich möchte zwei Protokolldateien in meiner Anwendung (Spring Integration), debug.log und main.log. Ich möchte main.log auf einer INFO-Ebene und debug.log auf einer DEBUG-Ebene ausführen. Dies ist mit Filtern auf den Appendern möglich. Ich möchte verschiedene Ebenen zu den Appendern basierend auf der Quelle protokollieren. Mit anderen Worten
<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>
Also zusammenfassend:
Aus diesem Grund muss ich die Logger auf DEBUG laufen lassen und ein Schwellenwertfilter auf einem Appender ist nicht fein genug.
Update Die Frage wurde klarer
Erstellen Sie eine ThresholdLoggerFilter-Klasse, die auf einem Appender wie folgt abgelegt werden kann:
<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>
Der folgende Code funktioniert
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();
}
}
}
Sie können dies auch etwas einfacher tun, wenn Sie vom Root-Logger erben möchten, z. Hier fügen wir einen zusätzlichen Logger für Fehler hinzu, der in stderr protokolliert. Es ist nur für bestimmte Logger aktiviert.
<configuration>
<appender name="CONSOLE-stdout" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern>
</encoder>
</appender>
<appender name="CONSOLE-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 [%thread] %logger{0}: %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE-stdout" />
</root>
<!-- We want error logging from this logger to go to an extra appender
It still inherits CONSOLE-stdout from the root logger -->
<logger name="org.springframework" level="INFO">
<appender-ref ref="CONSOLE-stderr" />
</logger>
</configuration>
Keine dieser Lösungen hat für mich funktioniert, da ich kein Framework wie Spark oder Spring verwende. Also habe ich etwas einfacher gemacht, das gut zu funktionieren scheint. Während diese Lösung für das OP möglicherweise nicht funktioniert, kann es für jemanden nützlich sein, der etwas nicht so sperriges möchte.
<property name="pattern" value="%d{yyyy.MMM.dd HH:mm:ss.SSS} [ProgramName] %level - %msg%n" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/path/to/your/program.log</file>
<append>true</append>
<encoder>
<pattern>${pattern}</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>${pattern}</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
Mit dieser Konfiguration kann ich die Konsole ziemlich sauber halten und gleichzeitig DEBUG-Anweisungen in die Protokolldatei ausgeben.
Ich habe gerade eine praktische Lösung mit Logback-Elementen gefunden, die ziemlich gut funktioniert. Im Wesentlichen müssen Sie zwei Appender haben, einen mit der Standardkonfiguration und den anderen mit einem Filter (in meinem Beispiel verwende ich die Konsole):
<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="WARN_FILTER_STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.Apache.spark" level="INFO" additivity="false">
<appender-ref ref="SPARK" /><!-- this line is not necessary, just here to ilustrate the need for the filter -->
<appender-ref ref="WARN_FILTER_STDOUT" />
</logger>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
Die Verwendung mehrerer Logger für verschiedene Nachrichten sieht folgendermaßen aus:
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;
public class ConfigureLogBack
{
public static void programmaticConfiguration()
{
Logger camel = getLogger("MyRoute", C:\\Users\\amrut.malaji\\Desktop\\Oracle\\logback\\camel-Log.txt");
Logger services = getLogger("webservices", "C:\\Users\\amrut.malaji\\Desktop\\Oracle\\logback\\services-log.txt");
}
private static Logger getLogger(String string, String file) {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder ple = new PatternLayoutEncoder();
ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
ple.setContext(lc);
ple.start();
FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
fileAppender.setFile(file);
fileAppender.setEncoder(ple);
fileAppender.setContext(lc);
fileAppender.start();
Logger logger = (Logger) LoggerFactory.getLogger(string);
logger.addAppender(fileAppender);
logger.setLevel(Level.INFO);
logger.setAdditive(false); /* set to true if root should log too */
return logger;
}
ein Schwellenwertfilter für einen Appender ist nicht fein genug
Sie können einen EvaluatorFilter verwenden. Ein JaninoEventEvaluator würde einen Verweis auf Janino (.jar) benötigen, und ein Beispiel für logback.xml wäre:
<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.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<expression>
level <= ERROR && logger.equals("com.myapp.ThresholdLoggerFilter")
</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
</appender>
Dieser Ansatz verwendet einen Java-Ausdruck im Ausdruckstag (muss xml-geschützt sein), um das Protokollierungsereignis auszuwerten, und es muss keine benutzerdefinierte Java-Klasse geschrieben werden.