Dieses Handbuch soll Ihnen grundlegende Erkenntnisse und Vorgehensweisen vermitteln, damit Sie Ihre Dienste effektiver überwachen und Fehler beheben können.
Bei der Anwendungsentwicklung wird die Protokollierung häufig übersehen, ist aber ein entscheidender Bestandteil beim Aufbau eines robusten und beobachtbaren Systems. Richtige Protokollierungspraktiken können die Sichtbarkeit Ihrer Anwendung verbessern, Ihr Verständnis ihrer Funktionsweise vertiefen und die allgemeine Anwendungsintegrität verbessern.
Standardprotokollierung
Die Einbindung von Standardprotokollierungsmechanismen an den Einstiegspunkten Ihrer Anwendung ist äußerst nützlich. Diese automatische Protokollierung kann wichtige Interaktionen erfassen und möglicherweise die Argumente des Einstiegspunkts enthalten. Dabei ist jedoch äußerste Vorsicht geboten, da die Protokollierung vertraulicher Informationen wie Passwörter Datenschutz- und Sicherheitsrisiken bergen kann.
Häufige Einstiegspunkte
- API-Endpunkte : Protokolldetails zu eingehenden Anfragen und Antworten
- Hintergrundjobs : Startpunkte, Ausführungsdetails und Ergebnisse von Jobs protokollieren
- Asynchrone Ereignisse : Protokollieren Sie die Behandlung asynchroner Ereignisse und damit verbundener Interaktionen.
Umfassende Protokollierung
Jede wichtige Aktion Ihrer Anwendung muss einen Protokolleintrag erzeugen, insbesondere solche Aktionen, die ihren Status ändern. Dieser umfassende Protokollierungsansatz ist der Schlüssel zur schnellen Identifizierung und Behebung auftretender Probleme und bietet einen transparenten Einblick in den Zustand und die Funktionalität Ihrer Anwendung. Eine solche sorgfältige Protokollierung gewährleistet eine einfachere Diagnose und Wartung.
Auswählen der geeigneten Protokollebene
Die Verwendung geeigneter Protokollebenen ist für die Verwaltung und Interpretation der enormen Datenmengen, die von Ihrer Anwendung generiert werden, von entscheidender Bedeutung. Durch die Kategorisierung von Protokollen nach Schweregrad und Relevanz stellen Sie sicher, dass kritische Probleme umgehend identifiziert und behoben werden, während weniger dringende Informationen zugänglich bleiben, ohne Ihre Überwachungsbemühungen zu überfordern.
Nachfolgend finden Sie eine Richtlinie zur effektiven Verwendung von Protokollebenen:
Ebene | Beschreibung & Beispiele | Akzeptierte Nutzung | Nicht akzeptiert |
---|---|---|---|
| Schwerwiegende Ereignisse, die den Systembetrieb stoppen, z. B. verlorene Datenbankverbindung | Kritische Systemfehler | Nicht kritische Fehler, wie fehlgeschlagene Benutzeranmeldeversuche |
| Es liegt ein Problem vor, aber das System kann die Ausführung fortsetzen und den angeforderten Vorgang abschließen | Mögliche Probleme, die zu Problemen führen | Routinemäßige Statusänderungen |
| Einblicke in normale Anwendungsfunktionen, wie das Anlegen von Benutzerkonten oder das Schreiben von Daten | Statusänderungen | Nur-Lese-Operationen ohne Änderungen |
| Detaillierte Diagnoseinformationen, wie z. B. Prozessstart/-ende | Das Protokollieren von Prozessschritten verändert den Systemzustand nicht | Routinemäßige Zustandsänderungen oder hochfrequente Operationen |
| Die detaillierteste Ebene, einschließlich Methodenein- und -ausgängen | Den Ablauf und die Details eines Prozesses verstehen | Protokollierung vertraulicher Informationen |
Welche IDs sollen protokolliert werden? - Hierarchischer Ansatz
Wenn Sie Aktionen in Ihrer Anwendung protokollieren, ist die Angabe der IDs der direkt beteiligten Entitäten entscheidend, um Protokollinformationen mit Datenbankdaten zu verknüpfen. Ein hierarchischer Ansatz hilft Ihnen dabei, schnell alle Protokolle zu finden, die mit einem bestimmten Teil Ihrer Anwendung verbunden sind, indem Elemente mit ihren übergeordneten Gruppen oder Kategorien verknüpft werden.
Anstatt beispielsweise nur die ID eines Chats zu protokollieren, wenn eine Nachricht nicht gesendet werden kann, sollten Sie auch die IDs des Chatrooms und des Unternehmens protokollieren, zu dem er gehört. Auf diese Weise erhalten Sie mehr Kontext und können die umfassenderen Auswirkungen des Problems erkennen.
Beispiel-Protokolleintrag:
Failed to send the message - chat=$roomId, chatRoomId=chatRoomId, company=$companyId
Beispiel für Produktionsprotokolle
Nachfolgend sehen Sie ein Beispiel, wie Produktionsprotokolle bei Verwendung des hierarchischen Ansatzes aussehen könnten:
Konsistenz und Standardisierung
Standardpräfixe
Durch die Standardisierung der Protokollformate in allen Teams können Sie Ihre Protokolle viel einfacher lesen und verstehen. Hier sind einige standardisierte Präfixe, die Sie berücksichtigen sollten:
- Fangen Sie an, etwas zu tun
- Etwas nicht geschafft
- Etwas erledigt
- Etwas ausgelassen
- Versuchen Sie erneut, etwas zu tun
Variable Werte separat protokollieren
Das Trennen von Variablennamen und -werten vom Hauptteil der Protokollmeldungen bietet mehrere Vorteile:
- Vereinfacht die Suche und Analyse von Protokollen: Erleichtert das Filtern und Auffinden bestimmter Informationen
- Optimiert die Erstellung von Protokollnachrichten: Macht den Prozess des Schreibens von Protokollnachrichten unkompliziert
- Verhindert Nachrichtenüberflutung: Große Werte beeinträchtigen die Lesbarkeit der Protokollnachricht nicht
Beispiel für ein Protokollformat:
Log message - valueName=value
Beispiele für Protokolle, die vorgeschlagene Vorgehensweisen verwenden
Theoretisches Beispiel
Nachfolgend finden Sie Beispiele für gut strukturierte Protokolleinträge, die den besprochenen Best Practices entsprechen:
2023-10-05 14:32:01 [INFO] Successful login attempt - userId=24543, teamId=1321312 2023-10-05 14:33:17 [WARN] Failed login attempt - userId=536435, teamId=1321312
Diese Beispiele zeigen:
- Standardisierte Protokollpräfixe : Klare, konsistente Präfixe wie „Erfolgreicher Anmeldeversuch“ und „Fehlgeschlagener Anmeldeversuch“ machen die Protokolle leicht verständlich.
- Getrennte Variablenwerte : Variablennamen und -werte werden von der Protokollnachricht getrennt, um die Übersichtlichkeit zu wahren und die Suche zu vereinfachen.
- Lesbarkeit und Konsistenz : Das strukturierte Format stellt sicher, dass die Protokolle leicht zu lesen und zu analysieren sind, was eine effiziente Fehlerbehebung und Überwachung unterstützt.
Beispiel für Produktionsprotokolle
Nachfolgend sehen Sie ein Beispiel dafür, wie Produktionsprotokolle bei Verwendung der vorgeschlagenen Vorgehensweisen aussehen könnten:
Trace-IDs
Um Protokolle effektiv einer bestimmten Benutzeraktion zuzuordnen, ist es wichtig, eine traceId
oder auch correlationId
in Ihre Protokolle aufzunehmen. Die ID sollte in allen Protokollen, die von der durch diesen Einstiegspunkt ausgelösten Logik generiert werden, konsistent bleiben und eine klare Ansicht der Ereignisabfolge bieten.
Implementierungsbeispiel
Während einige Überwachungsdienste wie Datadog standardmäßig eine Protokollgruppierung bereitstellen, kann diese auch manuell implementiert werden. In einer Kotlin-Anwendung mit Spring können Sie mithilfe eines HandlerInterceptor eine Trace-ID für REST-Anfragen implementieren.
@Component class TraceIdInterceptor : HandlerInterceptor { companion object { private const val TRACE_ID = "traceId" } override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { val traceId = UUID.randomUUID().toString() MDC.put(TRACE_ID, traceId) return true } override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) { MDC.remove(TRACE_ID) } }
Dieser Interceptor generiert für jede Anforderung eine eindeutige traceId
, fügt sie zu Beginn der Anforderung zum MDC hinzu und entfernt sie nach Abschluss der Anforderung.
Beispielprotokolle mit traceId
Durch die Implementierung einer solchen Protokollaggregation können Sie Protokolle ähnlich wie im folgenden Beispiel filtern
Verwenden von UUID vs. langen IDs in Protokollen
In vielen Systemen können Entitäten entweder UUID
oder Long
IDs als primäre Kennungen verwenden, während einige Systeme beide ID-Typen für unterschiedliche Zwecke verwenden. Um eine fundierte Entscheidung treffen zu können, ist es wichtig, die Auswirkungen der einzelnen Typen für Protokollierungszwecke zu verstehen.
Hier ist eine Aufschlüsselung der zu berücksichtigenden Dinge:
Lesbarkeit: Long
IDs sind leichter zu lesen und deutlich kürzer, insbesondere wenn sie nicht am oberen Ende des Long
Bereichs liegen.
Eindeutiger Wert: UUID
IDs sorgen für Eindeutigkeit im gesamten System, sodass Sie mithilfe einer ID nach Protokollen suchen können, ohne dass es zu ID-Kollisionen kommt. Kollisionen bedeuten hier, dass die Möglichkeit besteht, dass zwei Entitäten aus nicht miteinander verbundenen DB-Tabellen dieselbe Long
ID haben.
Systembeschränkungen : In Systemen, die lange Primärschlüssel als Entitäts-IDs verwenden, ist das Hinzufügen einer zufälligen UUID
ID normalerweise unkompliziert. In einem verteilten System mit UUID
Entitäts-IDs kann es schwierig oder kostspielig sein, Long
IDs speziell für die Protokollierung zu haben.
Vorhandene Protokolle: Konsistenz in der Art der in Protokollen verwendeten IDs ist entscheidend, zumindest pro Entität. Wenn das System bereits Protokolle für einige Entitäten erstellt und Sie nicht vorhaben, alle zu ändern, ist es besser, bei dem Typ zu bleiben, der bereits zur Identifizierung der Entität verwendet wird. Während einer Übergangsphase kann das Protokollieren beider IDs in Betracht gezogen werden, aber die dauerhafte Verwendung mehrerer IDs führt zu unnötiger Unordnung in den Protokollen.
Abschluss
Richtige Protokollierungspraktiken sind für eine effektive Servicebeobachtung unerlässlich. Durch die Integration umfassender Protokollierung, geeigneter Protokollebenen, Ablaufverfolgungs-IDs und standardisierter Protokollformate können Sie Ihre Fähigkeit zur Überwachung und Fehlerbehebung Ihrer Anwendungen erheblich verbessern. Diese Praktiken verbessern die Klarheit und Konsistenz Ihrer Protokolle und erleichtern so die schnelle Diagnose und Lösung von Problemen.
Vielen Dank, dass Sie sich die Zeit genommen haben, diesen Beitrag zu lesen!