Course contentsShow
← C#
Lesson 869 of 1,9088. ASP.NET Core Web API EngineeringFree lesson

Distributed Tracing and Observability

You will propagate trace headers across service boundaries to monitor the health of distributed transactions.

Propagating Trace Context Across Service Boundaries

In this lesson, you will learn how to maintain a single "trace" of execution as a request travels across multiple microservices to ensure your system’s health remains transparent.

The Challenge of Distributed Systems

In a monolithic application, you can follow the execution path through a single stack trace. However, in an ASP.NET Core ecosystem, a single user request might trigger calls to an Order Service, a Payment Service, and an Inventory Service. Without distributed tracing, these logs look like isolated events. If a transaction fails in the Payment Service, you wouldn't know which Order originated it.

Propagation via Headers

To solve this, we use Distributed Tracing. When a request enters your system, the first service generates a TraceId and an optional SpanId. To keep the "thread" alive as the request moves downstream, the calling service must inject this context into the HTTP headers of the outgoing request.

When you use HttpClient in C# to call another service, modern libraries like System.Diagnostics.Activity handle much of this automatically via the W3C Trace Context standard. However, understanding the manual propagation is vital:

// Inside a service sending an HTTP request
var httpRequest = new HttpRequestMessage(HttpMethod.Post, "https://payment-service/process");

// The Activity.Current holds the active trace context
if (Activity.Current != null)
{
    // Inject the trace ID into headers so the next service picks it up
    httpRequest.Headers.Add("traceparent", Activity.Current.Id);
}

await _httpClient.SendAsync(httpRequest);

Observing the Flow

When the Payment Service receives this request, it reads the traceparent header. Instead of generating a brand-new ID, it "continues" the existing trace. When these services export their spans to an observability platform (like Application Insights or Jaeger), the platform stitches these spans together. You suddenly see a waterfall diagram: Service A called Service B, which called Service C, allowing you to pinpoint exactly where the latency or error occurred.

By ensuring your services pass these headers along, you transform fragmented logs into a cohesive, observable timeline of your system's behavior.

Key Takeaway: Distributed tracing relies on injecting trace headers into outgoing HTTP requests, allowing downstream services to attach their activities to a single, unified transaction ID.