CodeGym /Java-Blog /Random-DE /Protokollierung: Was, wie, wo und womit?
John Squirrels
Level 41
San Francisco

Protokollierung: Was, wie, wo und womit?

Veröffentlicht in der Gruppe Random-DE
Hallo an alle in der CodeGym-Community! Protokollierung: Was, wie, wo und womit?  - 1 Lassen Sie uns heute über die Protokollierung sprechen:
  1. Was es ist, warum es existiert, wann Sie es verwenden und wann Sie es vermeiden sollten.
  2. Welche Protokollierungsimplementierungen in Java verfügbar sind und was Sie mit all diesen Protokollierungsoptionen tun sollten.
  3. Und Protokollebenen. Wir besprechen, was ein Appender ist und wie man ihn richtig konfiguriert.
  4. Protokollierungsknoten und wie man sie richtig konfiguriert, damit alles so funktioniert, wie wir es wollen.
Dieses Material richtet sich an ein breites Publikum. Es wird jedem klar sein, der Java gerade erst kennenlernt, aber auch denen, die bereits arbeiten, sich aber erst mit der Sprache beschäftigt haben. logger.info("log something"); Los geht’s!

Warum benötigen Sie eine Protokollierung?

Schauen wir uns einige reale Fälle an, in denen die Protokollierung ein Problem lösen kann. Hier ist ein Beispiel aus meiner Arbeit. Es gibt Punkte, an denen eine Anwendung in andere Dienste integriert wird. An diesen Stellen nutze ich die Protokollierung, um eine Art „Alibi“ zu schaffen : Wenn die Integration nicht funktioniert, lässt sich leicht herausfinden, auf welcher Seite das Problem liegt. Es ist auch wünschenswert, wichtige Informationen in einer Datenbank zu protokollieren. Beispielsweise die Erstellung eines Admin-Benutzers. Genau so etwas wäre gut zu protokollieren.

Tools zum Anmelden in Java

Unter den bekannten Protokollierungslösungen in Java können wir Folgendes hervorheben:
  • Log4j
  • JUL – java.util.logging
  • JCL – Jakarta Commons Logging
  • Wieder anmelden
  • SLF4J – Einfache Protokollierungsfassade für Java
Wir werden einen Überblick über jeden von ihnen geben. Dann nehmen wir eine slf4j - log4j- Bindung als Grundlage für eine praktische Diskussion. Das mag jetzt seltsam erscheinen, aber keine Sorge: Am Ende des Artikels wird alles klar sein.

System.err.println

Am Anfang gab es System.err.println (Anzeige von Protokolleinträgen auf der Konsole). Auch heute noch wird diese Technik verwendet, um beim Debuggen schnell ein Protokoll zu erstellen. Natürlich müssen hier keine Einstellungen besprochen werden, also merken Sie sich einfach diese Methode und wir machen weiter.

Log4j

Dabei handelt es sich um eine Komplettlösung, die Entwickler aus der Not heraus entwickelt haben. Das Ergebnis ist ein wirklich interessantes Tool, das Sie verwenden können. Aufgrund verschiedener Umstände landete diese Lösung nicht im JDK, was die gesamte Community sehr verärgerte. Log4j verfügt über Konfigurationsoptionen, mit denen Sie die Protokollierung im com.example.typePaket aktivieren und im Unterpaket deaktivieren können com.example.type.generic. Dadurch ist es möglich, Code, der nicht protokolliert werden muss, schnell auszuschließen. Hierbei ist zu beachten, dass es zwei Versionen von Log4j gibt: 1.2.x und 2.xx, die nicht miteinander kompatibel sind . Log4j hat die Konzepte des Appenders hinzugefügt(ein Tool zum Schreiben von Protokollen) und Layout (Protokollformatierung). Auf diese Weise können Sie nur das protokollieren, was Sie benötigen, und es genau so protokollieren, wie Sie es benötigen. Wir werden etwas später mehr über Appender sprechen.

JUL – java.util.logging

