Implement End-to-End Observability for .NET 8 Minimal APIs with OpenTelemetry and Azure Monitor

Mahmut Sarıkaya 4 dk okuma 7 Görüntülenme 0
Implement End-to-End Observability for .NET 8 Minimal APIs with OpenTelemetry and Azure Monitor

Why observability matters for modern .NET 8 services

Imagine a production outage that lasts 30 minutes because a single downstream call times out. Without a clear view of request flow, developers waste hours chasing logs. In 2023, 73% of SRE teams reported that lack of distributed tracing delayed incident resolution by more than an hour. For .NET 8 Minimal APIs—designed for lightweight, fast‑startup microservices—integrating observability from the first line of code is no longer optional; it is a prerequisite for reliable deployments.

Prerequisites and system requirements

Before you start, ensure you have .NET SDK 8.0 installed, an Azure subscription with a Log Analytics workspace, and the Azure Monitor extension for OpenTelemetry. The following commands verify the environment:

dotnet --version # should return 8.0.x
az account show # confirms Azure CLI login

All subsequent steps assume a fresh console project created with dotnet new web -n OrderService.

Creating a Minimal API project

Open the newly generated Program.cs and replace its content with a simple order endpoint. This example returns a hard‑coded order and simulates a downstream call to an inventory service.

var builder = WebApplication.CreateBuilder(args);

// Add services later
var app = builder.Build();

app.MapGet("/order/{id}", async (int id) =>
{
    // Simulated latency
    await Task.Delay(50);
    return Results.Ok(new { Id = id, Status = "Processed", Total = 199.99 });
});

app.Run();

This minimal code compiles in seconds, illustrating the speed of .NET 8 Minimal APIs.

Integrating OpenTelemetry SDK

OpenTelemetry provides the instrumentation layer that captures traces, metrics, and logs. Add the required NuGet packages:

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

Next, configure the SDK in Program.cs before building the app:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracerProviderBuilder =>
    {
        tracerProviderBuilder
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddAzureMonitorTraceExporter(o =>
            {
                o.ConnectionString = builder.Configuration["AzureMonitor:ConnectionString"];
            });
    })
    .WithMetrics(metricProviderBuilder =>
    {
        metricProviderBuilder
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddAzureMonitorMetricExporter(o =>
            {
                o.ConnectionString = builder.Configuration["AzureMonitor:ConnectionString"];
            });
    });

var app = builder.Build();

Notice the use of AddAspNetCoreInstrumentation and AddHttpClientInstrumentation—they automatically capture incoming requests and outgoing HTTP calls, respectively.

Configuring Azure Monitor exporter

Azure Monitor requires a Log Analytics workspace connection string. Store it safely in appsettings.json:

{
  "AzureMonitor": {
    "ConnectionString": "InstrumentationKey=YOUR_KEY;IngestionEndpoint=https://YOUR_REGION.monitor.azure.com/"
  }
}

Replace YOUR_KEY and YOUR_REGION with values from the Azure portal. The exporter will send traces and metrics to Azure Monitor in near real‑time, where they become searchable in Application Insights.

Enabling distributed tracing across services

To see a complete end‑to‑end view, propagate the trace context when calling external services. Suppose the order endpoint contacts an inventory API using HttpClient:

var httpClient = new HttpClient();
app.MapGet("/order/{id}", async (int id) =>
{
    var inventoryResponse = await httpClient.GetAsync($"https://inventory.api/orders/{id}");
    var inventory = await inventoryResponse.Content.ReadFromJsonAsync<dynamic>();
    return Results.Ok(new { Id = id, Status = "Processed", Inventory = inventory?.Available ?? false });
});

The AddHttpClientInstrumentation hook automatically injects the traceparent header, allowing Azure Monitor to stitch together the order service and the inventory service into a single trace tree.

Viewing data in Azure Monitor

After deploying the service to Azure App Service or Azure Container Apps, open the Azure portal, navigate to your Log Analytics workspace, and select “Application Insights.” The “Transaction search” view will list each HTTP request with latency breakdowns. Click a trace to expand child spans, revealing the exact time spent in the inventory call, database access, or custom business logic.

Metrics such as request rate, failure percentage, and average duration are available in the “Metrics Explorer.” Configure alerts—e.g., trigger a webhook when 5‑minute error rate exceeds 2%—to automate incident response.

Practical tips for production readiness

1. **Sample rate control** – In high‑traffic environments, set Sampler = new TraceIdRatioBasedSampler(0.1) to limit data volume to 10% while preserving statistically meaningful trends.

2. **Enrich traces with business attributes** – Use Activity.Current?.AddTag("order.id", id) inside the endpoint to tag each span with the order identifier. This makes root‑cause analysis faster.

3. **Secure connection strings** – Store the Azure Monitor connection string in Azure Key Vault and reference it via builder.Configuration.AddAzureKeyVault(...) to avoid secrets in source control.

4. **Version your instrumentation** – Pin the OpenTelemetry packages to a known minor version (e.g., 1.5.0) and test upgrades in a staging environment before rolling out to production.

Conclusion

By wiring OpenTelemetry into a .NET 8 Minimal API and directing telemetry to Azure Monitor, you gain full visibility into request lifecycles, performance bottlenecks, and failure patterns. The combination of automatic ASP.NET Core instrumentation, HTTP client propagation, and Azure’s out‑of‑the‑box dashboards turns a lightweight microservice into a fully observable component of a distributed system. Implement the steps above, fine‑tune sampling, and you’ll reduce mean time to detection (MTTD) from hours to minutes.

Sources

  • Microsoft Docs – OpenTelemetry .NET Documentation
  • Azure Monitor documentation – Exporters and integration guides
  • OpenTelemetry Specification – Distributed Tracing Overview

Author: Mahmut Sarıkaya — sarikayadev.com

Etiketler: #.NET 8 #OpenTelemetry #Azure Monitor #Observability #Distributed Tracing
Paylaş:
M

Yazar

Mahmut Sarıkaya

yazılım Geliştirici

Yorumlar

Henüz yorum yok. İlk yorumu siz yapın!

Yorum Bırakın

7 + 4 =