Articles

Wie Log4J2 funktioniert: 10 Möglichkeiten, das Beste daraus zu machen

Log4j2 ist die aktualisierte Version der beliebten und einflussreichen log4j-Bibliothek, die seit so vielen Jahren im gesamten Java-Ökosystem verwendet wird. Ausführung 2.x behält alle Protokollierungsfunktionen seines Vorgängers bei und baut auf dieser Grundlage mit einigen signifikanten Verbesserungen auf, insbesondere im Bereich der Leistung.

Und natürlich, da die Protokollierung für jede Anwendung sowohl für Audit- als auch für Debugging-Zwecke instrumentell ist, ist die Wahl einer soliden Protokollierungsbibliothek eine ziemlich wichtige Entscheidung.

In den folgenden Abschnitten werden wir einen Blick darauf werfen, warum die log4j2-Bibliothek eine gute Wahl für diese Entscheidung ist und wie wir sie in einer Anwendung verwenden können.

Grundlegende Log4j2-Konfiguration

Um log4j2 in Ihrem Projekt zu verwenden, müssen Sie lediglich die Abhängigkeit log4j-core hinzufügen. Wenn Sie Maven verwenden, können Sie Ihrem Pom die folgende Abhängigkeit hinzufügen.xml-Datei:

Und wenn Sie mit Gradle arbeiten, müssen Sie die Abhängigkeit zum Build hinzufügen.gradle-Datei:

