OpenTelemetry for .NET: Distributed Tracing & Metrics Guide
Learn to implement OpenTelemetry in .NET for distributed tracing, metrics, and logging.
20+ years shipping production .NET services in enterprise systems. Everything here is grounded in real deployments.
- ✓Basic knowledge of C# and ASP.NET Core
- ✓Visual Studio or .NET CLI installed
- ✓Familiarity with NuGet packages
- OpenTelemetry is an observability framework for collecting traces, metrics, and logs.
- In .NET, use the
OpenTelemetrySDK and exporter packages. - Key signals: traces (spans), metrics (instruments), logs.
- Export to backends like Jaeger, Prometheus, or Azure Monitor.
- Instrument ASP.NET Core automatically via
AddAspNetCoreInstrumentation().
Think of OpenTelemetry as a black box flight recorder for your app. It records every request (trace) as a series of steps (spans), measures performance (metrics), and logs errors. When something goes wrong, you can replay the flight to find the issue.
Modern applications are distributed, often spanning multiple services, databases, and cloud infrastructure. When a user reports a slow page load or an error, pinpointing the root cause becomes a detective game. Traditional logging gives you isolated messages, but lacks context across service boundaries. This is where OpenTelemetry shines.
OpenTelemetry is an open-source observability framework that provides a unified way to collect traces, metrics, and logs from your applications. It standardizes how telemetry data is generated, collected, and exported, making it easier to monitor and debug complex systems.
In this tutorial, you'll learn how to instrument a .NET application with OpenTelemetry. We'll cover distributed tracing, metrics, and logs, with practical examples for ASP.NET Core. You'll see how to export data to Jaeger for traces and Prometheus for metrics. By the end, you'll have a production-ready setup that helps you understand your application's behavior and quickly diagnose issues.
What is OpenTelemetry?
OpenTelemetry is a collection of APIs, SDKs, and tools for instrumenting, generating, collecting, and exporting telemetry data (traces, metrics, logs) to help you analyze your software's performance and behavior. It is vendor-agnostic and supports multiple backends like Jaeger, Prometheus, Zipkin, and Azure Monitor.
- Traces: Record the path of a request through a system, consisting of spans (individual operations).
- Metrics: Aggregate measurements (e.g., request count, latency) over time.
- Logs: Timestamped text records with structured data.
OpenTelemetry standardizes how these signals are generated and exported, allowing you to switch backends without changing your instrumentation code.
Setting Up Distributed Tracing
Distributed tracing tracks a single request as it travels across multiple services. Each service creates spans that are linked together via a trace ID. In .NET, you can automatically instrument ASP.NET Core requests, HttpClient calls, and database queries.
To set up tracing, add the OpenTelemetry SDK and configure the tracer provider. Use AddAspNetCoreInstrumentation() to capture incoming HTTP requests, and AddHttpClientInstrumentation() to capture outgoing HTTP calls. You can also add custom spans for business logic.
TraceIdRatioBasedSampler) to sample a percentage of requests.Collecting Metrics
Metrics are numerical measurements collected over time, such as request count, latency, and error rate. OpenTelemetry provides instruments like Counter, Histogram, and Gauge. ASP.NET Core instrumentation automatically captures HTTP server metrics (request duration, active requests). You can also create custom metrics.
To export metrics, configure a metric reader and exporter. Prometheus is a popular backend; use AddPrometheusExporter() to expose a /metrics endpoint.
Integrating Logs with OpenTelemetry
OpenTelemetry can also collect logs, providing a structured and correlated logging experience. By integrating with .NET's ILogger, you can enrich logs with trace and span IDs, making it easy to correlate logs with traces.
To enable OpenTelemetry logging, add the OpenTelemetry.Extensions.Logging package and configure the logger factory.
Exporting Telemetry to Backends
OpenTelemetry supports multiple exporters: Console, OTLP (OpenTelemetry Protocol), Jaeger, Zipkin, Prometheus, Azure Monitor, and more. The OTLP exporter is the recommended standard, as it can send traces, metrics, and logs to any OTLP-compatible backend.
To export to Jaeger, use the OpenTelemetry.Exporter.Jaeger package. For Prometheus, use OpenTelemetry.Exporter.Prometheus.AspNetCore. For Azure Monitor, use Azure.Monitor.OpenTelemetry.AspNetCore.
Sampling Strategies
In high-traffic systems, collecting every trace can be expensive. Sampling allows you to collect a representative subset. OpenTelemetry supports head-based sampling (decision made at the start of a trace) and tail-based sampling (decision made after the trace is complete).
Head-based sampling is simpler and can be configured via the sampler. For example, TraceIdRatioBasedSampler samples a fixed percentage of traces.
Security and Best Practices
When instrumenting your application, be mindful of security. Avoid capturing sensitive data in span attributes or log messages. Use attribute filtering to redact personal information.
Also, ensure that your OpenTelemetry endpoints are secured. If using OTLP over gRPC, consider TLS. For Prometheus scraping, protect the /metrics endpoint with authentication if it exposes internal metrics.
- Use semantic conventions for attribute names.
- Set appropriate resource attributes (service name, version, environment).
- Monitor the overhead of OpenTelemetry itself (CPU, memory).
- Regularly review and update exporter configurations.
The Silent Database Timeout
- Average metrics can hide outliers; use percentiles and traces to catch slow requests.
- Distributed tracing reveals the exact span where time is spent.
- Always instrument database calls with OpenTelemetry to see query performance.
- Set up alerts on span duration percentiles (e.g., p99).
- Use span attributes to capture query text and parameters for debugging.
dotnet add package OpenTelemetry.Exporter.ConsoleAdd UseConsoleExporter() to see traces in console.| File | Command / Code | Purpose |
|---|---|---|
| Program.cs | using OpenTelemetry; | What is OpenTelemetry? |
| Program.cs | using OpenTelemetry.Trace; | Setting Up Distributed Tracing |
| Program.cs | using OpenTelemetry.Metrics; | Collecting Metrics |
| Program.cs | using OpenTelemetry.Logs; | Integrating Logs with OpenTelemetry |
| Program.cs | builder.Services.AddOpenTelemetry() | Exporting Telemetry to Backends |
Key takeaways
Common mistakes to avoid
5 patternsNot setting up a sampler and exporting 100% of traces in production.
Forgetting to add instrumentation for HttpClient or database calls.
Using Console exporter in production.
Not handling exceptions in custom spans.
Exposing sensitive data in span attributes or logs.
Interview Questions on This Topic
Explain the three pillars of observability and how OpenTelemetry addresses them.
Frequently Asked Questions
20+ years shipping production .NET services in enterprise systems. Everything here is grounded in real deployments.
That's ASP.NET. Mark it forged?
3 min read · try the examples if you haven't