Laut der vierten jährlichen Observability-Umfrage von Grafana Labs (März 2026) ist OpenTelemetry weit verbreitet: für Metriken (57 %), Traces (50 %) und Logs (48 %). Diese Zahlen klingen gut, bis man eine schwierigere Frage stellt: Wie viele dieser Organisationen können eine einzelne Kundentransaktion vom API-Gateway über ein Kafka-Topic in einen Camunda-Workflow, weiter zu einem LLM-Anbieter und wieder zurück verfolgen? Ehrlich beantwortet: Die meisten können es nicht.
„Wir nutzen Tracing“ heißt meist: teilweise instrumentiert. Die HTTP-Services sind abgedeckt. Die Queue dahinter ist ein schwarzes Loch. Die BPM-Engine, die einen langlaufenden Genehmigungsprozess ausführt? Abgekoppelt. Der KI-Aufruf, der ein Dokument bewertet oder eine Zusammenfassung erzeugt? Flache Logs, kein Parent-Span, keine Verbindung zum auslösenden Geschäftsereignis. In dieser Lücke zwischen „wir tracen“ und „wir korrelieren“ werden Incidents teuer und Audits unangenehm.
W3C Trace Context liefert die gemeinsame Sprache: einen traceparent-Header (und optional einen tracestate), der standardisiert, wie Trace Context Servicegrenzen überquert. Das Protokoll ist einfach, die Disziplin drumherum nicht.
Der häufigste Fehler, den ich in den IT-Landschaften von Unternehmen sehe, ist zugleich der schädlichste: einen eingehenden traceparent unverändert in jeden nachgelagerten Request zu kopieren. Das wirkt intuitiv (gleicher Trace, gleicher Header, oder?), zerstört aber die Parent-Child-Beziehungen. Jeder nachgelagerte Span hängt am ursprünglichen Aufrufer und erscheint deshalb auf derselben Ebene wie der Service, der ihn tatsächlich ausgelöst hat, statt darunter als dessen Child. Aus Ihrem Trace-Baum wird ein Trace-Pfannkuchen: für die Ursachenanalyse unbrauchbar.
Korrekte Propagation folgt drei Schritten. Den eingehenden Kontext extrahieren. Einen Span für die aktuelle Operation erzeugen. Einen neuen ausgehenden Kontext injizieren, der den aktuellen Span als Parent trägt. Das Propagationsmodell von OpenTelemetry schreibt genau das fest: auf dem Weg hinaus in einen Carrier injizieren, auf dem Weg hinein aus dem Carrier extrahieren. Bei HTTP ist der Carrier ein Header. Beim Messaging sind es die Metadaten der Nachricht. Bei KI-Aufrufen ist es das, was Ihr Gateway oder SDK anzuhängen erlaubt. Das Prinzip bleibt gleich, nur der Carrier wechselt.
Kafka, RabbitMQ, SQS: Sobald Sie eine Nachricht an einen Broker übergeben, kommen Verzögerungen, Retries, erneute Zustellung, Fan-out, Fan-in und Batching ins Spiel. Jedes dieser Ereignisse im Lebenszyklus einer Nachricht kann einen Trace unbemerkt abreißen lassen, wenn Sie keine Regeln für die Propagation festgelegt haben. (Wenn noch offen ist, wo eine Queue überhaupt hingehört, beginnen Sie mit den drei Fragen zu API oder ereignisgesteuerter Architektur.)
Trace Context in die Message-Header zu injizieren ist die Grundlage. Fehlt diese Injektion, erscheint die Verarbeitung beim Consumer als abgekoppelter, verwaister Trace ohne Verbindung zur erzeugenden Transaktion. Die Injektion in die Header allein legt aber noch nicht fest, welche Form der Trace bekommt. Die OpenTelemetry Semantic Conventions für Messaging machen Span Links zum Standard: Der Span, der eine Nachricht verarbeitet, soll auf den Erstellungskontext dieser Nachricht verlinken, und den Erstellungskontext als Parent zu verwenden ist nur zulässig, wenn eine einzelne Nachricht verarbeitet wird. Der Grund ist einfach. Ein Span hat genau einen Parent; wenn also fünf Producer einen Batch eines Consumers speisen, können nur Links alle fünf zeigen. Links sind die einzige Trace-Struktur, die bei einzelnen Nachrichten, Batches, Retries und erneuter Zustellung gleich bleibt.
Meine Faustregel aus der Praxis: Eine Nachricht, ein Producer, ein Consumer, zügig verarbeitet, darf den Producer als Parent behalten, wenn die Wasserfallansicht dadurch leichter zu lesen ist. Batches, Fan-in, verzögerte Retries und erneute Zustellung bekommen eigene Spans, die auf den Erstellungskontext jeder einzelnen Nachricht zurückverlinken. Legen Sie diese Regel fest, bevor Sie instrumentieren; sie nach einem Incident im Produktivbetrieb nachzurüsten ist mühsam und bleibt meist unvollständig. Retries und Dead Letter Queues folgen eigenen Designregeln, die unser Leitfaden zu Timeouts, Retries, Idempotenz und DLQs behandelt. Der Trace sollte jeden Versuch zeigen, nicht nur den letzten.
Eine Workflow-Engine wie Camunda bringt eine Zeitdimension mit, für die HTTP-zentriertes Tracing nicht gebaut wurde. Eine Prozessinstanz kann den auslösenden Request um Stunden, Tage oder Wochen überdauern. Timer laufen ab. Benutzeraufgaben (Human Tasks) warten. Job Worker holen sich Arbeit asynchron ab. Der Trace Context, den der ursprüngliche HTTP-Aufruf im Speicher hielt, ist längst verschwunden.
Die Versuchung ist groß, die Prozessinstanz-ID oder einen Business Key (Bestellnummer, Fallnummer) als Korrelationsmechanismus zu nehmen und es dabei zu belassen. Diese Kennungen sind nützlich für die operative Suche und den Kundensupport, aber sie sind kein Trace Context. Sie bilden keine Parent-Beziehung zwischen Spans ab, sie laufen nicht durch die Propagatoren von OpenTelemetry, und sie tauchen nicht im Abhängigkeitsgraphen Ihres Tracing-Backends auf.
Was funktioniert: den Trace Context mit dem Prozess persistieren. Beim Start des Prozesses speichern Sie den auslösenden traceparent als Prozessvariable. Wenn ein Job Worker einen Task übernimmt, starten Sie für diese Ausführung einen neuen Trace, hängen die Prozessinstanz-ID als Span-Attribut an und fügen einen Span Link zum gespeicherten Kontext hinzu (oder zum Trace des vorherigen Tasks, wenn Sie auch diesen speichern). So erhalten Sie zwei Sichten, die sich ergänzen: die fachliche Korrelation über die Prozessinstanz-ID und den technischen Trace-Graphen über verlinkte Spans. Keine ersetzt die andere.
Wie das Observability-Team von Elastic festgestellt hat, entscheidet das Tracing von Modell- und Tool-Aufrufen als vollwertige Spans darüber, ob man nur sagen kann „die KI hat etwas getan“ oder „die KI hat dies getan, in diesem Workflow-Schritt, für diese Kundentransaktion, und so verteilt sich die Latenz“. Flache KI-Logs, die nur festhalten, welcher Prompt hineinging und welche Antwort herauskam, ohne Parent-Span und ohne Trace-ID, lassen sich nicht auf das Geschäftsereignis zurückführen, das sie ausgelöst hat.
Wenn Ihre KI-Aufrufe über ein Gateway laufen (und in einer Umgebung mit klarer Governance sollten sie das; wir haben Cloudflare AI Gateway als einen solchen Kontrollpunkt untersucht), ist der Aufruf dieses Gateways die Stelle, an der Sie den Trace Context injizieren. Propagieren Sie den Trace Context in den Gateway-Request, und lassen Sie Ihr SDK oder Ihren Gateway-Client einen Child-Span für den Modellaufruf erzeugen. Die OpenTelemetry Semantic Conventions für GenAI benennen dessen Attribute: gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.provider.name. Sie sind noch als in Entwicklung gekennzeichnet, geben aber jedem Team dieselben Feldnamen. Prompt- und Antwortinhalte (gen_ai.input.messages, gen_ai.output.messages) sind Opt-in; so bleibt der Span abfragbar, ohne dass Ihr Tracing-Backend zur Kopie jedes Prompts wird. Datenschutzfreundlich, auditierbar und mit der auslösenden Transaktion verbunden.
Bei agentischen Mustern, in denen ein Modellaufruf einen Tool-Aufruf auslöst, der wiederum einen weiteren Modellaufruf auslöst, gilt: Jeder Schritt ist ein Span, jeder Span trägt den Trace. Der Entscheidungsgraph des Agenten wird in derselben Wasserfallansicht sichtbar wie der API-Aufruf und die Queue-Nachricht, mit denen alles begann. Das hilft auch bei den Aufzeichnungspflichten: Für Hochrisiko-KI-Systeme verlangt die KI-Verordnung der EU (EU AI Act, Artikel 12) die automatische Aufzeichnung von Ereignissen über die gesamte Lebensdauer des Systems. Ein Trace, der jeden Modellaufruf mit seinem Prozessschritt und seiner Transaktion verbindet, ist eine solide Grundlage für diese Aufzeichnungen, ohne dass Prompts im Trace-Speicher landen.
Fünf Kontrollen, die ich umgesetzt sehen möchte, bevor ein Team von durchgängiger Trace-Korrelation spricht:
- Verifizierte Propagation je Grenztyp. HTTP, Messaging, Task-Dispatch in der BPM-Engine, KI-Gateway. Testen Sie jeden einzeln. Ein Trace, der drei Grenzen überquert und an der zweiten den Kontext verliert, ist schlimmer als gar kein Tracing, weil er falsche Sicherheit erzeugt.
- Eine explizite Tracing-Policy für asynchrone Abläufe. Dokumentieren Sie, wann ein Consumer den Producer als Parent behält und wann er verlinkt. Machen Sie die Entscheidung in Code-Reviews sichtbar, statt sie in den Defaults einer Bibliothek zu vergraben.
- Geschäftsidentität als Attribut, nicht als Ersatz. Bestell-IDs, Fallnummern und Prozessinstanz-IDs gehören als Attribute an den Span. Sie ergänzen den Trace Context, ersetzen ihn aber nicht.
- Ein Design für KI-Spans. Modellaufrufe bekommen eigene Spans mit den GenAI-Attributnamen. Keine flachen Logs. Kein „Tracing bauen wir später ein“.
- Eingehender Trace Context als nicht vertrauenswürdige Eingabe. Nach W3C Trace Context wird ein ungültiger traceparent ignoriert und ein neuer Trace gestartet; die Spezifikation beschreibt zudem, den Trace am Eingang eines gesicherten Netzwerks neu zu starten. Lassen Sie auch keinen externen Aufrufer über Ihr Sampling entscheiden: Ein erzwungenes Sampled-Flag ist ein billiger Weg, Ihr Tracing zu überlasten.
Wählen Sie eine reale Transaktion, die alle vier Grenzen überquert, und nehmen Sie sie sich zeitnah vor. Verfolgen Sie sie vom API-Aufruf über die Queue und den Workflow-Task bis zum Modellaufruf, und notieren Sie jede Stelle, an der der Trace abreißt. Jeder Abriss ist ein Carrier ohne Propagationspfad. Beheben Sie die Stellen in der Reihenfolge, in der die Transaktion auf sie trifft, und gehen Sie denselben Weg nach dem nächsten Release erneut ab.


