Introduction
Modern applications rarely exist as a single monolithic system. Most organizations now build applications using microservices, cloud-native architectures, APIs, message queues, databases, and third-party services. While these architectures improve scalability and flexibility, they also introduce new challenges when diagnosing performance issues and troubleshooting failures.
Imagine a user request that travels through an API Gateway, multiple microservices, a database, a cache, and several external services. When something goes wrong, identifying the root cause can be difficult without proper observability.
This is where OpenTelemetry becomes essential. OpenTelemetry provides a standardized way to collect telemetry data, including traces, metrics, and logs, helping developers understand how requests flow through distributed systems.
In this article, you'll learn how distributed tracing works, how OpenTelemetry integrates with .NET applications, and how to implement end-to-end tracing for better observability and monitoring.
What Is OpenTelemetry?
OpenTelemetry is an open-source observability framework designed to collect, process, and export telemetry data from applications and infrastructure.
It provides support for:
Distributed tracing
Metrics collection
Log correlation
Application monitoring
Performance analysis
OpenTelemetry is vendor-neutral, meaning telemetry data can be exported to various monitoring platforms without changing application code.
Popular integrations include:
Azure Monitor
Application Insights
Jaeger
Zipkin
Prometheus
Grafana
Datadog
New Relic
This flexibility has made OpenTelemetry the industry standard for observability.
Understanding Distributed Tracing
Distributed tracing tracks a request as it moves through different components of a system.
Consider the following architecture:
Client
↓
API Gateway
↓
Order Service
↓
Payment Service
↓
Database
Without tracing, determining where latency occurs is difficult.
Distributed tracing allows developers to see:
Request flow
Execution time
Dependencies
Failures
Bottlenecks
This visibility is critical in modern distributed applications.
Core OpenTelemetry Concepts
Before implementing OpenTelemetry, it's important to understand its primary components.
Trace
A trace represents the complete journey of a request.
Example:
Create Order Request
A single trace may span multiple services and systems.
Span
A span represents a single operation within a trace.
Example:
Create Order
↓
Validate Payment
↓
Save Database Record
Each operation becomes a separate span.
Context Propagation
Context propagation allows trace information to move across services.
This enables OpenTelemetry to reconstruct the complete request path.
Exporter
An exporter sends telemetry data to monitoring systems.
Examples include:
Jaeger Exporter
Zipkin Exporter
Azure Monitor Exporter
OTLP Exporter
Why OpenTelemetry Matters in .NET Applications
Traditional logging provides useful information, but it often lacks context across distributed systems.
OpenTelemetry provides:
For enterprise .NET applications, observability is no longer optional.
Setting Up OpenTelemetry in .NET
Create a new ASP.NET Core application:
dotnet new webapi -n OpenTelemetryDemo
Install the required packages:
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.Console
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
These packages provide tracing capabilities and telemetry export functionality.
Configure OpenTelemetry
Add OpenTelemetry configuration in Program.cs.
using OpenTelemetry.Trace;
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddConsoleExporter();
});
This configuration automatically captures:
Incoming HTTP requests
Outgoing HTTP requests
Trace information
Telemetry is displayed in the console.
Automatic Instrumentation
One of OpenTelemetry's biggest advantages is automatic instrumentation.
When enabled, many operations are traced automatically.
Example:
app.MapGet("/products", () =>
{
return Results.Ok("Products Retrieved");
});
When a request reaches this endpoint, OpenTelemetry automatically generates trace data.
No additional code is required.
Creating Custom Spans
Developers often need visibility into business operations.
Custom spans provide this capability.
Example:
using System.Diagnostics;
private static readonly ActivitySource
ActivitySource =
new("OrderService");
using var activity =
ActivitySource.StartActivity(
"ProcessOrder");
Additional metadata can be attached.
activity?.SetTag(
"order.id",
1001);
Custom spans improve trace detail and troubleshooting accuracy.
Tracing Database Operations
Database interactions are often performance bottlenecks.
Install SQL instrumentation:
dotnet add package OpenTelemetry.Instrumentation.SqlClient
Configure tracing:
tracing.AddSqlClientInstrumentation();
OpenTelemetry automatically captures:
SQL execution time
Database dependencies
Query latency
This helps identify slow database operations.
Tracing Outgoing HTTP Requests
Many applications call external APIs.
Example:
var client = new HttpClient();
var response =
await client.GetAsync(
"https://api.example.com");
With HttpClient instrumentation enabled:
tracing.AddHttpClientInstrumentation();
OpenTelemetry records:
Request duration
Response status
External dependencies
This provides visibility into third-party service performance.
Exporting Traces to Jaeger
Jaeger is a popular distributed tracing platform.
Install exporter:
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
Configure exporter:
tracing.AddOtlpExporter(options =>
{
options.Endpoint =
new Uri(
"http://localhost:4317");
});
Jaeger provides a visual representation of request traces.
Developers can quickly identify bottlenecks and failures.
Correlating Logs and Traces
One challenge in distributed systems is connecting logs with traces.
OpenTelemetry provides trace identifiers that can be included in logs.
Example:
_logger.LogInformation(
"Processing order {OrderId}",
orderId);
When trace IDs are attached, developers can easily correlate:
This dramatically improves troubleshooting efficiency.
Monitoring Microservices
Consider a microservices architecture:
API Gateway
↓
Order Service
↓
Inventory Service
↓
Payment Service
↓
Database
Without OpenTelemetry:
With OpenTelemetry:
This is one of the primary reasons organizations adopt distributed tracing.
Practical Example
A customer submits an order.
Trace output:
Trace ID:
123456
Create Order
120ms
Validate Payment
80ms
Save Database Record
45ms
Send Confirmation Email
350ms
The trace reveals that email processing introduces the most latency.
Developers can immediately focus optimization efforts on the correct component.
Without tracing, identifying this bottleneck could take significantly longer.
Best Practices
When implementing OpenTelemetry in .NET applications:
Define meaningful span names.
Add useful metadata through tags.
Instrument critical business operations.
Avoid collecting sensitive information.
Use sampling for high-volume workloads.
Standardize telemetry across services.
Monitor trace storage costs.
Correlate logs, metrics, and traces.
These practices improve observability while maintaining performance.
Common Mistakes to Avoid
Avoid these common pitfalls:
Tracing every operation unnecessarily.
Storing sensitive customer data in traces.
Ignoring trace sampling strategies.
Creating inconsistent span names.
Failing to monitor telemetry overhead.
Not correlating traces with logs.
A well-designed observability strategy balances visibility and performance.
Real-World Use Cases
OpenTelemetry is widely used for:
Organizations use OpenTelemetry to improve reliability, reduce downtime, and accelerate troubleshooting.
Conclusion
OpenTelemetry has become the standard solution for observability in modern distributed systems. By providing end-to-end distributed tracing, it enables developers to understand how requests move through applications, identify bottlenecks, and diagnose issues more effectively.
For .NET applications, OpenTelemetry offers seamless integration with ASP.NET Core, HttpClient, databases, and external services. Combined with monitoring platforms such as Jaeger, Grafana, Azure Monitor, and Application Insights, it provides the visibility needed to operate complex cloud-native applications confidently.
As software architectures continue to become more distributed, implementing OpenTelemetry is one of the most valuable investments organizations can make in application reliability, performance, and operational excellence.