Einer der Hauptvorteile dieser Lösung besteht darin, dass JUL im JDK (Java Development Kit) enthalten ist. Leider basierten seine Entwickler bei seiner Entwicklung nicht auf dem beliebten Dienstprogramm Log4j, sondern auf einer Lösung von IBM. Diese Entscheidung hatte Konsequenzen. Die Realität ist, dass derzeit niemand JUL verwendet. Die Protokollebenen in JUL unterscheiden sich von denen von Logback, Log4j und Slf4j. Dadurch fällt es ihnen schwerer, einander zu verstehen. Das Erstellen eines Loggers ist mehr oder weniger ähnlich. Dazu müssen Sie einen Import durchführen:

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Der Klassenname wird übergeben, sodass wir wissen, woher unsere Protokollierung kommt. Ab Java 8 können Sie übergeben Supplier<String>. Dies hilft uns, eine Zeile nur dann zu lesen und zu erstellen, wenn wir sie wirklich brauchen, und nicht jedes Mal, wie es früher der Fall war. Erst mit der Veröffentlichung von Java 8 haben Entwickler endlich wichtige Probleme gelöst und JUL wirklich nutzbar gemacht. Nämlich Methoden mit einem Supplier<String> msgSupplierParameter, wie unten gezeigt:

public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL – Jakarta Commons Logging

Da es lange Zeit keinen Industriestandard für die Protokollierung gab und viele Leute ihre eigenen benutzerdefinierten Logger erstellten, wurde die Entscheidung getroffen, JCL zu veröffentlichen, einen allgemeinen Wrapper, der zusätzlich zu anderen verwendet werden konnte. Warum? Manchmal verwendeten Abhängigkeiten, die dem Projekt hinzugefügt wurden, einen anderen Logger als den im Projekt. Aus diesem Grund wurden sie dem Projekt als transitive Abhängigkeiten hinzugefügt, was beim Versuch, alles zusammenzusetzen, zu echten Problemen führte. Leider war die Hülle nicht sehr funktionell und hat nichts hinzugefügt. Es wäre wahrscheinlich praktisch, wenn jeder JCL verwenden würde. Aber das ist nicht passiert, daher ist die Verwendung von JCL im Moment nicht die beste Idee.

Wieder anmelden

Der Open-Source-Weg ist dornig ... Derselbe Entwickler, der Log4j geschrieben hat, hat auch Logback als Nachfolge-Logging-Framework geschrieben. Es basierte auf der gleichen Idee wie Log4j. Die Unterschiede bei Logback sind:
  • verbesserte Leistung
  • native Unterstützung für Slf4j hinzugefügt
  • erweiterte Filtermöglichkeiten
Standardmäßig erfordert Logback keine Konfiguration und zeichnet alle Ereignisse auf DEBUG-Ebene und höher auf. Wenn Sie Anpassungen benötigen, können Sie diese über eine XML-Konfiguration erreichen:

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

SLF4J – Einfache Protokollierungsfassade für Java

Irgendwann im Jahr 2006 verließ einer der Gründerväter von Log4j das Projekt und erstellte Slf4j (Simple Logging Facade for Java), einen Wrapper für Log4j, JUL, Common-Logging und Logback. Wie Sie sehen, sind wir so weit fortgeschritten, dass wir einen Wrapper über einen Wrapper erstellen ... In diesem Fall ist er in zwei Teile unterteilt: Eine API, die in der Anwendung verwendet wird, und eine Implementierung, die separat hinzugefügt wird Abhängigkeiten für jede Art der Protokollierung. Zum Beispiel slf4j-log4j12.jarund slf4j-jdk14.jar. Sie müssen die richtige Implementierung anschließen und das war's: Ihr gesamtes Projekt wird sie verwenden. Slf4j unterstützt alle neuesten Funktionen, wie z. B. Formatierungszeichenfolgen für die Protokollierung. Zuvor gab es ein solches Problem. Nehmen wir an, wir erstellen einen Protokolleintrag wie diesen:

log.debug("User " + user + " connected from " + request.getRemoteAddr());
Aufgrund des Verkettungsoperators userwird das Objekt dank user.toString(). Dies kostet Zeit und verlangsamt das System. Und das kann in Ordnung sein, wenn wir die Anwendung debuggen. Es treten Probleme auf, wenn die Protokollebene für diese Klasse INFO oder höher ist. Mit anderen Worten: Wir sollten diesen Protokolleintrag nicht schreiben (für INFO oder höher) und wir sollten keine Zeichenfolgenverkettung verwenden. Theoretisch sollte die Protokollierungsbibliothek selbst dieses Problem lösen. Dies stellte sich tatsächlich als das größte Problem in der ersten Version von Log4j heraus. Es lieferte keine anständige Lösung, sondern schlug stattdessen vor, etwa Folgendes zu tun:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Das heißt, statt einer Zeile Code für die Protokollierung schlugen sie vor, drei zu schreiben! Durch die Protokollierung sollten Codeänderungen minimiert werden, und die drei Zeilen verstoßen eindeutig gegen diesen allgemeinen Ansatz. Slf4j hatte keine Kompatibilitätsprobleme mit dem JDK und der API, sodass sofort eine schöne Lösung entstand:

