it-swarm.com.de

Programmgesteuertes Konfigurieren des LogBack-Appenders

Ich habe einen Logback-Appender in der logback.xml definiert, es ist ein DB-Appender, aber ich bin gespannt, ob es eine Möglichkeit gibt, den Appender in Java mit meinem eigenen Verbindungspool zu konfigurieren, der als definiert ist Bohne.

Ich finde ähnliche Dinge, aber nie die eigentliche Antwort.

63
user1732480

Hier ein einfaches Beispiel, das für mich funktioniert (beachte, 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); /* set to true if root should log too */

          return logger;
    }

}
106
reto

Sie können Appender programmgesteuert konfigurieren. Nahezu alle Appender werden mithilfe einer programmgesteuerten Konfiguration getestet. Daraus folgt, dass der Quellcode des Logback-Projekts viele Beispiele für die programmatische Appender-Konfiguration enthält. Einen Logback-Core-Appender finden Sie unter logback-core/src/test/Java, und für einen Logback-klassischen Appender unter logback-classic/src/test/Java.

14
Ceki

Wenn Sie versuchen, den für die Erstellung von Loggern verantwortlichen Code zu ändern, müssen eine Reihe von Regeln eingehalten werden, damit ein Logger funktioniert.

Diese Regeln wurden in einem großartigen und hilfreichen Artikel beschrieben Programmatische Konfiguration von slf4j/logback :

Jetzt habe ich Erfahrung mit der programmgesteuerten Konfiguration von slf4j/logback.

Aufgabe

Ein Programm muss für jede verarbeitete Eingabedatei eine eigene Protokolldatei öffnen.

Lösung für die Aufgabe

Anstatt die Rückmeldung über XML zu konfigurieren, müssen Encoder, Appender und Logger "manuell" instanziiert und dann konfiguriert und miteinander verknüpft werden.

Einschränkung 1

Beim Versuch, einen Encoder (d. H. PatternLayoutEncoder) für mehrere Appender freizugeben, wird die Rückmeldung verrückt.

Lösung für Vorbehalt 1

Erstellen Sie für jeden Appender einen eigenen Encoder.

Einschränkung 2

Logback weigert sich, etwas zu protokollieren, wenn Encoder und Appender nicht mit dem Protokollierungskontext verknüpft sind.

Lösung für Vorbehalt 2

Rufen Sie setContext für jeden Encoder und Appender auf und übergeben Sie LoggerFactory als Parameter.

Einschränkung 3

Logback weigert sich, etwas zu protokollieren, wenn Encoder und Appender nicht gestartet werden.

Lösung für Vorbehalt 3

encoder und Appender müssen in der richtigen Reihenfolge gestartet werden, d. h. zuerst Encoder, dann Appender.

Einschränkung 4

RollingPolicy-Objekte (d. H. TimeBasedRollingPolicy) erzeugen seltsame Fehlermeldungen wie "Datumsformat nicht erkannt", wenn sie nicht an denselben Kontext wie der Appender angehängt sind.

Lösung für Vorbehalt 4

rufen Sie setContext in RollingPolicy auf die gleiche Weise wie in Encodern und Appendern auf.

Hier ist ein Arbeitsbeispiel für die manuelle Konfiguration der Rückmeldung:

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.additive = false;
    log.level = Level.INFO;
    log.addAppender(logConsoleAppender);
    log.addAppender(logFileAppender);
  }
}
7
dominik

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 einen Logger programmatisch konfigurieren? Weil ich meine App (Spring Boot) in eine JAR-Datei packe. Folglich scheint sich die Datei Logback.xml in einem Glas zu verstecken. Das Auspacken und Wechseln ist jedoch nicht bequem. Und ich brauche nicht jede logback.xml-Datei neben meiner app.jar. Ich habe nur app.yaml-Datei, die alle Konfigurationseigenschaften für App enthält.

6
Yan Pak

Darf ich (noch?) Nicht kommentieren, möchte nur drei Tipps hinzufügen;

  • wenn Sie Probleme haben, rufen Sie einfach an

    StatusPrinter.print(context);
    

    nachdem alles konfiguriert wurde, dh nachdem Sie Ihre Appender hinzugefügt haben, wird der Root/"Main" Appender Ihnen sagen , was falsch ist.

  • Ich mag es sehr, Protokollebenen in verschiedenen Dateien zu trennen. Wenn ich nach Fehlern suche, beginne ich damit, in der Fehlerdatei nachzuschauen und sie wie folgt einzurichten

tot_[app name].log   : Level.INFO
deb_[app name].log   : Level.DEBUG
err_[app name].log   : Level.ERROR

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 rufen Sie einfach myFilter.start() und myAppender.addFilter(myFilter); auf.

  • Wenn ich es zusammenstelle, möchte ich normalerweise in der Lage sein, die Protokollebenen dynamisch zu ändern, wobei das Setup eine einfache Schnittstelle wie implementiert

    public interface LoggingService {
        void setRootLogLevel(Level level);
    }
    

behalten Sie die Root-Protokollierungsstufe in einer Eigenschaftendatei bei, die überwacht wird, sodass ich diesen Dienst einfach so implementiere, wenn dort eine gültige Eingabe vorhanden ist

    @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.

0
Ola Aronsson