Instrumenting .NET with OpenTelemetry means using the OpenTelemetry .NET SDK and instrumentation libraries, or the automatic instrumentation agent, to emit traces, metrics and logs over OTLP..
Instrumenting .NET with OpenTelemetry means using the OpenTelemetry .NET SDK and instrumentation libraries, or the automatic instrumentation agent, to emit traces, metrics and logs over OTLP.
For a .NET service you watch per-endpoint latency and error rate, database and downstream call latency, and the CLR runtime: garbage collection, the thread pool, and exceptions. The .NET-specific failure that trips teams up is thread-pool starvation, usually from blocking on async code (sync-over-async), which makes a service slow and unresponsive while CPU and memory look fine.
The correlation that pinpoints most .NET incidents is endpoint latency against thread-pool queue length and GC: latency that rises with a growing thread-pool queue is starvation, and latency that lines up with gen-2 collections is heap pressure.
.NET has first-class OpenTelemetry support. The SDK integrates with the built-in Activity tracing and the .NET metrics APIs, and instrumentation packages cover ASP.NET Core, HttpClient and common data access, so you add them and configure an OTLP exporter with AddOpenTelemetry(). For zero-code, the OpenTelemetry .NET automatic instrumentation agent injects the same instrumentation without editing the app.
The runtime metrics, GC collections and heap size, thread-pool thread and queue counts, and exception counts, come from the runtime instrumentation and are the .NET-specific half of the picture. The detail to watch is not double-emitting metrics if you run both the agent and manual SDK registration; pick one source per signal.
The signals that explain most .NET service incidents:
| Signal | Source | What it tells you / watch for |
|---|---|---|
http.server.request.duration | ASP.NET Core instrumentation | Per-endpoint latency histogram; track p95/p99 by route. |
process.runtime.dotnet.thread_pool.queue.length | runtime instrumentation | A growing queue is thread-pool starvation, the classic sync-over-async symptom. |
process.runtime.dotnet.gc.heap.size (gen 2) | runtime instrumentation | Gen-2 heap that keeps growing after collection points to a leak. |
process.runtime.dotnet.gc.collections.count | runtime instrumentation | Frequent gen-2 collections indicate allocation pressure and cause latency. |
process.runtime.dotnet.exceptions.count | runtime instrumentation | A rising exception rate, even handled ones, is expensive and often hides a real fault. |
db.client.operation.duration | data instrumentation | Query latency; if it dominates a request the fix is in the query or pool. |
A .NET dashboard should separate thread-pool starvation from GC pressure from a slow dependency. Row one: endpoint p95/p99 and 5xx by route. Row two: thread-pool queue length and available threads, and GC heap size by generation with collection frequency. Row three: database latency and exception rate.
# p99 latency by endpoint
histogram_quantile(0.99, http.server.request.duration) by (http.route)
# thread-pool starvation: queue length climbing
process.runtime.dotnet.thread_pool.queue.length
# gen-2 heap after GC: a rising floor = leak
process.runtime.dotnet.gc.heap.size{generation="gen2"}
The service becomes slow and unresponsive while CPU and memory look healthy, because blocking calls on async paths have exhausted the thread pool and new work queues. Thread-pool queue length climbing while available threads drop is the signature. Fix the sync-over-async call rather than raising the thread-pool limit.
Latency spikes line up with gen-2 collections because the service allocates heavily. Collection frequency and pause behaviour confirm it. Reduce large or frequent allocations on the hot path (pooling, spans, avoiding LOH allocations).
Gen-2 heap size grows over hours and never returns to baseline after collection, ending in high memory and eventual failure. Static caches and undisposed resources are the usual causes; the heap-size trend is the tell.
Starting thresholds to tune:
| Condition | Signal | Meaning |
|---|---|---|
| 5xx rate by route > 2% for 5m | errors | Endpoint failing. |
| thread-pool queue length > 0 sustained for 2m | runtime | Thread-pool starvation. |
| gen-2 heap trending up over 24h | memory | Probable leak. |
| exception rate rising | errors | A fault is generating exceptions. |
Ops Singularity's TelemetryOps ingests .NET OpenTelemetry data natively, and Sentinel AI resolves the incidents it reveals through governed Action Tickets. Explore TelemetryOps.
Add the OpenTelemetry packages, configure AddOpenTelemetry() with ASP.NET Core and HttpClient instrumentation, and add an OTLP exporter to your Collector. Alternatively use the automatic instrumentation agent for zero-code setup.
Yes. .NET integrates OpenTelemetry with its built-in Activity tracing and metrics APIs, and provides instrumentation packages plus an automatic instrumentation agent.
Bring a real incident. We will show you Sentinel investigate, act and verify end to end, with every action reversible and audited.