log.debug("User {} connected from {}", user, request.getRemoteAddr());
Dabei {}sind Platzhalter für die an die Methode übergebenen Argumente angegeben. Das heißt, das erste {}entspricht userund das zweite {}entspricht request.getRemoteAddr(). Auf diese Weise führen wir die Zeichenfolgenverkettung nur dann durch, wenn die Protokollebene erfordert, dass wir den Protokolleintrag schreiben. Danach begann Sjf4j immer beliebter zu werden. Derzeit ist es die beste Lösung. Werfen wir daher einen Blick auf die Protokollierung mithilfe einer slf4j-log4j12Bindung.

Was muss protokolliert werden?

Natürlich sollte man nicht alles protokollieren. Dies ist oft nicht notwendig und manchmal sogar gefährlich. Wenn Sie beispielsweise die persönlichen Daten einer Person protokollieren und diese irgendwie durchsickern, wird es echte Probleme geben, insbesondere bei Projekten, die sich auf westliche Märkte konzentrieren. Es gibt aber auch Dinge, die Sie unbedingt protokollieren sollten :
  1. Beginn/Ende der Bewerbung. Wir müssen wissen, ob die Anwendung wirklich wie erwartet gestartet und beendet wurde.
  2. Sicherheitsprobleme. Hier wäre es sinnvoll, Versuche zu protokollieren, das Passwort einer Person zu erraten, Fälle, in denen sich Administratoren anmelden usw.
  3. Bestimmte Anwendungszustände . Beispielsweise der Übergang von einem Zustand in einen anderen in einem Geschäftsprozess.
  4. Bestimmte Debug-Informationen zusammen mit der entsprechenden Protokollebene.
  5. Bestimmte SQL-Skripte. Es gibt reale Fälle, in denen dies notwendig ist. Aber auch hier können Sie durch geschickte Anpassung der Protokollebenen hervorragende Ergebnisse erzielen.
  6. Laufende Threads können protokolliert werden, um sicherzustellen, dass alles ordnungsgemäß funktioniert.

Beliebte Fehler bei der Protokollierung

Hier gibt es viele Nuancen, aber wir möchten einige häufige Fehler besonders erwähnen:
  1. Übermäßige Protokollierung. Sie sollten nicht jeden Schritt protokollieren, der theoretisch wichtig sein könnte. Hier eine gute Faustregel: Protokolle sollten 10 % der Last nicht überschreiten. Andernfalls kommt es zu Leistungsproblemen.
  2. Protokollierung aller Daten in einer Datei. Dies wird es irgendwann sehr schwierig machen, das Protokoll zu lesen/schreiben, ganz zu schweigen von der Tatsache, dass bestimmte Systeme Beschränkungen hinsichtlich der Dateigröße haben.
  3. Verwendung falscher Protokollebenen. Jede Protokollebene hat klare Grenzen und diese sollten respektiert werden. Wenn eine Grenze unklar ist, können Sie sich darauf einigen, welche Ebene verwendet werden soll.

Protokollebenen

