Modern applications rarely consist of a single service. A single user request might travel through an API Gateway, multiple microservices, databases, caches, and third-party APIs before a response is returned. When something goes wrong, traditional logging alone often isn't enough to identify where the problem occurred.
OpenTelemetry (OTel) is an open-source observability framework that standardizes the collection of logs, metrics, and distributed traces. It enables developers to understand application behavior, diagnose performance bottlenecks, and monitor production systems using a single telemetry pipeline.
Rather than relying on disconnected logs and monitoring tools, this article demonstrates how to integrate OpenTelemetry into an ASP.NET Core application and build a production-ready observability solution.
Note: OpenTelemetry itself does not provide dashboards or data storage. It collects telemetry and exports it to observability platforms such as Prometheus, Grafana, Jaeger, Azure Monitor, or Application Insights.
Why Traditional Logging Isn't Enough
Imagine an e-commerce application where placing an order involves multiple services:
API Gateway
Order Service
Inventory Service
Payment Service
Notification Service
SQL Server
Redis
If the payment service becomes slow, each service writes its own log entries. Without distributed tracing, it's difficult to determine exactly where the request spent most of its time.
OpenTelemetry solves this problem by assigning a Trace ID that follows the request across every service involved.
The Three Pillars of Observability
OpenTelemetry collects three types of telemetry data.
| Telemetry | Purpose |
|---|---|
| Logs | Record application events and errors |
| Metrics | Measure application performance over time |
| Traces | Follow a request across multiple services |
Together, these provide complete visibility into application health.
OpenTelemetry Architecture
flowchart LR
A[ASP.NET Core API]
B[OpenTelemetry SDK]
C[OTLP Exporter]
D[OpenTelemetry Collector]
E[Jaeger]
F[Prometheus]
G[Grafana]
A --> B
B --> C
C --> D
D --> E
D --> F
F --> G
The application generates telemetry, the SDK collects it, and the OpenTelemetry Collector forwards it to one or more monitoring platforms.
Installing OpenTelemetry
Install the required NuGet packages.
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Instrumentation.SqlClient
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
These packages automatically instrument incoming HTTP requests, outgoing HTTP calls, and SQL Server operations.
Configuring OpenTelemetry
Register OpenTelemetry during application startup.
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSqlClientInstrumentation()
.AddOtlpExporter();
});
With only a few lines of configuration, your application begins collecting distributed traces automatically.
Creating Custom Spans
Automatic instrumentation covers framework operations, but business processes should also be traced.
using System.Diagnostics;
private static readonly ActivitySource Activity =
new("OrderService");
using var activity =
Activity.StartActivity("Create Order");
activity?.SetTag("CustomerId", customerId);
activity?.SetTag("OrderAmount", total);
Custom spans help identify which business operations consume the most time during request execution.
Correlating Logs and Traces
Every log entry should include its associated Trace ID.
Example:
TraceId: 7a1d4ab8ef
Order Created Successfully
CustomerId: 1054
When viewing logs inside an observability platform, the Trace ID makes it possible to jump directly to the complete request trace.
Join the conversation! Your thoughts help the community grow.