paint-brush
So funktioniert das Logging: Observability Foundationvon@feddena
688 Lesungen
688 Lesungen

So funktioniert das Logging: Observability Foundation

von Fedor Denisov6m2024/06/22
Read on Terminal Reader

Zu lang; Lesen

Die Protokollierung ist ein wichtiger, aber häufig unterschätzter Bestandteil der Anwendungsentwicklung. Richtige Protokollierungspraktiken können die Sichtbarkeit Ihrer Anwendung verbessern und Ihr Verständnis ihrer Funktionsweise vertiefen. Dieser Leitfaden soll Ihnen grundlegende Erkenntnisse und Praktiken vermitteln, damit Sie Ihre Dienste effektiver überwachen und Fehler beheben können.
featured image - So funktioniert das Logging: Observability Foundation
Fedor Denisov HackerNoon profile picture

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

ERROR

Schwerwiegende Ereignisse, die den Systembetrieb stoppen, z. B. verlorene Datenbankverbindung

Kritische Systemfehler

Nicht kritische Fehler, wie fehlgeschlagene Benutzeranmeldeversuche

WARN

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

INFO

Einblicke in normale Anwendungsfunktionen, wie das Anlegen von Benutzerkonten oder das Schreiben von Daten

Statusänderungen

Nur-Lese-Operationen ohne Änderungen

DEBUG

Detaillierte Diagnoseinformationen, wie z. B. Prozessstart/-ende

Das Protokollieren von Prozessschritten verändert den Systemzustand nicht

Routinemäßige Zustandsänderungen oder hochfrequente Operationen

TRACE

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:

Datadog-Protokoll-Benutzeroberfläche mit Protokollen, die den vorgeschlagenen hierarchischen Ansatz verwenden

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:

Datadog-Protokoll-Benutzeroberfläche mit Filter nach dem Präfix „Beginnt mit“

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


Während der Verarbeitung von Asset-Löschanfragen generierte Protokolle

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!