x: Sichtbar
TÖDLICH FEHLER WARNEN DIE INFO DEBUGGEN VERFOLGEN ALLE
AUS
TÖDLICH X
FEHLER X X
WARNEN X X X
DIE INFO X X X X
DEBUGGEN X X X X X
VERFOLGEN X X X X X X
ALLE X X X X X X X
Was sind Protokollebenen? Um irgendwie eine Hierarchie von Protokolleinträgen zu erstellen, sind bestimmte Konventionen und Abgrenzungen notwendig. Aus diesem Grund wurden Protokollebenen eingeführt. Die Stufe wird in der Anwendung eingestellt. Wenn ein Eintrag unter einem bestimmten Wert liegt, wird er nicht protokolliert. Beispielsweise verfügen wir über Protokolle, die wir beim Debuggen der Anwendung verwenden. Im Normalbetrieb (wenn die Anwendung bestimmungsgemäß verwendet wird) sind solche Protokolle nicht erforderlich. Daher ist die Protokollebene höher als beim Debuggen. Schauen wir uns die Protokollebenen mit Log4j an. Abgesehen von JUL verwenden andere Lösungen dieselben Protokollebenen. Hier sind sie in absteigender Reihenfolge:
  • AUS: Es werden keine Protokolleinträge aufgezeichnet. alles wird ignoriert.
  • FATAL: Ein Fehler, der die weitere Ausführung der Anwendung verhindert. Beispiel: „JVM-Fehler wegen nicht genügend Arbeitsspeicher“.
  • FEHLER: Fehler auf dieser Ebene weisen auf Probleme hin, die behoben werden müssen. Der Fehler stoppt nicht die gesamte Anwendung. Andere Anfragen funktionieren möglicherweise ordnungsgemäß.
  • WARN: Protokolleinträge, die eine Warnung darstellen. Es ist etwas Unerwartetes passiert, aber das System konnte die Anfrage bewältigen und erfüllen
  • INFO: Protokolleinträge, die auf wichtige Aktionen in der Anwendung hinweisen. Dabei handelt es sich nicht um Fehler oder Warnungen. Es handelt sich um erwartete Systemereignisse.
  • DEBUG: Protokolleinträge müssen zum Debuggen der Anwendung verwendet werden. Um sicherzustellen, dass die Anwendung genau das tut, was erwartet wird, oder um die von der Anwendung durchgeführten Aktionen zu beschreiben, z. B. „Eingegebene Methode1“.
  • TRACE: Protokolleinträge mit niedrigerer Priorität zum Debuggen. Die niedrigste Protokollebene.
  • ALL: Eine Protokollebene zum Schreiben aller Protokolleinträge der Anwendung.
Wenn die INFO-Protokollebene irgendwo in der Anwendung aktiviert ist, werden die Einträge für jede Ebene protokolliert, von INFO bis FATAL. Wenn die Protokollebene FATAL eingestellt ist, werden nur Protokolleinträge mit dieser Ebene geschrieben.

Protokolle protokollieren und senden: Appender

Betrachten wir, wie das alles funktioniert, wenn wir Log4j verwenden, das zahlreiche Möglichkeiten zum Schreiben/Versenden von Protokollen bietet:
  • in eine Datei schreiben –DailyRollingFileAppender
  • Informationen auf die Konsole schreiben –ConsoleAppender
  • Protokolle in eine Datenbank schreiben –JDBCAppender
  • um das Senden von Protokollen über TCP/IP zu verwalten –TelnetAppender
  • um sicherzustellen, dass sich die Protokollierung nicht negativ auf die Leistung auswirkt –AsyncAppender
Es gibt noch einige weitere Implementierungen: Eine vollständige Liste finden Sie hier . Übrigens, wenn der von Ihnen benötigte Appender nicht existiert, ist das kein Problem. Sie können Ihren eigenen Appender schreiben, indem Sie die Appender- Schnittstelle implementieren, die Log4j unterstützt.

Protokollierungsknoten

Zu Demonstrationszwecken verwenden wir eine Slf4j-Schnittstelle mit einer Implementierung von Log4j. Das Erstellen eines Loggers ist sehr einfach: In einer Klasse namens MainDemo, die einige Protokollierungen durchführt, müssen wir Folgendes hinzufügen:

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Dadurch wird ein Logger für uns erstellt. Um einen Protokolleintrag zu erstellen, stehen mehrere Methoden zur Verfügung, deren Namen angeben, welche Protokollebene verwendet wird. Zum Beispiel:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
Obwohl wir die Klasse übergeben, ist der endgültige Name der vollständige Name der Klasse, einschließlich der Pakete. Dies geschieht, damit Sie später die Protokollierung in Knoten aufteilen und die Protokollierungsstufe und den Appender für jeden Knoten konfigurieren können. Beispielsweise wurde der Logger in der com.github.romankh3.logginglecture.MainDemoKlasse erstellt. Der Name bildet die Grundlage für die Erstellung einer Hierarchie von Protokollierungsknoten. Der Hauptknoten ist der RootLogger der obersten Ebene . Dies ist der Knoten, der alle Protokolleinträge für die gesamte Anwendung empfängt. Die verbleibenden Knoten können wie folgt dargestellt werden: Protokollierung: Was, wie, wo und womit?  - 3Appender werden für bestimmte Protokollierungsknoten konfiguriert. Jetzt schauen wir uns die Datei log4j.properties an , um ein Beispiel für deren Konfiguration zu sehen.

Eine Schritt-für-Schritt-Anleitung zur Datei log4j.properties

