Projekt: Logger
Ziele
- Ich kann ein Java-Package ohne
main
erstellen und darin nur statische Hilfsfunktionen bereitstellen. - Ich kann zeilenweise Logausgaben in eine Datei schreiben (anhängen, nicht überschreiben).
- Ich kann Log-Level unterscheiden und sichtbar machen.
- Ich kann ein leicht lesbares Zeitformat vorneweg in jeder Zeile schreiben.

Einführung
Was ist ein Logger? Ein Logger schreibt wichtige Ereignisse deines Programms in eine Datei, damit du später nachvollziehen kannst, was wann passiert ist (z. B. Start, Fehler, Warnungen). Jedes Ereignis ist eine Zeile (bei langen Nachrichten ggf. mehrere Zeilen), die u. a. Informationen zu Zeit, Prozess und Thread des Ereignisses enthält.
Was ist ein Log-Level? Log-Level sind Bedeutungsstufen: z. B. INF
(Information), WRN
(Warnung), ERR
(Fehler). Optional: DBG
(Debug), TRC
(sehr detailliert). Über einen Minimal-Level kannst du steuern, ab
welcher Stufe geschrieben wird: TRC
→ DBG
→ INF
→ WRN
→ ERR
. Bei Minimal-Level INF
werden auch WRN
und ERR
geschrieben, bei Minimal-Level WRN
nur noch WRN
und ERR
.
PID & TID (kurz):
- PID = Process ID, die Kennzahl deines laufenden Prozesses (Programms).
- TID = Thread ID, die Kennzahl eines Ausführungsstrangs innerhalb des Prozesses.
Details zu Threads behandeln wir später im eigenen Modul. Für das Loggen reicht: PID/TID helfen, Aktivitäten voneinander zu unterscheiden.
Kontext & Einschränkungen
- Nur statische Hilfsfunktionen: keine Instanzen, keine Vererbungsthemen.
- Kein
main
: Das Ergebnis ist ein Package, das in anderen Projekten genutzt werden kann. - Kein Test-Framework: Du testest manuell (siehe Abschnitt Manuelles Testen).
- Coding-Style: Halte den Coding-Style-Guide strikt ein (Einrückung, Namen, Konstanten, Javadoc etc.).
Aufgabenstellung
Implementiere ein Logging-Package, das folgende Aufgaben erfüllt:
Log-Zeilen schreiben: Pflicht-Methoden
info
,warn
,error(msg)
,error(msg, ex)
,debug
schreiben eine oder mehrere Zeile(n) in eine Log-Datei (append → am Ende anfügen, falls Datei schon existiert). Die API ist weiter unten definiert.Dateiformat: In der Log-Datei muss klar ersichtlich sein, wann welches Ereignis wo vorgekommen ist.
- Zeitstempel: Logging-Einträge können über mehrere Tage verteilt, aber auch innerhalb von Millisekunden erfolgen. Das muss ersichtlich sein.
- Message: freie Nachricht; kann mehrere Zeilen enthalten.
- PID/TID: nach Möglichkeit im Bereich 000–999 darstellen; falls grösser, darf kein Abschneiden erfolgen.
- Log-Level: Kurzform verwenden:
INF
,WRN
,ERR
, … - Quelle (optional): Mit einem 4-stelligen String soll mitgeteilt werden können, aus welchem Package der
Eintrag kommt (z. B.
MAIN
→ aus dem Main-Package,STHE
→ aus dem String-Helper-Package, …).
Dateiverwaltung & Dateiname:
- Verzeichnis: bei Bedarf erstellen.
- Dateiname: es muss klar unterschieden werden können, in welcher Reihenfolge die Dateien erstellt wurden (über Zeitstempel, Index, …). Es soll ein Text definiert werden können, der jeweils im Dateinamen enthalten ist (File Identifier).
- Dateigrösse: es muss festgelegt werden können, wie gross die Log-Datei werden darf (z. B. 1 MB).
- Rotation (Rolling): es soll definiert werden können, wie viele (Zahl) oder wie lange (Zeit) Log-Dateien aufbewahrt werden sollen. Wird eine der beiden Limiten überschritten, sollen zu viele vorhandene Log-Dateien gelöscht werden.
Thread-Sicherheit (basic): Mehrere Aufrufe dürfen keine Zeilen vermischen (synchronisieren oder
Files.newBufferedWriter
mit Append & Flush benutzen).Konfiguration (ENV/User-Datei):
Der Logger liest Einstellungen aus Umgebungsvariablen oder einer User-Konfigdatei.
- LogFolder: Speicherort der Log-Dateien.
- LogIdentifier: String, der in jeder Log-Datei enthalten sein soll.
- MinLevel: Minimal-Level.
- MaxFiles: maximale Anzahl an Log-Dateien, die aufbewahrt werden sollen.
- MaxDays: maximale Aufbewahrungszeit für eine Log-Datei in Tagen.
- LineLen (optional): maximale Länge einer Zeile in der Log-Datei. Längere Zeilen sollen umgebrochen werden.
Konfig-Pfad-Ermittlung (Reihenfolge):
- explizit via
setConfigPath(Path)
(falls genutzt), - ENV
ITNINJA_LOGGER_CONFIG
, - Default: im Benutzerverzeichnis, z. B.
~/.itninja-logger
(Windows:%USERPROFILE%\.itninja-logger
).
- explizit via
Umgebungsvariablen:
- ITNINJA_LOGGER_LOGFOLDER: Speicherort der Log-Dateien.
- ITNINJA_LOGGER_LOGIDENTIFIER: String, der in jeder Log-Datei enthalten sein soll.
- ITNINJA_LOGGER_MINLEVEL: Minimal-Level.
- ITNINJA_LOGGER_MAXFILES: maximale Anzahl an Log-Dateien, die aufbewahrt werden sollen.
- ITNINJA_LOGGER_MAXDAYS: maximale Aufbewahrungszeit für eine Log-Datei in Tagen.
- ITNINJA_LOGGER_LINELEN (optional): maximale Länge einer Zeile in der Log-Datei. Längere Zeilen sollen umgebrochen werden.
Konfigurationsermittlung (Reihenfolge):
- explizit via Methodenaufruf im Code (falls vorhanden),
- aus der Konfigurationsdatei, falls definiert und vorhanden,
- aus den Umgebungsvariablen.
Fehlertoleranz: Wenn die Log-Datei nicht geschrieben werden kann, wirf keine Exception nach aussen. Dokumentiere das Verhalten (z. B. Fallback auf
System.err
).Performance: Das Schreiben in die Log-Datei soll so performant wie möglich erfolgen. Alle zusätzlichen Aufgaben wie z. B. die Dateiverwaltung erfolgen in separaten Methoden, die beim Start aufgerufen werden und vom Benutzer des Logging-Packages aufgerufen werden können.
Konsole: Per Konfiguration soll es möglich sein, die Log-Ausgabe nicht nur in die Log-Datei zu schreiben, sondern auch auf der Konsole auszugeben. (Optional) Mittels farbigem Text soll zwischen den verschiedenen Log-Levels unterschieden werden können.
API – minimale Pflicht
Die folgenden Pflicht-Methoden müssen vorhanden sein; alle weiteren sind optional. Der Logger funktioniert ohne optionale Methoden (Defaults & Konfigurationsdatei/Umgebungsvariablen).
|
|
API – optionale Erweiterungen
|
|
Du darfst die API vereinfachen oder erweitern, solange die Anforderungen erfüllt sind.
Manuelles Testen (ohne Test-Framework)
Mini-Demo-Klasse in einem separaten Projekt (oder im selben Repo unter
demo/
), nicht im Logger-Package:1 2 3 4 5 6 7 8
public class LoggerDemo { public static void main(String[] args) { Logger.init(Path.of("./logs/app.log"), "Tournament", LogLevel.INF); Logger.info("Round started"); Logger.warn("Low disk space (drive=C: freeMB=512)"); Logger.error("Failed to open config file (path=./cfg/app.yaml)"); } }
Mehrfachlauf: Programm 3–5× starten → prüfen, dass Zeilen angehängt werden.
Level-Filter:
setMinLevel(LogLevel.WRN)
setzen →INF
darf nicht mehr erscheinen.Race-Test (einfach): In der Demo mehrere Threads starten, die parallel loggen → keine Zeilenverschachtelung.
Datei öffnen: Mit einem Editor prüfen, dass keine leeren Zeilen entstehen.
(Optional) Rotation: Datei bis > 1 MB füllen → prüfen, dass eine neue Log-Datei erstellt und beschrieben wird.
Akzeptanzkriterien (Definition of Done)
- Package baut ohne Fehler, ohne
main
. - Es wird ein
.jar
erstellt. - Es existiert eine README.md im Package mit kurzer API- und Konfigurations-Beschreibung und Beispiel.
- API ist mit JavaDoc dokumentiert.
- Log-Datei wird angelegt, angehängt und enthält die geforderten Informationen.
- Minimal-Level-Filter funktioniert.
- Keine Exceptions verlassen die öffentlichen Methoden (Fehler beim Schreiben werden intern behandelt und dokumentiert).
- Coding-Style-Guide eingehalten (Formatierung, Namen, Kommentare/Javadoc, keine Magic Numbers, sinnvolle
final
-Konstanten).
Ordner-/Dateistruktur (Vorschlag)

pom.xml
in den Verzeichnissen logger
und demo
kannst du eine pom.xml
aus deinen Übungen als Vorlage
nehmen.
|
|
pom.xml
im Root:
|
|
Abgabe

- Eigenes Repo
it-ninja-[deinName]-logger
(ersetze[deinName]
mit deinem Namen). - Repo-URL mit
logger/
(Package) unddemo/
(manuelle Tests). - Kurze Beschreibung in der
README.md
– wie ausführen, wo die Datei liegt.
Architektur & Austauschbarkeit (Ausblick)
Ziel ist eine Struktur, in der wir Packages austauschen können: Logger
, Tournament
, Game
sowie getrennte
Frontend- und Backend-Varianten. Damit können wir z. B. vergleichen, wie GameEngine A ein Spiel gegenüber
GameEngine B anders spielt, ohne den Logger oder das Frontend zu ändern.
- Halte die API des Loggers stabil und minimal.
- Verwende neutrale, sprechende Methodennamen und kurze, robuste Formate (siehe Pflichtformat), damit andere Module leicht integrieren können.
- Erstelle zusätzliche Utility-Klassen, wenn sinnvoll.