01 · Problem
Wofür braucht man das?
Diagnose braucht konsistente Level, strukturierte Metadaten und austauschbare Ausgaben, ohne Geschäftslogik an process.stdout oder process.exit zu koppeln.
02 · Denkmodell
Das mentale Modell
Ein LogRecord ist Daten. Ein Formatter übersetzt ihn, ein Sink schreibt ihn; TTY-Animationen sind ein optionaler Renderer oberhalb dieses Kerns.
Formatiert Meldungen mit korrigiertem Level-Filter, begrenzter Historie und expliziter Ausgabe. Das Singleton bleibt kompatibel; direkte Konstruktion erlaubt isolierte Tests. Fatal-Logs beenden den Prozess nicht.
03 · Kontrollfluss
Was passiert in welcher Reihenfolge?
- Level, Nachricht, Timestamp und Metadaten zu einem Record formen.
- Record vor Formatierung gegen eine klar geordnete Schwelle prüfen.
- Formatter erzeugt Text oder JSON ohne die Ursprungsdaten zu verändern.
- Ein injizierter Sink schreibt; Terminaleffekte laufen nur bei isTTY.
04 · Bauteile
Die entscheidenden Verträge
Logger / getInstanceErzeugt einen isolierten Logger oder liefert das kompatible Singleton.trace / debug / info / warn / error / fatalFiltert nach Schweregrad und schreibt ohne Prozessbeendigung.profile / profileSyncMisst Arbeit und räumt ihre Animation auf.05 · Selbst bauen
Selbst implementieren
Baue einen kleinen Logger ohne Globals; JSON, hübsche Konsole und Animationen können danach als getrennte Adapter folgen.
- Definiere eine monotone Levelreihenfolge und teste die Schwelle als reine Funktion.
- Injiziere Sink, Uhr und Formatter über den Konstruktor.
- Lass fatal nie im Kern den Prozess beenden; der Aufrufer entscheidet über Lifecycle.
type Level = 10 | 20 | 30 | 40 | 50;
type Record = { at: Date; level: Level; message: string; meta?: object };
class Logger {
constructor(
private threshold: Level,
private write: (record: Record) => void,
private now = () => new Date(),
) {}
log(level: Level, message: string, meta?: object) {
if (level < this.threshold) return;
this.write({ at: this.now(), level, message, meta });
}
}06 · Verifizieren
Was solltest du testen?
- Für jede Schwelle werden exakt die erlaubten Level an den Sink weitergegeben.
- Metadaten bleiben strukturiert und Formatterfehler verändern den Record nicht.
- Nicht-TTY-Sinks starten keine Animation; Exceptions stoppen Timer zuverlässig.
Selbst ausprobieren
Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.
Für jede Schwelle werden exakt die erlaubten Level an den Sink weitergegeben.
Ansatz vergleichen
Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.
07 · Grenzen
Kompromisse und Stolperfallen
- Synchrone Sinks sind einfach, können unter Last aber blockieren.
- Unbegrenzte Breadcrumbs und Metadaten können Speicher und sensible Daten akkumulieren.
- Terminalsteuerung ist plattform- und TTY-abhängig.
Das Singleton bleibt kompatibel; direkte Konstruktion erlaubt isolierte Tests. Fatal-Logs beenden den Prozess nicht.
08 · Weiterdenken
Quellcode und verwandte Ideen
yarn tsx packages/logger/examples/basic.ts