Wir richten Schritt für Schritt alles ein und schauen, was möglich ist:

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Diese Zeile besagt, dass wir den CONSOLE-Appender registrieren, der die Implementierung org.apache.log4j.ConsoleAppender verwendet. Dieser Appender schreibt Informationen in die Konsole. Als nächstes registrieren wir einen weiteren Appender. Dieser schreibt in eine Datei:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Es ist wichtig zu beachten, dass die Appender selbst noch konfiguriert werden müssen. Sobald wir unsere Appender registriert haben, können wir bestimmen, welche Protokollebenen und welche Appender an den Knoten verwendet werden.

log4j.rootLogger=DEBUG, KONSOLE, DATEI

  • log4j.rootLogger bedeutet, dass wir den Root-Knoten konfigurieren, der alle Protokolleinträge enthält
  • Das erste Wort nach dem Gleichheitszeichen gibt die minimale zu schreibende Protokollebene an (in unserem Fall ist es DEBUG).
  • Nach dem Komma geben wir alle zu verwendenden Appender an.
Um einen spezifischeren Protokollierungsknoten zu konfigurieren, würden Sie einen Eintrag wie diesen verwenden:

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
where log4j.logger.wird verwendet, um auf einen bestimmten Knoten zu verweisen. In unserem Fall com.github.romankh3.logginglecture. sprechen wir nun über die Konfiguration des CONSOLE-Appenders:

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Hier sehen wir, dass es möglich ist, die spezifische Ebene festzulegen, ab der der Appender mit der Arbeit beginnt. Hier ist ein Beispiel dafür, was tatsächlich passiert: Angenommen, eine Nachricht mit der INFO-Ebene wird vom Protokollierungsknoten empfangen und an den ihr zugewiesenen Appender weitergeleitet. Wenn der Schwellenwert des Appenders auf WARN gesetzt ist, empfängt er den Protokolleintrag, unternimmt aber nichts damit. Als nächstes müssen wir entscheiden, welches Layout die Nachricht verwenden soll. Im Beispiel verwende ich PatternLayout, es gibt aber noch viele andere Optionen. Wir werden sie in diesem Artikel nicht behandeln. Beispiel für die Konfiguration des FILE-Appenders:

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Sie können die spezifische Datei konfigurieren, in die Protokolleinträge geschrieben werden, wie aus dieser Zeile ersichtlich ist:

log4j.appender.FILE.File=./target/logging/logging.log
Der Eintrag wird in die logging.logDatei geschrieben. Um Probleme mit der Dateigröße zu vermeiden, können Sie das Maximum konfigurieren, das in diesem Fall 1 MB beträgt. MaxBackupIndexgibt an, wie viele solcher Protokolldateien es geben wird. Wenn wir mehr Dateien erstellen müssen, wird die erste Datei gelöscht. Um ein reales Beispiel für die Konfiguration der Protokollierung anzusehen, können Sie zum öffentlichen Repository auf GitHub gehen.

Bekräftigen Sie, was wir besprochen haben

Versuchen Sie selbst, alles zu tun, was wir beschrieben haben:
  • Erstellen Sie Ihr eigenes Projekt ähnlich unserem Beispiel oben.
  • Wenn Sie wissen, wie man Maven verwendet, verwenden Sie es. Wenn nicht, lesen Sie dieses Tutorial, in dem beschrieben wird, wie Sie die Bibliothek anschließen.

Zusammenfassend

  1. Wir haben über die in Java vorhandenen Protokollierungslösungen gesprochen.
  2. Fast alle bekannten Protokollierungsbibliotheken wurden von einer Person geschrieben :D
  3. Wir haben gelernt, was protokolliert werden sollte und was nicht.
  4. Wir haben die Protokollebenen ermittelt.
  5. Wir wurden mit Protokollierungsknoten vertraut gemacht.
  6. Wir haben uns angesehen, was ein Appender ist und wozu er dient.
  7. Wir haben Schritt für Schritt eine log4j.proterties-Datei erstellt.

Zusätzliche Materialien

  1. CodeGym: Logger-Lektion
  2. Weekly Geekly: Java-Protokollierung. Hallo Welt
  3. Coding Horror: Das Problem mit der Protokollierung
  4. YouTube: Die Hölle der Java-Protokollierung verstehen – Die Grundlagen. Java-Logging-Hölle und wie man sich da raushält
  5. Log4j: Appender
  6. Log4j: Layout
Siehe auch meinen anderen Artikel:
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION