Log4j
| |
---|---|
Basisdaten
| |
Hauptentwickler | Scott Deboy, Ralph Goers, Gary Gregory, Christian Grobmeier |
Entwickler | Apache Software Foundation |
Aktuelle Version | 2.24.1[1] (29. September 2024) |
Betriebssystem | plattformübergreifend |
Programmiersprache | Java |
Lizenz | Apache-Lizenz 2.0 |
logging.apache.org |
Log4j ist ein Framework für das Logging von Anwendungsmeldungen in Java. Innerhalb vieler Open-Source- und kommerzieller Softwareprodukte hat es sich über die Jahre zu einem De-facto-Standard entwickelt. Log4j gilt als Vorreiter für andere Logging-Frameworks, auch in anderen Programmiersprachen.
Das Projekt wurde von Ceki Gülcü 1996 während seiner Arbeit am IBM-Entwicklungslabor in Zürich gegründet. Heute ist es ein Teil des Logging-Projekts der Apache Software Foundation und steht unter der Apache-Lizenz 2.0. Es entstand zu einer Zeit, als es in den Java-Standardbibliotheken noch keine Logging-Mechanismen gab. Heutzutage ist es durch seine Ausgereiftheit und Konfigurierbarkeit für viele Softwareentwickler das Log-System der ersten Wahl.
Die Ausstrahlung der Log4j-Konzepte auf andere Programmiersprachen bzw. Plattformen ist so groß, dass es mittlerweile etliche Adaptionen gibt. Einige werden vom Apache Logging Projekt selbst gepflegt. Zum Beispiel:
Viele Varianten werden jedoch außerhalb von Apache Logging entwickelt:
Seit Juli 2014 ist Log4j 2 als Nachfolger des Log4j 1.x verfügbar.
Das Apache-Logging-Projekt versucht, Log4j-ähnliche Systeme für diverse Programmiersprachen zusammenzuführen. Bisher sind das log4j, log4cxx, log4net, log4php[5] und Chainsaw (ein Logdatei-Betrachter und -Analysewerkzeug).[6]
Außerdem werden sogenannte Companions entwickelt, die zusätzliche Funktionalität für Apache Log4j bereitstellen.
Anstatt auftretende Fehler und Infomeldungen auf der Standardausgabe auszugeben, dient Log4j dazu, die Meldungen über sogenannte Logger an das gewählte Ausgabeziel weiterzuleiten („Appender“).[7] Neben der Auswahl des Ausgabeziels (z. B. eine Logdatei) wird gleichzeitig aufgrund der Wichtigkeit („Log-Level“) der Meldung entschieden, ob diese überhaupt weitergeleitet wird. Der Programmierer muss sich beim Erstellen des Programms nur um die Wichtigkeit der Meldungen Gedanken machen. Für eine Meldung können mehrere Appender mit unterschiedlicher Wichtigkeit angeschlossen werden, so dass ein Appender hier die Rolle eines Kanals spielt. Die Filterung und Art der Ausgabe kann zur Laufzeit konfiguriert werden.
Log4j ist auf möglichst hohe Geschwindigkeit ausgelegt, damit das Protokollieren die Systemleistung nicht negativ beeinflusst. So dauert die Entscheidung, ob eine Meldung ausgegeben werden muss, auch auf einem veralteten System (AMD Duron mit 800 MHz, JDK 1.3.1) nur 5 Nanosekunden, die Ausgabe selbst – je nachdem, welches Layout verwendet wird – zwischen 21 und 37 Mikrosekunden.[8]
In der Konfigurationsdatei kann die Ausgabe je nach Wichtigkeit der Nachrichten gefiltert werden. Der Ausgabe-Umfang sinkt mit der zugewiesenen Wichtigkeitsstufe und umfasst alle Nachrichten der Stufe selbst sowie aller noch dringenderen Stufen. Die Reihenfolge stellt sich dabei wie folgt dar: ALL
→ TRACE
→ DEBUG
→ INFO
→ WARN
→ ERROR
→ FATAL
→ OFF
.
Für die Einstufung der Wichtigkeit gelten folgende Richtwerte:
ALL
TRACE
DEBUG
INFO
Foo
aufgebaut, Verarbeitung dauerte soundsoviel Sekunden …)WARN
ERROR
FATAL
OFF
Mittels Appender kann das Ausgabeziel/können die Ausgabeziele der erzeugten Protokollausgaben festgelegt werden.
Nachfolgend die wichtigsten Appender-Arten:
ConsoleAppender
FileAppender
RollingFileAppender
DailyRollingFileAppender
SyslogAppender
JDBCAppender
NTEventLogAppender
SMTPAppender
SocketAppender
LogCatAppender
LogCat
Weitere Appender können jederzeit hinzugefügt werden.
Es gibt drei Arten, Log4j zu konfigurieren: mittels einer Properties- oder einer XML-Datei oder im Programmcode. Es wird empfohlen, eine Properties- oder XML-Datei zu verwenden, damit ist die Konfiguration vom Code getrennt, was es ermöglicht, ohne Modifikation oder Neustart der Applikation die Konfiguration des Loggings anzupassen. Somit kann beispielsweise eine Applikation so lange nur mit der Wichtigkeitsstufe FATAL betrieben werden, bis ein Fehler auftritt. Ab dann wird die Stufe WARN gesetzt, ohne die Applikation anzuhalten.
Die Konfigurationsdateien definieren mittels der folgenden Komponenten das Verhalten von Log4j:
Logger log = Logger.getLogger(org.wikipedia.MyClass)
.Ein weiteres nützliches Merkmal ist der Mapped Diagnostic Context. Dabei wird einer Kontextvariablen ein Wert zugewiesen und in der Konfigurationsdatei kann darauf referenziert werden. Dabei hat jeder Thread seinen eigenen Kontext und kann zusätzliche Informationen wie z. B. die Adresse des Clients bei einer Serveranwendung protokollieren.
Die folgende XML-Konfiguration konfiguriert eine Applikation so, dass FATAL-Fehler von Fremdbibliotheken auf die Konsole protokolliert werden, ERROR-Fehler der eigenen Applikation zusätzlich auch per E-Mail geschickt werden, bei einer spezifischen Komponente darüber hinaus auch noch INFO-Meldungen protokolliert werden und bei einer bestimmten Klasse sogar noch DEBUG-Meldungen.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN"
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration>
<!-- Appender für eine einzeilige Ausgabe an der Konsole -->
<appender name="Konsole" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" />
</layout>
</appender>
<!-- Appender für dieselbe Ausgabe via E-Mail -->
<appender name="mail" class="org.apache.log4j.net.SMTPAppender">
<param name="SMTPHost" value="smtp.myservername.xx" />
<param name="From" value="email@fromemail.xx" />
<param name="To" value="toemail@toemail.xx" />
<param name="Subject" value="[LOG] ..." />
<param name="BufferSize" value="1" />
<param name="threshold" value="error" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" />
</layout>
</appender>
<!-- ERROR-Logger für alle Klassen meiner Applikation -->
<logger name="com.myapp">
<level value="error"/>
<appender-ref ref="Konsole" />
<appender-ref ref="mail" />
</logger>
<!-- INFO-Logger für eine spezifische Komponente -->
<logger name="com.myapp.mycomponent">
<level value="info"/>
</logger>
<!-- DEBUG-Logger für eine spezifische Klasse -->
<logger name="com.myapp.mycomponent.MyClass">
<level value="debug"/>
</logger>
<!-- FATAL-Logger für die gesamte Applikation (inkl. Bibliotheken) -->
<root>
<level value="fatal" />
<!-- protokolliert auf Konsole - wenn nicht in Sub-Loggern anders definiert -->
<appender-ref ref="Konsole" />
</root>
</log4j:configuration>
Version 2 wurde von Grund auf neu geschrieben, auch wenn Teile von Log4j 1.x übernommen wurden. Die neue Version verfügt über eine moderne Schnittstelle, wie sie auch von logback bekannt ist. Außerdem unterstützt sie slf4j native. Zugleich wurden Schwächen von logback analysiert und versucht zu verbessern. Somit verliert Log4j 2 beispielsweise keine Logging-Events, wenn sich das System neu konfiguriert. Außerdem wurde eine Plugin-Architektur bereitgestellt und die Konfiguration mittels JSON ermöglicht.[10]
Das Projekt gab im August 2015 bekannt, dass der 1.x‐Zweig das „End of Life“ erreicht hat und damit die Weiterentwicklung eingestellt wird. Entwickler werden deswegen gebeten, auf den 2.x‐Zweig zu migrieren.[11][12]
Auf der Website von Apache werden einige Unterschiede zwischen Log4j 1 und Log4j 2 aufgelistet.[13]
In Log4j 2 hat sich die Syntax der Konfiguration geändert. Es folgt eine beispielhafte Konfigurationsdatei nach dem neuen Standard:
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration >
<Properties>
<Property name="logfile">C:/logs/logfile</Property>
<Property name="LOG_PATTERN">%d{dd.MM.yyyy - HH:mm:ss} %-5p [%t] - %C - %M - %m%n</Property>
</Properties>
<Appenders>
<!-- Appender für eine einzeilige Ausgabe an der Konsole -->
<Console name="Konsole" target="SYSTEM_OUT">
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
<!-- Appender für alle Protokolle ab Stufe Debug in maximal 20 Dateien, die jeweils maximal 20 MB groß werden dürfen -->
<RollingFile name="DEBUG_LOG"
fileName="${logfile}_Debug.log"
filePattern="${logfile}_Debug-%i.log">
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="${LOG_PATTERN}" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="20000KB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
<!-- Appender für alle Protokolle ab Stufe Error in maximal 20 Dateien, die jeweils maximal 20 MB groß werden dürfen -->
<RollingFile name="ERROR_LOG"
fileName="${logfile}/${project}_Error.log"
filePattern="${logfile}/${project}_Error-%i.log">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="${LOG_PATTERN}" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="20000KB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
</Appenders>
<Loggers>
<logger name="com.myapp" additivity="false">
<AppenderRef ref="DEBUG_LOG" />
<AppenderRef ref="ERROR_LOG" />
<AppenderRef ref="Konsole" />
</logger>
<Root level="all">
<AppenderRef ref="Konsole" />
</Root>
</Loggers>
</Configuration>
Am 10. Dezember 2021 wurde eine Zero-Day-Lücke in Log4j-Version 2 bekannt (CVE-2021-44228,[14] oft als Log4Shell bezeichnet), die Angreifer ausnutzen konnten, um Code auf dem jeweiligen Hostsystem auszuführen (Remote Code Execution) und somit zum Beispiel Rechenleistung von den infizierten Servern zu benutzen, um Krypto-Mining zu betreiben.[15] Die Schwachstelle wurde vom Alibaba-Cloud-Sicherheitsdienst an Apache gemeldet. Aufgrund der weiten Verbreitung von Log4j und der einfach auszunutzenden Schwachstelle bezeichneten Fachleute die Meldung als „Größte Schwachstelle in der Geschichte des modernen Computing“.[16][17]
Zahlreiche Softwareentwickler, Dienstanbieter, Unternehmen und Behörden waren potentiell betroffen, unter anderem Amazon Web Services, Steam und iCloud.[18][19][17] Laut Bundesamt für Sicherheit in der Informationstechnik (BSI) ergaben Berichte von CERT-Quellen, dass weltweite Massenscans und versuchte Kompromittierungen, sowie laut F-Secure auch Ransomware-Angriffe im Zuge der Zero-Day-Lücke stattfanden.[20][19] Das BSI verwies auf eine „unvollständige Auflistung“ von 140 Unternehmen, die besonders anfällig seien, schätze die direkte Bedrohung für Endanwender jedoch als eher gering ein.[21][19][17]
Bekannte Fälle, in denen die Sicherheitslücke kriminell ausgenutzt wurde, sind (Auswahl):[22]
Die Schließung der Sicherheitslücke war nach kurzer Zeit über eine Softwareaktualisierung möglich, die Umsetzung durch die jeweils betroffenen Softwarehersteller zog sich jedoch aufgrund der Komplexität der Nutzung von Log4j über mehrere Wochen und teilweise sogar Monate hin.[25] Im März 2023, 15 Monate nach Entdeckung und Schließung der Sicherheitslücke, waren immer noch mehr als ein Drittel der täglich heruntergeladenen Versionen von Log4j von der Sicherheitslücke betroffen. Dies wird auf automatische Softwareverteilung und -downloads durch Abhängigkeiten zurückgeführt.[26]