Hier ein einfaches Beispiel, das für mich funktioniert (beachten Sie, dass ich in diesem Beispiel den FileAppender verwende)
import org.slf4j.LoggerFactory;
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 Loggerutils {
public static void main(String[] args) {
Logger foo = createLoggerFor("foo", "foo.log");
Logger bar = createLoggerFor("bar", "bar.log");
foo.info("test");
bar.info("bar");
}
private static Logger createLoggerFor(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.DEBUG);
logger.setAdditive(false);
return logger;
}
}
Logger
macht dieaddAppender()
Methode nicht mehr verfügbar .Logger
dass dieaddAppender
Methode nicht vorhanden ist, liegt es daran, dass Sie auf die AbstraktionsklasseLogger
von sl4j hinweisen. Wenn Sie auf die ImplementierungLogger
aus demlogback
Paket hinweisen, können Sie die verwendenaddAppender
. Der Nachteil dabei ist, dass Ihr Testcode an dielogback
Implementierung gekoppelt wird .lc.getLogger(string)
.Sie können Appender programmgesteuert konfigurieren. Fast alle Appender werden mit programmatischer Konfiguration getestet. Daraus folgt, dass der Quellcode des Logback-Projekts viele Beispiele für die Konfiguration programmatischer Appender enthält. Suchen Sie für einen Logback-Core-Appender unter
logback-core/src/test/java
und für einen Logback-klassischen Appender unterlogback-classic/src/test/java
.quelle
Wenn Sie versuchen, Code zu ändern, der für die Erstellung von Loggern verantwortlich ist, müssen als Referenz eine Reihe von Regeln erfüllt sein, damit ein Logger funktioniert.
Diese Regeln wurden in einem großartigen und hilfreichen Artikel Programmatische Konfiguration von slf4j / logback beschrieben :
package testpackage 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.core.ConsoleAppender import ch.qos.logback.core.rolling.RollingFileAppender import ch.qos.logback.core.rolling.TimeBasedRollingPolicy import org.slf4j.LoggerFactory class TestLogConfig { public static void main(String[] args) { LoggerContext logCtx = LoggerFactory.getILoggerFactory(); PatternLayoutEncoder logEncoder = new PatternLayoutEncoder(); logEncoder.setContext(logCtx); logEncoder.setPattern("%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n"); logEncoder.start(); ConsoleAppender logConsoleAppender = new ConsoleAppender(); logConsoleAppender.setContext(logCtx); logConsoleAppender.setName("console"); logConsoleAppender.setEncoder(logEncoder); logConsoleAppender.start(); logEncoder = new PatternLayoutEncoder(); logEncoder.setContext(logCtx); logEncoder.setPattern("%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n"); logEncoder.start(); RollingFileAppender logFileAppender = new RollingFileAppender(); logFileAppender.setContext(logCtx); logFileAppender.setName("logFile"); logFileAppender.setEncoder(logEncoder); logFileAppender.setAppend(true); logFileAppender.setFile("logs/logfile.log"); TimeBasedRollingPolicy logFilePolicy = new TimeBasedRollingPolicy(); logFilePolicy.setContext(logCtx); logFilePolicy.setParent(logFileAppender); logFilePolicy.setFileNamePattern("logs/logfile-%d{yyyy-MM-dd_HH}.log"); logFilePolicy.setMaxHistory(7); logFilePolicy.start(); logFileAppender.setRollingPolicy(logFilePolicy); logFileAppender.start(); Logger log = logCtx.getLogger("Main"); log.setAdditive(false); log.setLevel(Level.INFO); log.addAppender(logConsoleAppender); log.addAppender(logFileAppender); } }
quelle
java.lang.ClassCastException: org.apache.logging.slf4j.Log4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
"Main"
Name scheint ungültig zu sein.Logger.ROOT_LOGGER_NAME
ist"ROOT"
.Nur wenn jemand nach einem konkreten Beispiel für eine programmatische Konfiguration suchen würde.
Hier richte ich den Zeichensatz von ConsoleAppender ein:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); ConsoleAppender<ILoggingEvent> appender = (ConsoleAppender) lc.getLogger("appconsole").getAppender("STDOUT"); LayoutWrappingEncoder<ILoggingEvent> enc = (LayoutWrappingEncoder<ILoggingEvent>) appender.getEncoder(); enc.setCharset(Charset.forName("utf-8"));
Und meine logback.xml:
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>866</charset> <pattern>[%level] %msg%n</pattern> </encoder> </appender> <logger name="appconsole"> <appender-ref ref="STDOUT" /> </logger>
Warum muss ich programmgesteuert einen Logger konfigurieren? Weil ich meine App (Spring Boot) in eine JAR-Datei packe. Folglich scheint die Datei Logback.xml in einem Glas versteckt zu sein. Es ist jedoch nicht bequem, es auszupacken und zu ändern. Und ich brauche keine logback.xml-Datei neben meiner app.jar. Ich habe nur die Datei app.yaml, die alle Konfigurationseigenschaften für die App enthält.
quelle
(Noch?) Nicht kommentieren dürfen, ich möchte nur drei Tipps hinzufügen;
Wenn Sie Probleme haben, fügen Sie einfach einen Anruf hinzu
Nachdem alles konfiguriert wurde, dh nachdem Sie Ihre Appender hinzugefügt haben, wird Ihnen der Root / "Main" -Anhänger angezeigt, der Ihnen sagt, was falsch ist.
Ich mag es sehr, Protokollierungsstufen in verschiedenen Dateien zu trennen. Wenn ich nach Fehlern suche, beginne ich mit dem Suchen in der Fehlerdatei und so weiter
Routing mittels einer einfachen privaten Filterklasse wie z
private static class ThresholdLoggerFilter extends Filter<ILoggingEvent> { private final Level level; private ThresholdLoggerFilter(Level level){ this.level = level; } @Override public FilterReply decide(ILoggingEvent event) { if (event.getLevel().isGreaterOrEqual(level)) { return FilterReply.NEUTRAL; } else { return FilterReply.DENY; } } }
und dann einfach anrufen
myFilter.start()
undmyAppender.addFilter(myFilter);
.Wenn ich es zusammenstelle, möchte ich normalerweise in der Lage sein, die Protokollebenen dynamisch zu ändern, indem das Setup eine einfache Schnittstelle wie implementiert
public interface LoggingService { void setRootLogLevel(Level level); }
Halten Sie die Root-Protokollierungsstufe in einer Eigenschaftendatei, die überwacht wird, so dass ich diesen Dienst einfach als implementiert bezeichne, wenn dort eine gültige Eingabe vorliegt
@Override public void setRootLogLevel(Level level) { if (context != null && context.isStarted()) { ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level); } }
mit meinem neuen Root-Logger-Level.
quelle