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.
Exporting Telemetry
Most production systems export telemetry using OTLP.
builder.Services.AddOpenTelemetry()
.WithTracing(builder =>
{
builder.AddOtlpExporter(options =>
{
options.Endpoint =
new Uri("http://localhost:4317");
});
});
The OpenTelemetry Collector can then forward the data to multiple backends without requiring application code changes.
Choosing an Observability Platform
Several platforms integrate seamlessly with OpenTelemetry.
| Platform | Primary Use |
|---|
| Jaeger | Distributed tracing |
| Prometheus | Metrics collection |
| Grafana | Dashboards and visualization |
| Azure Monitor | Azure-native monitoring |
| Application Insights | Application diagnostics |
The OpenTelemetry Collector makes it easy to switch between these platforms without modifying your application.
Sampling Strategies
Capturing every request in production may generate excessive telemetry.
Common sampling strategies include:
Always On
Always Off
Trace ID Ratio
Parent-Based Sampling
Sampling reduces storage costs while preserving enough telemetry for troubleshooting.
Common Production Mistakes
| Problem | Root Cause |
|---|
| Missing traces | Instrumentation not configured |
| No SQL spans | SQL instrumentation missing |
| Large telemetry volume | Sampling disabled |
| Slow exports | Synchronous exporter configuration |
| Missing Trace IDs | Logging not correlated with tracing |
Most observability issues arise from incomplete instrumentation rather than OpenTelemetry itself.
Best Practices
Instrument every service consistently.
Use meaningful span names.
Add business-specific attributes to important operations.
Enable sampling in production environments.
Export telemetry asynchronously.
Monitor the health of the telemetry pipeline.
Avoid logging sensitive customer information.
Common Anti-Patterns
Avoid these implementation mistakes:
Treating logs as a replacement for traces.
Instrumenting only the API layer.
Recording excessive custom metrics.
Ignoring failed spans.
Storing sensitive information in telemetry.
Exporting every request in high-traffic production environments.
FAQ
Does OpenTelemetry replace Serilog or Microsoft.Extensions.Logging?
No. OpenTelemetry complements existing logging frameworks by adding distributed tracing and metrics.
Should every ASP.NET Core application use OpenTelemetry?
Applications that run in production, especially those using multiple services, benefit significantly from standardized observability.
Is the OpenTelemetry Collector required?
No. Applications can export directly to supported platforms, but using the Collector provides greater flexibility and simplifies future migrations.
Does OpenTelemetry impact application performance?
Yes, but the overhead is generally low when sampling and asynchronous exporters are configured correctly.
Conclusion
OpenTelemetry has become the industry standard for application observability. By collecting logs, metrics, and distributed traces through a unified framework, developers gain complete visibility into application behavior and production performance.
For ASP.NET Core applications, integrating OpenTelemetry requires only a small amount of configuration while providing significant operational benefits. Combined with platforms such as Jaeger, Prometheus, Grafana, or Azure Monitor, it enables faster troubleshooting, proactive monitoring, and more reliable production systems.