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.