dependencies { compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2'}

Standardmäßig stellt log4j2 automatisch eine einfache Konfiguration bereit, wenn Sie selbst keine explizit definieren. Die Standardkonfigurationsprotokolle an der Konsole auf einer Fehlerstufe oder höher.

Um die Protokollierung von Nachrichten mit dieser Grundkonfiguration zu starten, müssen Sie lediglich eine Logger-Instanz mit der LogManager-Klasse abrufen:

private static Logger logger = LogManager.getLogger(MyService.class);

Anschließend können Sie das Logger-Objekt mit Methoden verwenden, die der gewünschten Protokollebene entsprechen:

logger.error("This is an error message");

Anpassen der Log4j2-Konfiguration

Eine benutzerdefinierte log4j2-Konfiguration kann entweder programmgesteuert oder über eine Konfigurationsdatei erstellt werden.

Die Bibliothek unterstützt Konfigurationsdateien in XML, JSON, YAML geschrieben, sowie die .eigenschaften Format. Hier werden wir XML verwenden, um alle Beispiele in erster Linie zu diskutieren.

Zunächst können Sie die Standardkonfiguration überschreiben, indem Sie einfach ein log4j2 erstellen.xml-Datei auf dem Klassenpfad:

Werfen wir einen genaueren Blick auf die Tags, die in dieser einfachen Konfiguration verwendet werden:

  • Konfiguration: das Root-Element einer log4j2-Konfigurationsdatei; das status-Attribut stellt die Ebene dar, auf der interne log4j-Ereignisse protokolliert werden sollen
  • Appenders: Dieses Element enthält eine Liste von Appendern; in unserem Beispiel ist ein Appender definiert, der der Systemkonsole entspricht
  • Loggers: Dieses Element enthält eine Liste von Logger-Instanzen. Das Root-Element ist ein Standard-Logger, der alle Nachrichten ausgibt

Es ist wichtig zu verstehen, dass der Root-Logger in jeder Konfiguration obligatorisch ist. Wie bereits erwähnt, wird es standardmäßig automatisch mit einem Konsolen-Appender und der Fehlerprotokollebene konfiguriert, wenn Sie keinen bereitstellen.

Appender konfigurieren

In der log4j2-Architektur ist ein Appender grundsätzlich dafür verantwortlich, Protokollnachrichten an ein bestimmtes Ausgabeziel zu senden.

Hier sind einige der nützlichsten Arten von Appendern, die die Bibliothek bereitstellt:

  • ConsoleAppender – protokolliert Nachrichten an die Systemkonsole
  • FileAppender – schreibt Protokollnachrichten in eine Datei
  • RollingFileAppender – schreibt die Nachrichten in eine rollierende Protokolldatei
  • JDBCAppender – verwendet eine relationale Datenbank für Protokolle
  • AsyncAppender – enthält eine Liste anderer Appender und bestimmt die Protokolle für diese, die in einem separaten Thread geschrieben werden sollen

Um besser zu verstehen, wie Appender funktionieren, schauen wir uns einige Konfigurationsbeispiele an.

Der RollingFileAppender

Alles in einer einzigen Datei zu protokollieren ist natürlich nicht ideal. Es ist normalerweise viel besser, die aktive Protokolldatei regelmäßig zu übertragen – genau das tut der RollingFileAppender.

Mit dieser Art von Appender können Sie auch über die Grundlagen hinausgehen und sowohl eine benutzerdefinierte Auslöserichtlinie als auch eine Rollover-Strategie konfigurieren.

Die Auslöserichtlinie bestimmt, wann die Protokolldatei gerollt wird, d. h. eine neue Datei wird erstellt, während die Rollover-Strategie bestimmt, wie die Datei gerollt wird.

Lassen Sie uns als kurzes Beispiel einen Appender konfigurieren, der eine neue Protokolldatei basierend auf 3 Richtlinien erstellt:

  • OnStartupTriggeringPolicy – Bei jedem Start der JVM wird eine neue Protokolldatei erstellt
  • TimeBasedTriggeringPolicy – Die Protokolldatei wird basierend auf einem Datum / Uhrzeit–Muster gerollt
  • SizeBasedTriggeringPolicy – Die Datei wird gerollt, wenn sie eine bestimmte Größe erreicht

Die Konfiguration verwendet die DefaultRolloverStrategy:

Sie können sehen, wie flexibel dieser Konfigurationsstil ist und wie Sie die genaue Semantik Ihrer Protokollierungsstrategie bis ins letzte Detail optimieren können.

Der JDBCAppender

Wie der Name schon sagt, verwendet dieser Appender JDBC, um Protokolle in eine relationale Datenbank zu schreiben.

Für diese Konfiguration müssen Sie eine ConnectionSource definieren, die entweder eine JNDI-Datenquelle oder eine benutzerdefinierte ConnectionFactory sein kann. Der Logger verwendet die ConnectionSource, um JDBC-Verbindungen abzurufen, weshalb es wichtig ist, einen Verbindungspool für eine bessere Leistung zu verwenden.

Um den Appender in der XML-Konfigurationsdatei zu konfigurieren, können Sie das JDBC-Tag verwenden:

Wie Sie sehen können, wird die JNDI-Datenquelle einfach mit dem Attribut jndiName des DataSource-Tags angegeben. Zusammen mit der ConnectionSource können Sie die Tabelle und die Spalten definieren, die zum Speichern der Protokolldaten verwendet werden sollen.

Der FailoverAppender

Schauen wir uns zum Schluss den FailoverAppender an; dieser definiert einen primären Appender und eine Liste von Backups, die die Protokollierung übernehmen, falls der primäre Appender ausfällt.

Sie können beispielsweise einen primären JDBCAppender mit einem sekundären RollingFile- und Konsolen-Appender konfigurieren, falls keine Datenbankverbindung hergestellt werden kann:

In einer Produktionsumgebung ist eine Failover-Strategie für Ihren Protokollierungsmechanismus immer eine gute Idee.

Layouts konfigurieren

Während die Appender für das Senden von Protokollnachrichten an ein Ziel verantwortlich sind, definieren die Appender anhand der Layouts, wie eine Protokollnachricht formatiert wird.

Hier ist eine kurze Beschreibung einiger der am häufigsten verwendeten Layouts, die log4j2 bietet:

  • PatternLayout – konfiguriert Nachrichten nach einem Zeichenfolgenmuster
  • JsonLayout – definiert ein JSON–Format für Protokollnachrichten
  • CsvLayout – kann verwendet werden, um Nachrichten im CSV-Format zu erstellen

Das PatternLayout

Die erste Art von Layout, die wir uns ansehen werden, ist das PatternLayout. Dies ist eine ziemlich flexible Lösung, die Ihnen viel Kontrolle über die endgültige Ausgabe der Protokollnachricht gibt.

Der Mechanismus wird hauptsächlich durch ein Konvertierungsmuster gesteuert, das Konvertierungsspezifizierer enthält. Jeder Bezeichner beginnt mit dem % -Zeichen, gefolgt von Modifikatoren, die beispielsweise die Breite und Farbe der Nachricht steuern, und einem Konvertierungszeichen, das den Inhalt darstellt, z. B. Datum oder Thread-Name.

Schauen wir uns ein Beispiel für die Konfiguration eines Patternlayouts an, das Protokollzeilen so konfiguriert, dass Datum, Thread, Protokollebene und Protokollnachricht mit unterschiedlichen Farben für verschiedene Protokollebenen angezeigt werden:

Diese Bezeichner sind es wert, im Detail verstanden zu werden, also schauen wir uns das genauer an:

  • %d{HH:mm:ss .SSS} – gibt das Datum des Protokollereignisses im angegebenen Format aus
  • %t – gibt den Thread–Namen aus
  • %level – zeigt die Protokollebene der Nachricht an
  • %highlight{%level} – wird verwendet, um die Farben für das Muster zwischen geschweiften Klammern zu definieren
  • %msg%n – gibt die Protokollnachricht aus

Die Ausgabe zeigt die Protokollebenen in verschiedenen Farben an:

Sie können mehr über den vollständigen Satz lesen von Optionen zum Definieren von Mustern in der log4j2-Dokumentation zu PatternLayout.

Das JsonLayout

Das Protokollieren von Daten im JSON-Format hat einige wesentliche Vorteile, z. B. die Analyse und Verarbeitung der Protokolle durch Protokollierungstools.

Um das JSONLayout in log4j2 zu konfigurieren, können Sie einfach das entsprechende Tag definieren:

<JSONLayout complete="true" compact="false"/>

Wenn Sie complete=true setzen, wird ein wohlgeformtes JSON-Dokument erstellt:

Um JSON produzieren zu können, müssen Sie auch die Jackson-databind-Bibliothek zum Klassenpfad hinzufügen:

Filter konfigurieren

Filter in log4j2 werden verwendet, um zu bestimmen, ob eine Protokollnachricht verarbeitet oder übersprungen werden soll.

Ein Filter kann für die gesamte Konfiguration oder auf Logger- oder Appender-Ebene konfiguriert werden.

Die Bibliothek bietet verschiedene Arten von Filtern, die verwendet werden können:

  • BurstFilter – steuert die Anzahl der zulässigen Protokollereignisse
  • DynamicThresholdFilter – filtert Protokollzeilen basierend auf bestimmten Attributen
  • RegexFilter – filtert Nachrichten basierend darauf, ob sie mit einem regulären Ausdruck übereinstimmen

Sie können beispielsweise die Rate steuern, mit der die Anwendung Daten protokollieren darf.

Dazu können Sie einen BurstFilter einrichten und diesen auf Infonachrichten anwenden:

<Filters> <BurstFilter level="INFO" rate="10" maxBurst="100"/></Filters>

Dadurch wird selektiv der Datenverkehr von Nachrichten auf Infoebene und darunter ignoriert, während sichergestellt wird, dass Sie keine der wichtigeren Nachrichten über den INFORMATIONEN verlieren.

In diesem Fall definiert rate die durchschnittlichen Protokollnachrichten, die pro Sekunde verarbeitet werden sollen, und maxBurst steuert die Gesamtgröße des Datenverkehrs-Bursts, bevor der Filter mit der Eliminierung von Protokolleinträgen beginnt.

Ebenso können wir den Appender so konfigurieren, dass er nur Protokollnachrichten akzeptiert, die einem bestimmten regulären Ausdruck entsprechen:

<Appenders> <JDBC name="JDBCAppender"> <RegexFilter regex="*jdbc*" onMatch="ACCEPT" onMismatch="DENY"/> </JDBC></Appenders>

Insgesamt kann dieser Filtermechanismus mit großer Präzision verwendet werden, um sicherzustellen, dass jeder Appender in Ihrer gesamten Protokollierungskonfiguration die richtigen Informationen verfolgt. Die Möglichkeit, nur sehr spezifische und relevante Informationen zu protokollieren, führt in der Regel zu einer sehr schnellen Ursachenanalyse, insbesondere in komplexen Systemen – insbesondere in Verbindung mit einem leistungsstarken Protokollanzeigewerkzeug.

Logger konfigurieren

Neben dem Root-Logger können wir auch weitere Logger-Elemente mit unterschiedlichen Log-Levels, Appendern oder Filtern definieren. Jeder Logger benötigt einen Namen, der später verwendet werden kann, um darauf zu verweisen:

<Loggers> <Logger name="RollingFileLogger"> <AppenderRef ref="RollingFileAppender" /> </Logger></Loggers>

Um Protokollnachrichten mit diesem speziellen Logger zu schreiben, können Sie einen Verweis darauf mithilfe der LogManager-Klasse erhalten:

Logger rfLogger = LogManager.getLogger("RollingFileLogger");rfLogger.info("User info updated");

Eine weitere sehr verbreitete Methode zur Strukturierung der Hierarchie dieser Logger basiert auf der Java-Klasse:

Logger logger = LogManager.getLogger(MyServiceTest.class);

Lookups verwenden

Lookups stellen eine Möglichkeit dar, externe Werte in die log4j2-Konfiguration einzufügen. Wir haben bereits ein Beispiel für die Datumssuche in der RollingFileAppender-Konfiguration gesehen:

<RollingFile name="RollingFileAppender" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

Die ${date:yyy-MM} -Suche fügt das aktuelle Datum in den Dateinamen ein, während das vorhergehende $ ein Escape-Zeichen ist, um den Suchausdruck in das filePattern-Attribut einzufügen.

Sie können auch Systemeigenschaftswerte in die log4j2-Konfiguration einfügen, indem Sie das Format ${sys:property_name} verwenden:

<File name="ApplicationLog" fileName="${sys:path}/app.log"/>

Eine andere Art von Informationen, die Sie nachschlagen und einfügen können, sind Java-Umgebungsinformationen:

<PatternLayout header="${java:version} - ${java:os}"> <Pattern>%d %m%n</Pattern></PatternLayout>

Weitere Details zu der Art von Daten, die Sie durch Nachschlagen einfügen können, finden Sie in der log4j2-Konfiguration dokumentation.

Programmgesteuerte Konfiguration

Neben Konfigurationsdateien kann log4j2 auch programmgesteuert konfiguriert werden. Es gibt verschiedene Möglichkeiten, dies zu tun:

  • Erstellen Sie eine benutzerdefinierte ConfigurationFactory
  • Verwenden Sie die Configurator-Klasse
  • Ändern Sie die Konfiguration nach der Initialisierung
  • Kombinieren Sie Eigenschaftendateien und programmgesteuerte Konfiguration

Werfen wir einen Blick darauf, wie Sie ein Layout und einen Appender programmgesteuert konfigurieren:

Als nächstes können Sie einen Logger mit der LoggerConfig-Klasse definieren, den Appender die Konfiguration:

Anschließend können Sie den Logger wie gewohnt verwenden:

Logger pLogger = LogManager.getLogger("programmaticLogger");pLogger.info("Programmatic Logger Message");

Diese Art der fließenden API kann zu einer schnelleren Entwicklung und Iteration komplexerer Protokollierungskonfigurationen führen, da Sie jetzt von den Vorteilen der direkten Arbeit mit Java-Code profitieren.

Da XML jedoch immer noch lesbarer und kompakter sein kann, können Sie die Konfiguration häufig programmgesteuert entwickeln und dann nach Abschluss des Vorgangs in XML konvertieren.

Benutzerdefinierte Protokollebenen

Die integrierten Protokollebenen für log4j2 sind:

  • OFF
  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE
  • ALL

Darüber hinaus können Sie auch eine benutzerdefinierte Protokollebene entsprechend Ihren Anwendungsanforderungen definieren.

Um beispielsweise diese neue Protokollebene zu definieren, können Sie die Ebene verwenden.forName() API – Angabe des neuen Ebenennamens und einer Ganzzahl, die den Platz der Ebene in der Protokollebenen-Hierarchie darstellt:

Level myLevel = Level.forName("NEW_LEVEL", 350);

Um zu bestimmen, welcher Integer-Wert verwendet werden soll, können Sie sich die Werte ansehen, die für die anderen Protokollebenen in der log4j2-Dokumentation definiert sind:

Der Wert 350 setzt den Pegel zwischen WARN und INFO, was bedeutet, dass die Meldungen angezeigt werden, wenn der Pegel auf INFO oder höher eingestellt ist.

Um eine Nachricht auf benutzerdefinierter Ebene zu protokollieren, müssen Sie die log() -Methode verwenden:

logger.log(myLevel, "Custom Level Message");

Die entsprechende XML-Konfiguration könnte lauten:

<CustomLevels> <CustomLevel name="NEW_XML_LEVEL" intLevel="350" /></CustomLevels>

Dann kann es über die Standardprotokoll-API verwendet werden:

logger.log(Level.getLevel("NEW_XML_LEVEL"),"Custom XML Level Message");

Die neuen benutzerdefinierten Ebenen werden auf die gleiche Weise wie die Standardebenen angezeigt:

11:28:23.558 NEW_LEVEL - Custom Level Message11:28:23.559 NEW_XML_LEVEL - Custom XML Level Message

Migration von Log4j 1.x

Wenn Sie eine Anwendung mit der 1 migrieren.x-Version der Bibliothek auf die aktuelle 2.x-Version gibt es ein paar Routen, denen Sie folgen können:

  • Verwenden Sie das log4j 1.x bridge
  • manuelles Aktualisieren der API und der Konfiguration

Die Verwendung der Bridge ist trivial. Sie müssen nur die log4j-Abhängigkeit durch die log4j-1.2-api-Bibliothek ersetzen:

Dies ist zwar die schnellere Methode, hat jedoch den Nachteil, dass die Art der Konfiguration, die konvertiert werden kann, begrenzt ist.

Die manuelle Methode ist natürlich mehr Arbeit, wird aber letztendlich zu einer flexibleren und leistungsfähigeren Protokollierungslösung führen.

Hier sind einige der häufigsten Arten von Änderungen, die Sie vornehmen müssen:

Fazit

Protokolldateien sind in jeder Produktionsumgebung von entscheidender Bedeutung, und die Wahl einer guten Protokollierungslösung kann den Unterschied zwischen 5 Minuten und einem ganzen Tag ausmachen, um ein Problem in der Produktion zu verstehen.

Log4j2 ist eine leistungsstarke und robuste Protokollierungslösung für moderne Java-Anwendungen mit einer Vielzahl von Konfigurationsoptionen.

Es ermöglicht die einfache Konfiguration erweiterter Best Practices für die Protokollierung, z. B. fortlaufende Dateien, verschiedene Arten von Protokollierungsausgabezielen, Unterstützung für strukturierte Protokollierungsformate wie JSON oder XML, Verwendung mehrerer Logger und Filter sowie benutzerdefinierte Protokollebenen.

Wenn Sie über die manuelle Analyse von Protokolldaten hinausgehen müssen, sollten Sie sich unbedingt die Protokollierungsfunktionen von Retrace APM ansehen.