Strukturierte JSON-Logs: Praktischer Leitfaden für Entwickler
Logging ist ein zentraler Bestandteil der Observability in modernen verteilten Systemen. Im Gegensatz zu Metriken und Traces bieten Logs die größte Flexibilität bei der Analyse von Anwendungsereignissen. Dieser Leitfaden liefert konkrete Muster für die Umsetzung effektiven Loggings mit strukturiertem JSON-Format, MDC-Kontext und klarer Trennung der Fehlerstufen.
Warum strukturierte Logs Klartext schlagen
Traditionelle Klartext-Logs sind in der Konsole einfach lesbar, bereiten aber bei automatisierter Verarbeitung massive Probleme. Ihr Parsen erfordert komplexe Regex-Muster, das Extrahieren spezifischer Daten ist knifflig, und Formatänderungen sind ein Albtraum. In verteilten Systemen, wo Vorfälle schnelle Analysen über mehrere Quellen erfordern, werden diese Schwächen zum Dealbreaker.
Strukturierte JSON-Logs lösen diese Probleme:
- Vereinfachen die Suche und Filterung nach spezifischen Feldern
- Ermöglichen partielle Indexierung in Suchsystemen
- Machen die Datenextraktion nach Vorfällen automatisch
- Erleichtern die Filterung personenbezogener Daten und das Hinzufügen von Metadaten
Beispiel für ein ineffektives Klartext-Log:
2025-03-15 10:16:01.795 INFO 12345 --- [nio-8080-exec-1] c.e.UserController : User saved to DB: User{id=123, [email protected], role=USER}
Beispiel für ein strukturiertes JSON-Log:
{
"timestamp": "2025-03-22T10:15:30.123Z",
"level": "ERROR",
"service": "auth-service",
"traceId": "1fd7a997-6517-4b63-9baa-4238f8012734",
"entrypoint": "HTTP request POST /api/user/auth",
"message": "Failed to authenticate user",
"user_id": "user-789",
"error": {
"type": "InvalidCredentials",
"details": "Provided password does not match"
}
}
Mapped Diagnostic Context für End-to-End-Tracing
Mapped Diagnostic Context (MDC) in SLF4J löst die Herausforderung, kontextuelle Infos durch Aufrufketten zu vermitteln. Statt Thread-IDs manuell durch jede Methode zu fädeln, bindet MDC Daten an den aktuellen Ausführungs-Thread.
Wichtige Aspekte der MDC-Nutzung:
- Geschäfts-IDs — user_id, order_id, transaction_id
- Technischer Kontext — traceId, spanId für Tracing
- Einstiegspunkt-Metadaten — Einstiegspunkt-Typ, Retry-Versuch
- Automatische Bereinigung — Kontext immer nach Anfragenbehandlung löschen
MDC glänzt an Einstiegspunkten, wo Geschäfts-IDs von Anfang an verfügbar sein müssen – oft aus Headern extrahiert, bevor der Payload gelesen wird.
Einstiegspunkte und ihr Logging
Ein Einstiegspunkt (EP) ist die Abstraktion für den Start der Geschäftslogik-Ausführung. Häufige Typen in modernen Apps:
- HTTP/REST-Server
- gRPC-Server
- Kafka-Consumer
- Cron-Jobs und geplante Tasks
- Message-Queue-Listener
Jeder EP sollte ein konsistentes Logging-Schema befolgen:
- Eingaben — Anfragemetadaten und Payload
- Ausführungskontext — Geschäfts-IDs, technische Parameter
- Ausgaben — Verarbeitungsergebnis oder Fehler
- Status — Erfolg/Fehler unter Berücksichtigung von Retries
Trennung von Fehlern und Warnungen in verteilten Systemen
Retries sind Standard für Zuverlässigkeit in verteilten Systemen und prägen direkt die Logging-Strategie:
WARN-Stufe für:
- Fehler bei Zwischenversuchen von Retries
- Transiente Ausfälle, die durch Retry behoben werden
- Probleme, die keine sofortige Operator-Aufmerksamkeit erfordern
ERROR-Stufe reservieren für:
- Finale fehlgeschlagene Versuche
- Kritische Fehler, die weitere Retries sinnlos machen
- Situationen, die sofortiges Eingreifen erfordern
Retries von hoch nach niedrig nummerieren (z. B. 2 → 1 → 0), wobei 0 der letzte Versuch ist. Das macht das Filtern finaler Fehler einfach.
Praktische Umsetzung mit Interceptors
Moderne Frameworks bieten Interceptors für Querschnittsanliegen. Logging-Fluss an Einstiegspunkten via Interceptors:
- Kontext-Initialisierung — traceId, spanId in MDC setzen
- Einstiegs-Log — Metadaten und Eingaben erfassen
- Anfrage verarbeiten — Geschäftslogik mit automatischer MDC-Propagation ausführen
- Ausstiegs-Log — Ergebnis oder Fehler protokollieren
- Kontext bereinigen — Alle MDC-Daten löschen
Wichtige Umsetzungselemente:
- Entry/Exit-Logging-Interceptors pro EP-Typ
- Tracing-Integration (Jaeger, Zipkin)
- Automatische Extraktion von Geschäfts-IDs aus Headern
- Konsistente JSON-Log-Serialisierung
Pflichtfelder in strukturierten Logs
Für Konsistenz und einfache Analyse muss jedes Log enthalten:
- Kerntechnische Felder
- timestamp im ISO-8601-Format
- Log-Stufe (ERROR, WARN, INFO, DEBUG)
- Service-Name und Version
- App-Instanz-ID
- Ausführungskontext
- traceId und spanId für Anfragenkorrelation
- requestId
- Einstiegspunkt-Typ und -Name
- Retry-Anzahl
- Geschäftskontext
- Wichtige Geschäfts-IDs (user_id, order_id usw.)
- Anfragemetadaten (HTTP-Methode, Endpoint, Consumer-Gruppe)
- Umgebung (Stage, Region, Cluster)
- Ereignisdaten
- Menschlich lesbare Nachricht
- Strukturierte Ereignisdetails
- Fehler-Stacktrace (bei ERROR)
- Dauer (für EP-Logs)
Integration in das Observability-Ökosystem
Strukturierte Logs stehen nicht isoliert – sie sind Teil der vollständigen Observability:
Metriken-Korrelation:
- Gemeinsame IDs zwischen Logs und Metriken
- Fehlerlogs mit Fehler-Raten-Metriken verknüpfen
- Logs nutzen, um Metriken-Anomalien zu kontextualisieren
Tracing-Integration:
- Einheitliche traceId/spanId über Logs und Traces
- Traces mit Log-Details anreichern
- Spezifische Spans via Logs debuggen
Automatisierte Verarbeitung:
- Alarme basierend auf Log-Mustern
- Hooks für Incident-Management-Systeme
- Automatische Datenextraktion für Recovery
Wichtige Erkenntnisse
- JSON-strukturierte Logs liefern maschinenlesbares Format für nahtlose automatisierte Verarbeitung und Analyse.
- MDC-Kontext vermittelt Geschäfts-IDs durch Aufrufketten ohne Änderungen an Methodensignaturen.
- Klare Fehler/Warn-Trennung unterstützt Retry-Logik und reduziert Monitoring-Rauschen.
- Einheitliches EP-Logging-Schema gewährleistet Konsistenz für verteilte Transaktionsanalysen.
- Standard-Feldset ermöglicht Ereigniskorrelation und effiziente Suche.
— Editorial Team
Noch keine Kommentare.