Zurück zu allen Beiträgen
·5 Min. Lesezeit

Distributed Tracing: Logs, Metriken und Traces gemeinsam gestalten

Wenn eine Anwendung in einem Prozess läuft, ist Fehlersuche vergleichsweise direkt: Fehlerdatensatz öffnen, den relevanten Stack Trace finden und die Logs um diesen Zeitpunkt prüfen. Sobald eine Anfrage über ein API-Gateway, einen Identitätsservice, eine Message Queue, einen Background Worker und einen Drittanbieter läuft, reicht diese Methode nicht mehr. „Ein Nutzer konnte nicht bezahlen“ ist dann kein einzelner Fehler, sondern eine Ereigniskette.

Observability bedeutet, diese Kette sichtbar zu machen, während das System läuft, statt sie später zu erraten. Mit einem guten Setup kann ein Team drei Fragen schnell beantworten: Was ist passiert? Wo ist es passiert? Warum ist es passiert? Logs beschreiben ein detailliertes Ereignis, Metriken zeigen das Verhalten des gesamten Systems und Traces zeigen den End-to-End-Weg einer einzelnen Anfrage. Diese Signale sind keine Alternativen, sondern ergänzen einander.

Zuerst Fragen für Störungen definieren

Observability sollte nicht mit der Installation eines Tools beginnen. Zunächst sollten die operativen Fragen aufgeschrieben werden, die beantwortet werden müssen:

  • Warum wurde eine Nutzeranfrage langsam?
  • Welcher Endpoint hat die Fehlerrate erhöht?
  • Warum verzögern sich Nachrichten in einer Queue?
  • Wie viele Personen waren von demselben Fehler betroffen?
  • Welche Abläufe sind betroffen, wenn ein externer Dienst langsamer wird?

Diese Fragen entscheiden, welches Signal benötigt wird. Um den Ort einer Latenz zu finden, braucht es einen Trace; um eine gestiegene Fehlerrate der letzten Stunde zu sehen, eine Metrik; um den Ablauf einer einzelnen Person zu verstehen, kontextreiche Logs. „Alles loggen“ erzeugt ein teures, lautes System, das häufig keine dieser Fragen beantwortet.

Einer Anfrage eine gemeinsame Identität geben

Die Grundlage für Distributed Tracing ist eine Correlation ID oder ein Trace Context. Wenn eine Anfrage das System betritt, wird eine Trace-ID erzeugt oder ein gültiger Kontext aus dem vorgelagerten System übernommen. Diese Kennung wird über HTTP-Aufrufe, Queue-Nachrichten und Background Jobs weitergegeben.

Entscheidend ist nicht nur, die Kennung in eine Logzeile zu schreiben. Jeder neue Span oder Untervorgang muss den Kontext seines Elternvorgangs erben. Ein Weg, der mit einer API-Anfrage beginnt, kann dann als ein Baum über eine Datenbankabfrage, einen weiteren HTTP-Aufruf und einen asynchronen Consumer hinweg betrachtet werden.

In Queue-basierten Architekturen gehört der Kontext in die Message Headers. Wenn ein Consumer die Nachricht verarbeitet, sollte er deren Trace Context fortsetzen und keine neue, unabhängige Transaktion beginnen. Sonst unterbrechen asynchrone Grenzen den Trace-Baum genau dort, wo er am dringendsten gebraucht wird.

Traces zeigen Wege, Metriken zeigen Trends

Ein Trace zeigt, was bei einer bestimmten Anfrage geschah und wie lange es dauerte. Ein Span kann GET /orders, eine PostgreSQL-Abfrage, einen Redis-Zugriff oder einen Aufruf beim Zahlungsanbieter darstellen. Spans erhalten einen Operationsnamen, Dauer, Ergebnisstatus und kleine, begrenzte Attribute.

Eine Metrik zeigt aggregiertes Verhalten statt der Details einer einzelnen Anfrage. Anzahl der Anfragen, Fehlerzahl, Queue-Tiefe, Verarbeitungsdauer und aktive Verbindungen lassen sich als Zeitreihen verfolgen. Gerade bei Latenz ist ein Durchschnitt allein irreführend. Perzentile wie p95 oder p99 zeigen oft besser die langsame Erfahrung, die Nutzer tatsächlich sehen.

