CodeGym /Kurse /JAVA 25 SELF /Grundlagen des Loggings: java.util.logging, Log4j, SLF4J

Grundlagen des Loggings: java.util.logging, Log4j, SLF4J

JAVA 25 SELF
Level 63, Lektion 0
Verfügbar

1. Warum Logging nötig ist

Logging ≠ Konsolenausgabe

Gerade am Anfang wirkt es so, als reiche zum Suchen von Problemen überall System.out.println("Hier war ich!") einzufügen. Das funktioniert, solange das Programm klein ist und auf Ihrem Rechner läuft. Stellen Sie sich aber ein großes Projekt vor, einen Server, der 24/7 arbeitet, oder eine Anwendung, die Tausende Menschen nutzen – Sie können ja nicht jedem Nutzer über die Schulter schauen und seine Konsole beobachten.

Logging ist nicht einfach das Ausgeben von Meldungen. Es ist die systematische Aufzeichnung von Informationen über den Betrieb einer Anwendung: Fehler, Warnungen, Business-Events, technische Details. Logs werden in Dateien oder Datenbanken gespeichert, können über das Netzwerk gesendet werden – und ermöglichen es, das Verhalten des Programms nachträglich oder sogar während der Ausführung zu analysieren.

Wofür Logs gebraucht werden

  • Diagnose von Problemen: Wenn etwas schiefläuft, sind Logs Ihr wichtigstes Hilfsmittel. Man kann daraus erkennen, wo und warum der Fehler entstanden ist.
  • Audit und Sicherheit: Logs halten wichtige Benutzeraktionen fest und helfen bei der Untersuchung von Vorfällen.
  • Debugging: Manche Bugs treten nur unter bestimmten Bedingungen auf – ohne Logs sind sie kaum zu fassen.
  • Monitoring: Anhand von Logs lässt sich der Zustand der Anwendung, ihre Leistung und ihr „Gesundheitszustand“ nachvollziehen.

Beispiel aus dem Alltag

Wenn Flugzeuge keine „Black Boxes“ (Flugschreiber) hätten, wären Unfalluntersuchungen nahezu unmöglich. In der Programmierung sind Logs Ihre Black Boxes.

2. Basis-Logging-Level

Beim Logging verwendet man üblicherweise Level für Meldungen. Das ist wie eine Ampel: Rot – gefährlich, Gelb – Vorsicht, Grün – alles in Ordnung.

Wesentliche Level (vom „lautesten“ zum „leisesten“):

Level Beschreibung
ERROR
Kritischer Fehler, die Anwendung kann nicht fortfahren
WARN
Warnung: Etwas ist schiefgelaufen, aber das Programm läuft weiter
INFO
Information über reguläre Ereignisse
DEBUG
Detailinformationen für die Fehlersuche (nur für Entwickler sichtbar)
TRACE
Äußerst detaillierte Informationen – für tiefe Diagnosen

Beispiel:

  • Ein Benutzer konnte sich wegen eines falschen Passworts nicht anmelden – das ist WARN.
  • Die Datenbank ist ausgefallen – das ist ERROR.
  • Die Anwendung ist gestartet – das ist INFO.
  • Ausgabe des Werts einer Variablen in einer Schleife – das ist DEBUG oder TRACE.

Wie man das passende Level wählt

Schreiben Sie nicht alles pauschal auf ERROR – sonst gehen echte Fehler unter. Setzen Sie die Level bewusst ein: Nur wirklich kritische Ausfälle sollten Fehler sein.

3. Standard-Logging in Java (java.util.logging)

Java wird mit einem integrierten Logging-System ausgeliefert – dem Paket java.util.logging (kurz JUL). Das ist ein „eigenes“ Werkzeug, das stets verfügbar ist, selbst wenn Sie keine Bibliotheken eingebunden haben.

Zentrale Klassen:

  • Logger – die Hauptklasse zum Schreiben von Logs.
  • Level – Aufzählung der Logging-Level (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST).
  • Handler – bestimmt, wohin geloggt wird (Datei, Konsole usw.).
  • Formatter – ist für das Format der Meldungen verantwortlich.

Beispiel für die Verwendung von JUL

import java.util.logging.Logger;
import java.util.logging.Level;

public class LoggingExample {
    // Logger anhand des Klassennamens beziehen
    private static final Logger logger = Logger.getLogger(LoggingExample.class.getName());

    public static void main(String[] args) {
        logger.info("Anwendung gestartet");
        logger.warning("Das ist eine Warnung!");
        logger.severe("Und das ist bereits ein Fehler!");

        int x = 42;
        logger.fine("Debug-Variable x=" + x); // Wird standardmäßig nicht ausgegeben
    }
}

Wichtiger Punkt: Standardmäßig gibt JUL nur die Level INFO und höher aus. Um fine und andere Detailmeldungen zu sehen, muss das Logging-Level konfiguriert werden.

Konfiguration über Datei

JUL kann über die Datei logging.properties (liegt meist im JRE-Ordner) konfiguriert werden. Dort können Sie festlegen:

  • Mindestlevel für den Logger
  • Wohin geloggt wird (Datei, Konsole)
  • Formatierung der Meldungen

Beispielzeile in logging.properties:

.level=INFO

4. Externe Logging-Bibliotheken

Log4j (Apache)

Log4j ist eine der bekanntesten Logging-Bibliotheken für Java. Sie ist flexibel, leistungsfähig, unterstützt verschiedene Formate, asynchrones Schreiben, Dateirotation und vieles mehr.

Einfachste Log4j 2-Konfiguration (XML):

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Beispiel für die Verwendung von Log4j 2 im Code:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4jExample {
    private static final Logger logger = LogManager.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.info("Hello from Log4j!");
        logger.error("Das ist ein Fehler über Log4j");
    }
}

Damit das funktioniert, müssen Sie die Log4j-Abhängigkeiten zu Ihrem Projekt hinzufügen (z. B. über Maven oder Gradle).

SLF4J: Logging-Fassade

SLF4J (Simple Logging Facade for Java) ist kein eigenständiges Logging-System, sondern eine „Zwischenschicht“ zwischen Ihrem Code und einer konkreten Implementierung (Log4j, Logback, JUL u. a.).

Die Fassade ist dazu da, Code einmal zu schreiben und bei Bedarf die tatsächliche Logging-Implementierung zu wechseln, ohne den Code umzuschreiben – selbst wenn unterschiedliche Bibliotheken unterschiedliche Logger verwenden.

Beispiel für die Verwendung von SLF4J:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Slf4jExample {
    private static final Logger logger = LoggerFactory.getLogger(Slf4jExample.class);

    public static void main(String[] args) {
        logger.info("Hallo, Logging über SLF4J!");
        logger.warn("Achtung: Es könnte etwas schiefgehen");
        logger.error("Fehler über SLF4J");
    }
}

Wie funktioniert das?

  • Sie schreiben den Code gegen SLF4J.
  • Sie fügen die gewünschte Implementierung zum Classpath hinzu (z. B. Logback oder Log4j).
  • SLF4J leitet die Aufrufe an die gewählte Implementierung weiter.

Zusammenspiel von SLF4J mit anderen Loggern: SLF4J kann auf JUL, Log4j, Logback u. a. aufsetzen und ermöglicht so eine einfache Migration ohne Codeänderungen.

5. Praxis: System.out.println versus Logging

Beispiel 1: System.out.println

public class PrintlnExample {
    public static void main(String[] args) {
        System.out.println("Anwendung gestartet");
        System.out.println("Es ist ein Fehler aufgetreten: Etwas ist schiefgelaufen");
    }
}

Was daran problematisch ist:

  • Kein Level für die Meldung (Fehler, Info, Warnung – alles gleich).
  • Keine Zeitangabe, kein Klassenname, kein Thread.
  • Alle Meldungen landen in einem Topf.
  • Keine flexible Steuerung der Ausgabe (z. B. nur Fehler schreiben).

Beispiel 2: Logging mit SLF4J + Logback

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingVsPrintln {
    private static final Logger logger = LoggerFactory.getLogger(LoggingVsPrintln.class);

    public static void main(String[] args) {
        logger.info("Anwendung gestartet");
        logger.error("Es ist ein Fehler aufgetreten: Etwas ist schiefgelaufen");
    }
}

Vorteile:

  • Jede Meldung enthält Zeit, Level, Klassenname und Thread.
  • Meldungen lassen sich nach Level filtern.
  • Logs können in Dateien geschrieben, über das Netzwerk gesendet, formatiert und archiviert werden.
  • Logging ist thread-sicher (wichtig für nebenläufige Anwendungen).

Demonstration des Unterschieds

