Unified Distributed Tracing for .NET 8 Microservices with OpenTelemetry, Azure Monitor, and Service Bus

Mahmut Sarıkaya 4 min read 2 Views 0
Unified Distributed Tracing for .NET 8 Microservices with OpenTelemetry, Azure Monitor, and Service Bus

Why Distributed Tracing Is Critical for .NET 8 Microservices

Imagine a user places an order, the request hops through an API gateway, an inventory service, a payment processor, and finally a notification worker. If the transaction stalls, pinpointing the exact service that introduced latency can feel like searching for a needle in a haystack. According to the 2023 Cloud Native Computing Survey, 68% of organizations cite observability gaps as the top barrier to scaling microservices. Distributed tracing fills that gap by stitching together spans from each component, giving developers a single timeline to diagnose failures.

Installing the OpenTelemetry SDK in a .NET 8 Project

The first step is adding the official OpenTelemetry packages. .NET 8 supports the minimal hosting model, so the configuration lives in Program.cs. Run the following commands in a terminal:

dotnet add package OpenTelemetry.Exporter.AzureMonitor
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Instrumentation.Azure.Messaging.ServiceBus

After the packages are installed, extend the builder with tracing services. The code below demonstrates a typical setup that captures HTTP, ASP.NET Core, and Service Bus activities while assigning a logical service name.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetryTracing(telemetryBuilder =>
{
    telemetryBuilder
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddAzureServiceBusInstrumentation()
        .AddSource("MyCompany.Services")
        .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("OrderService"))
        .AddAzureMonitorTraceExporter(o => o.ConnectionString = Environment.GetEnvironmentVariable("AZURE_MONITOR_CONNECTION_STRING"));
});
var app = builder.Build();
app.MapGet("/health", () => "OK");
app.Run();

Notice the use of ResourceBuilder to tag every span with the service name; Azure Monitor later groups traces by this attribute.

Sending Traces to Azure Monitor

Azure Monitor’s OpenTelemetry exporter ships a lightweight agent that forwards spans over HTTPS. The exporter requires a connection string that you can retrieve from the Azure portal under “Monitor → Logs → Exporters”. Store it securely, for example in an Azure Key Vault secret, and reference it via an environment variable as shown above. Once the app runs, you will see a new “Traces” blade populated within minutes, complete with dependency graphs and latency breakdowns.

Instrumenting Azure Service Bus Interactions

Service Bus is often the backbone of event‑driven architectures. The OpenTelemetry instrumentation library automatically creates spans for SendMessageAsync, ReceiveMessagesAsync, and CompleteMessageAsync. Below is a minimal producer example that respects the current activity context, ensuring the trace propagates end‑to‑end.

var connectionString = Environment.GetEnvironmentVariable("SERVICE_BUS_CONNECTION_STRING");
var queueName = "order-queue";
var client = new ServiceBusClient(connectionString);
var sender = client.CreateSender(queueName);
await sender.SendMessageAsync(new ServiceBusMessage("{ \"orderId\": 12345 }"));

The generated span will contain attributes such as messaging.system=azure.servicebus and messaging.destination=order-queue, which Azure Monitor visualizes as a distinct node linked to the originating HTTP request.

Correlating Traces Across Multiple Services

To achieve a unified view, each microservice must propagate the W3C Trace‑Context headers. In .NET 8 this happens automatically when you use HttpClientFactory together with the OpenTelemetry HTTP client instrumentation. For custom messaging patterns—like publishing an event to Service Bus from within a background worker—explicitly inject the activity context:

using var activity = new ActivitySource("MyCompany.Services").StartActivity("PublishOrderEvent");
activity?.SetTag("order.id", 12345);
await sender.SendMessageAsync(new ServiceBusMessage(JsonSerializer.Serialize(order)));

When the consumer processes the message, the Service Bus instrumentation extracts the context and continues the trace, allowing Azure Monitor to render a seamless end‑to‑end graph.

Practical Tips and Common Pitfalls

1. Sampling strategy: Production environments should enable TraceIdRatioBasedSampler at 0.1 (10 % of requests) to balance cost and visibility. Adjust the ratio based on traffic spikes.

2. Environment variables: Keep connection strings out of source control. Azure App Service and AKS support secret injection directly into the container environment.

3. Versioning: Tag the ResourceBuilder with service.version equal to your assembly version. This helps when you roll out a new release and need to compare latency trends.

4. Avoid double‑instrumentation: Do not manually create spans for operations already covered by the built‑in instrumentations; duplicate spans clutter the UI and skew latency numbers.

Conclusion

Unified distributed tracing in .NET 8 is no longer a research project; with OpenTelemetry, Azure Monitor, and Azure Service Bus you can obtain a real‑time, end‑to‑end picture of every request that flows through your microservice landscape. By installing the SDK, configuring the Azure exporter, and letting the built‑in Service Bus instrumentation handle context propagation, you gain actionable insights—faster root‑cause analysis, measurable performance improvements, and a solid foundation for future observability investments.

Sources

Microsoft Docs – OpenTelemetry for .NET
Azure Monitor documentation – Trace export
OpenTelemetry Instrumentation for Azure Service Bus – GitHub

Author: Mahmut Sarıkaya — sarikayadev.com

Tags: #distributed tracing #.net 8 #OpenTelemetry #Azure Monitor #Azure Service Bus
Share:
M

Written by

Mahmut Sarıkaya

Software Developer

Comments

No comments yet. Be the first to share your thoughts!

Leave a Comment

1 + 6 =