Zusammen sind die Signale stark: Ein Dashboard zeigt steigende p95-Latenz, ein Trace erklärt, welche Abhängigkeit oder Abfrage sie verursacht hat. Traces nur als Werkzeug für Einzelfehler und Metriken nur als Managementansicht zu behandeln, verliert diese Beziehung.

Logs strukturiert und kontextreich halten

Logzeilen, die nur aus für Menschen lesbarem Text bestehen, sind schwer abzufragen. Strukturierte Logs, häufig im JSON-Format, ermöglichen das zuverlässige Filtern von Feldern wie Zeit, Level, Servicename, Umgebung, Trace-ID, Span-ID, Operationsname und Fehlertyp.

Kontext hinzuzufügen bedeutet nicht, sensible Daten zu loggen. Passwörter, Access Tokens, vollständige Zahlungsdaten und Inhalte persönlicher Dokumente dürfen nie in Logs erscheinen. Wenn eine Nutzerkennung nötig ist, ist eine pseudonyme oder technische Kennung innerhalb der Aufbewahrungsrichtlinie sicherer. Logging ist ein Diagnosewerkzeug, kein zweiter Datenspeicher.

Für einen Fehlerdatensatz können Ausnahmeklasse, Fehlercode, Name der Abhängigkeit und Informationen zur Wiederholung nützlich sein. Statt allgemeiner Texte wie „Vorgang fehlgeschlagen“ sollten stabile Felder gewählt werden, mit denen das Team Fehlertypen gruppieren kann.

Operationsnamen und Attribute begrenzen

Schlecht benannte Traces sind ebenso wenig hilfreich wie nicht durchsuchbare Logs. Verwenden Sie GET /users/{id} statt einer Route mit Nutzerkennung wie GET /users/123. Dieselbe Regel ist für Metrikattribute noch wichtiger: Nutzer-IDs, E-Mail-Adressen, zufällige Request-IDs oder unbegrenzte URL-Pfade haben hohe Kardinalität und machen ein Metriksystem langsam und teuer.

Gute Attribute sind endlich und aussagekräftig: HTTP-Methode, Ergebnisklasse, Servicename, Queue-Name, Rechenzentrum oder Feature-Version. Vor einem Attribut hilft die Frage: „Nach wie vielen verschiedenen Werten möchte ich gruppieren?“ Ist die Antwort unbegrenzt, gehört der Wert meist in ein Log- oder Trace-Attribut, nicht in ein Metriklabel.

Alarme mit Nutzerwirkung verbinden

Nicht jeder Fehler sollte einen Alarm auslösen. Ein kurzer einzelner 404 oder ein temporärer Fehler, der nach Wiederholung erfolgreich ist, rechtfertigt vielleicht keinen nächtlichen Pager. Alarmregeln sollten Nutzerwirkung, Fehlerbudget und Dauer berücksichtigen.

Die Regel „p95-Latenz liegt fünf Minuten über dem Ziel, während ein relevantes Anfragevolumen besteht“ ist zum Beispiel gesünder als ein Alarm für eine einzelne langsame Anfrage. Bei Queues sollte nicht nur die Tiefe, sondern auch das Alter der ältesten Nachricht beobachtet werden; eine Nachricht mit geringem Volumen, die seit Stunden wartet, kann trotzdem ein ernstes Geschäftsproblem sein.

Jeder Alarm braucht ein kurzes Runbook: welches Dashboard geöffnet wird, welcher Trace abgefragt wird, was der erste sichere Schritt ist und wann eskaliert wird. Ein Alarm sollte mehr tun, als ein Problem zu melden; er sollte die Kosten für den Beginn der Untersuchung senken.

Mit einem kleinen Vertrag beginnen

Perfekte Telemetrie im gesamten System ist nicht sofort erforderlich. Beginnen Sie mit Trace Context an den Anfragegrenzen, grundlegenden HTTP-Metriken und strukturierten Fehlerlogs. Danach erweitern Sie die Abdeckung auf die zwei kritischsten Abhängigkeiten, Queue-Consumer und die wertvollsten Arbeitsabläufe.

Der Erfolg zeigt sich nicht an der Zahl der Dashboards. Er zeigt sich an der Zeit, die benötigt wird, um zu beantworten, welcher Service eine Anfrage langsam machte, welche Abhängigkeit ausfiel und wie viele Nutzer betroffen waren. Wenn diese Fragen während einer Störung innerhalb von Minuten beantwortet werden können, erfüllt das Observability-Fundament seine Aufgabe.