System.out.println
Logging (SLF4J/Logback)
Anwendung gestartet 12:34:56 [main] INFO LoggingVsPrintln - Anwendung gestartet
Es ist ein Fehler aufgetreten: Etwas ist schiefgelaufen 12:34:56 [main] ERROR LoggingVsPrintln - Es ist ein Fehler aufgetreten: Etwas ist schiefgelaufen

6. Wie man Logging ins eigene Projekt bringt

Für den Standard-Logger (JUL)

Alles ist bereits im JDK enthalten, Sie können sofort loslegen:

import java.util.logging.Logger;

public class MyApp {
    private static final Logger logger = Logger.getLogger(MyApp.class.getName());

    public static void main(String[] args) {
        logger.info("Dies ist eine Info-Meldung");
    }
}

Für Log4j oder SLF4J

  1. Fügen Sie Abhängigkeiten hinzu (z. B. über Maven).

    Für Log4j 2:

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</groupId>
        <version>2.20.0</version>
    </dependency>
    

    Für SLF4J + Logback:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</groupId>
        <version>2.0.7</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</groupId>
        <version>1.4.7</version>
    </dependency>
    
  2. Erstellen Sie eine Konfigurationsdatei (z. B. logback.xml für Logback oder log4j2.xml für Log4j).
  3. Verwenden Sie den Logger in Ihrem Code (siehe Beispiele oben).

7. Mini-Anwendung: Logging hinzufügen

Nehmen wir eine einfache Anwendung – einen Kommandozeilenrechner. Fügen wir Logging hinzu.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Scanner;

public class CalculatorApp {
    private static final Logger logger = LoggerFactory.getLogger(CalculatorApp.class);

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        logger.info("Taschenrechner gestartet");

        try {
            System.out.print("Geben Sie die erste Zahl ein: ");
            int a = Integer.parseInt(scanner.nextLine());
            logger.debug("Erste Zahl eingegeben: {}", a);

            System.out.print("Geben Sie die zweite Zahl ein: ");
            int b = Integer.parseInt(scanner.nextLine());
            logger.debug("Zweite Zahl eingegeben: {}", b);

            int sum = a + b;
            logger.info("Summe der Zahlen: {}", sum);
            System.out.println("Ergebnis: " + sum);
        } catch (NumberFormatException ex) {
            logger.error("Fehler bei der Zahleneingabe", ex);
            System.out.println("Fehler: Bitte geben Sie eine gültige Zahl ein!");
        } catch (Exception ex) {
            logger.error("Unbekannter Fehler", ex);
            System.out.println("Es ist ein Fehler aufgetreten!");
        }
        logger.info("Taschenrechner beendet");
    }
}

Was hier passiert:

  • Alle Schlüsselerereignisse werden geloggt.
  • Fehler werden mit Level ERROR und vollständigem Stacktrace protokolliert.
  • Alle Informationen stehen zur Analyse nach der Programmausführung bereit.

8. Typische Fehler beim Arbeiten mit Logging

Fehler Nr. 1: Nur System.out.println für Debugging und Diagnose verwenden.
Das ist am Anfang bequem, taugt aber nicht für reale Anwendungen. Sie können die Level nicht steuern, sehen keine Zeitstempel und können Logs nicht auswerten, wenn das Programm auf einem Server läuft.

Fehler Nr. 2: Zu viele Informationen auf Level ERROR loggen.
Wenn alles als Fehler geschrieben wird, unterscheiden Sie nicht mehr, was wirklich wichtig ist und was nur Debug-Information ist.

Fehler Nr. 3: Protokollierung sensibler Daten (Passwörter, Tokens, Kartennummern).
Logs müssen sicher sein! Schreiben Sie nichts hinein, was andere nicht sehen sollten.

Fehler Nr. 4: Fehlende Logging-Konfiguration.
Ohne konfigurierte Level, Formate und Speicherorte können Sie entweder in Gigabytes unnötiger Informationen „untergehen“ oder Fehler gar nicht sehen.

Fehler Nr. 5: Nichtverwendung der Logging-Fassade (SLF4J) in großen Projekten.
Wenn Ihr Projekt wächst oder Sie die Bibliothek wechseln möchten – ohne Fassade wird das schmerzhaft. SLF4J erlaubt es, die „Engine“ des Loggings zu wechseln, ohne den Code umzuschreiben.

1
Aufgabe
JAVA 25 SELF, Level 63, Lektion 0
Gesperrt
Werksingenieur
Werksingenieur
1
Aufgabe
JAVA 25 SELF, Level 63, Lektion 0
Gesperrt
Neuer Entwickler
Neuer Entwickler
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION