Im Monolithen gab es eine Anfrage, einen Prozess und ein Protokoll. Seit diesem Modul geht eine Teilnahme an einer Ausschreibung durch das Gateway, die Kladde, den Ausschreibungsdienst, die Outbox, Service Bus und den Vertrieb. Wenn sie hängt, fragt niemand mehr „was sagt das Protokoll?“, sondern „welches Protokoll?“. Diese Lektion verbindet die Teile wieder zu einem Bild: eine Spur (trace) je Vorgang über alle Dienste, Metriken je Dienst und je Fluss, Logs, die zu ihrer Spur gehören. Die Werkzeuge kennen Sie aus K3 (3.4); neu ist, dass sie über Prozessgrenzen hinweg zusammenpassen müssen.

Eine Spur über alle Dienste

Eine Spur besteht aus Abschnitten (spans), in .NET Activity genannt. Jeder Abschnitt hat eine eigene Id und kennt die Spur-Id und seinen Elternabschnitt. Damit ein Dienst weiß, zu welcher Spur eine Anfrage gehört, reist der Kontext mit. Der Standard dafür ist W3C Trace Context: die Kopfzeile traceparent mit Version, Spur-Id, Id des Elternabschnitts und Flags, etwa 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01, dazu optional tracestate.

Wer ihn weiterreicht, hängt am Weg:

  • HTTP: HttpClient schreibt traceparent von selbst, sobald eine Aktivität läuft, und ASP.NET Core liest es auf der Gegenseite und setzt die Spur fort. Seit .NET 9 füllt HttpClient seine Abschnitte selbst nach den Konventionen von OpenTelemetry.
  • gRPC: läuft in .NET über HttpClient und HTTP/2, also gilt dasselbe.
  • YARP: leitet die Kopfzeile weiter und schreibt selbst einen Abschnitt für die Weiterleitung. Das Gateway aus Lektion 4.12.5 ist damit ein Glied der Spur.
  • Service Bus: Das SDK schreibt den Kontext beim Senden als Eigenschaft Diagnostic-Id in die Nachricht, und der Empfänger setzt die Spur beim Verarbeiten fort. Für OpenTelemetry ist diese Unterstützung nach Microsofts Dokumentation noch experimentell und muss eingeschaltet werden.

Eine Spur reißt immer dort ab, wo kein Kontext mitreist. Das passiert selten in einem Aufruf, aber regelmäßig in Arbeit, die später geschieht: ein Hintergrunddienst, ein Reminder, ein Relay. Die Anfrage, die die Arbeit auslöste, ist dann längst vorbei, und Activity.Current ist leer.