Phase 14 of 30 · Topic 14.4

Distributed Tracing with `System.Diagnostics.Activity` & OpenTelemetry

1Concept

`System.Diagnostics.Activity` is the native .NET implementation of the W3C TraceContext standard, propagating `TraceId` and `SpanId` headers across distributed microservices.

2Architecture Diagram

[ Microservice A ] (TraceId: 4bf92f3577b34da6a3ce929d0e0e4736)
       │ HTTP Request Header: traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
       ▼
[ Microservice B ] ── Automatically continues parent trace context!

3Code Example

C# 13 & .NET 9
using System;
using System.Diagnostics;

public class ActivityTracingDemo
{
    private static readonly ActivitySource MyActivitySource = new("Enterprise.CheckoutService");

    public static void Main()
    {
        using var listener = new ActivityListener
        {
            ShouldListenTo = source => source.Name == "Enterprise.CheckoutService",
            Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllDataAndRecorded
        };
        ActivitySource.AddActivityListener(listener);

        using (Activity? activity = MyActivitySource.StartActivity("ProcessPayment"))
        {
            activity?.SetTag("payment.amount", 450.00);
            activity?.SetTag("payment.currency", "USD");

            Console.WriteLine($"Active TraceId: {activity?.TraceId}");
            Console.WriteLine($"Active SpanId:  {activity?.SpanId}");
        }
    }
}

4Expected Output

Active TraceId: 4bf92f3577b34da6a3ce929d0e0e4736
Active SpanId:  00f067aa0ba902b7

5Key Takeaways

  • `ActivitySource` and `Activity` have zero overhead when no listeners/OpenTelemetry collectors are attached.
  • Seamlessly exports to Jaeger, Zipkin, Azure Application Insights, and Prometheus.
  • Standard for modern cloud-native observability.