.NET monitoring and APM
OpenTelemetry .NET automatic instrumentation sends traces, runtime metrics and logs from ASP.NET Core, worker services and .NET Framework apps to Obseria, without code changes.


Why monitor .NET with Obseria
No code changes
The OpenTelemetry .NET automatic instrumentation hooks into ASP.NET Core, HttpClient, SQL clients and gRPC at startup.
Runtime health at a glance
GC, heap size, thread pool queue length and exceptions are shown per service and correlated with request latency.
Windows, Linux and containers
Monitor IIS-hosted apps, Linux services and Kubernetes pods with one data model based on OpenTelemetry.
.NET frameworks and libraries Obseria monitors
- ASP.NET Core and Kestrel. Every inbound request becomes a server span with route, status code and duration.
- ASP.NET on .NET Framework and IIS. Classic web apps on Windows are covered by the automatic instrumentation for .NET Framework.
- HttpClient and gRPC. Outbound calls carry W3C trace context to downstream services in any language.
- Entity Framework Core and SqlClient. SQL statements appear as client spans, including duration and target database.
- Messaging clients. Supported clients such as Azure Service Bus, RabbitMQ and Kafka propagate trace context across queues.
- Worker services and background jobs. Hosted services and console apps are traced like web workloads.
The .NET signals that matter
Obseria collects these values automatically and shows them in ready-made dashboards and alerts.Speed and connections
Shows how quickly your .NET services answer requests and how many users are connected at the same time.
Memory and cleanup
Tells you how much memory your application uses and how often it pauses to clean up, causing short delays.
Work queue
Reveals whether incoming work is piling up because the application cannot keep pace with demand.
Application errors
Highlights how often the application runs into unexpected errors, an early warning for failing features or bad releases.
Show all 9 metrics in detail
| Metric | Unit | What it tells you |
|---|---|---|
http.server.request.duration | s | Latency of inbound ASP.NET Core requests per route and status code. |
dotnet.gc.collections | {collection} | Garbage collections per generation; frequent Gen 2 collections hurt latency. |
dotnet.gc.pause.time | s | Total time the runtime was paused by GC; the direct cost of collections. |
dotnet.gc.last_collection.heap.size | By | Managed heap size per generation after the last GC, to spot leaks. |
dotnet.thread_pool.queue.length | {work_item} | Work items waiting for a thread; growth signals thread pool starvation. |
dotnet.thread_pool.thread.count | {thread} | Thread pool threads; sudden jumps often follow sync-over-async code. |
dotnet.exceptions | {exception} | Exceptions thrown, by type; spikes often precede error rate increases. |
dotnet.process.memory.working_set | By | Physical memory used by the process, to compare against container limits. |
kestrel.active_connections | {connection} | Open connections on the Kestrel web server. |
Set up .NET monitoring in minutes
- Step 1
Install the automatic instrumentation
Run the official otel-dotnet-auto-install script, use the NuGet package, or let the Obseria Agent handle hosts and Kubernetes.
- Step 2
Configure the exporter
Set OTEL_SERVICE_NAME, the Obseria OTLP endpoint and your token as environment variables.
- Step 3
Start the app
Source instrument.sh (or use the PowerShell module on Windows) and start your app as usual.
# Install OpenTelemetry .NET automatic instrumentation (Linux/macOS)
curl -sSfL -O \
https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/latest/download/otel-dotnet-auto-install.sh
sh ./otel-dotnet-auto-install.sh
chmod +x "$HOME/.otel-dotnet-auto/instrument.sh"
export OTEL_SERVICE_NAME="orders-api"
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=production"
export OTEL_EXPORTER_OTLP_ENDPOINT="${OBSERIA_OTLP_ENDPOINT}"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20${OBSERIA_TOKEN}"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
. "$HOME/.otel-dotnet-auto/instrument.sh"
dotnet OrdersApi.dllOut of the box
Dashboards, alerts and SLOs that are ready the moment data arrives.
- .NET runtime: GC, heap, thread pool, exceptions
- ASP.NET Core endpoints with RED metrics
- Alert on thread pool queue length growth
- Alert on Gen 2 collection rate
- Top exceptions by type and service
.NET monitoring: what matters
Why .NET monitoring matters
.NET powers a wide range of production systems, from ASP.NET Core APIs on Linux containers to long-lived .NET Framework applications on Windows and IIS. Both share a managed runtime with its own garbage collector, thread pool and JIT compiler. .NET monitoring means watching these runtime internals together with request traces, so you can explain why an endpoint is slow or why error rates rise after a release.
Modern .NET has observability built in: System.Diagnostics.Activity is the native span type, and System.Diagnostics.Metrics provides counters and histograms. OpenTelemetry builds on both. The OpenTelemetry .NET automatic instrumentation adds them to your app at startup, so .NET APM works without recompiling.
Runtime signals that matter
- Request latency and errors:
http.server.request.durationper route and status code gives the RED view of every ASP.NET Core service. - Garbage collection:
dotnet.gc.collectionsby generation anddotnet.gc.pause.time. Gen 2 collections are expensive and should be rare. - Heap size:
dotnet.gc.last_collection.heap.sizeper generation, including the large object heap. Steady growth means objects are kept alive. - Thread pool:
dotnet.thread_pool.queue.lengthanddotnet.thread_pool.thread.count. A growing queue is the clearest signal of thread pool starvation. - Exceptions:
dotnet.exceptionsby type. Even handled exceptions cost CPU and often hint at a failing dependency.
Common .NET performance problems
Thread pool starvation
Blocking calls such as .Result or .Wait() on async code tie up thread pool threads. The pool injects new threads slowly, requests queue up and latency explodes while CPU stays moderate. The fix is usually to make the call path fully asynchronous; the metrics tell you where and when it happens.
Memory leaks and LOH fragmentation
Static caches, event handlers that are never unsubscribed and large buffers on the large object heap keep memory alive. Watch heap size after GC and the working set together, especially in containers with tight memory limits.
Chatty database access
Entity Framework Core can generate many small queries per request. Traces show each SQL span with its duration, so N+1 patterns and missing indexes become visible without a profiler session.
Exceptions as control flow
Code that throws and catches exceptions in hot paths burns CPU. A high dotnet.exceptions rate with an unchanged error rate is the typical sign.
Socket exhaustion from HttpClient misuse
Creating a new HttpClient for every request leaves many sockets in the TIME_WAIT state and can exhaust local ports under load. Outbound client spans that fail with connection errors while the target service is healthy are a strong hint. Using IHttpClientFactory or a shared, long-lived client resolves it.
Slow dependencies hidden behind retries
Resilience libraries retry failed calls transparently. That keeps error rates low but adds latency. Traces show every retry attempt as its own client span, so you can see when a downstream service degrades long before it fails completely.
Best practices for .NET APM
- Use automatic instrumentation for broad coverage, then add custom
ActivitySourcespans for important business operations. - Set
service.nameandservice.versionso you can compare deployments side by side. - Enable log correlation: OpenTelemetry adds trace and span IDs to
ILoggeroutput, so logs and traces line up. - Alert on thread pool queue length and Gen 2 collection rate, not only on CPU and memory.
- Run on a current .NET version where the runtime emits the standard
dotnet.*metrics natively.
How Obseria helps with .NET performance monitoring
Obseria ingests OpenTelemetry traces, metrics and logs from .NET over OTLP, so you keep vendor-neutral instrumentation and can export data at any time. The Obseria Agent adds host, IIS server and container context and can roll out the automatic instrumentation on hosts and Kubernetes. TopoGraph shows how each .NET service connects to SQL Server, caches and message brokers. Continuous profiling with under 1% overhead reveals hot methods and allocations. When something breaks, Obseria Intelligence correlates thread pool starvation, a deployment or a failing dependency and explains the root cause with a chain of evidence. Dashboards, alerts and SLOs are included.
Related integrations
Related capabilities
Distributed Tracing
Follow each request across services, queues and databases with OpenTelemetry-native distributed tracing, and find the slow span or failing dependency in seconds.
Learn moreError Tracking
The Errors Inbox groups exceptions from backend, frontend and mobile apps into issues, shows their impact and lets teams assign and resolve them in one workflow.
Learn moreContinuous Profiling
Always-on continuous profiling shows which functions consume CPU, memory and locks in production, with under 1% overhead and direct links to traces.
Learn moreLearn more
What is APM (application performance monitoring)?
What is APM? Learn how application performance monitoring measures latency, throughput and errors, how distributed tracing works, and which metrics matter.
What is OpenTelemetry?
What is OpenTelemetry? Learn how OTel's APIs, SDKs, Collector, OTLP and semantic conventions produce vendor-neutral traces, metrics, logs and profiles.
.NET monitoring FAQ
Yes. The OpenTelemetry .NET automatic instrumentation supports modern .NET on Windows and Linux and .NET Framework on Windows. Obseria accepts the resulting OTLP data from both.
No. Automatic instrumentation works at startup through environment variables. You can optionally add custom spans with ActivitySource and custom metrics with Meter.
Install the automatic instrumentation on the Windows server and register it for IIS with the provided PowerShell module. The Obseria Agent adds host and IIS context.
Yes. If your app already uses the OpenTelemetry .NET SDK, point the OTLP exporter to Obseria. First traces typically arrive within 15 minutes.
Yes. Logs written through ILogger carry trace and span IDs, so Obseria links each log line to its request trace.
Start monitoring .NET today
Connect .NET in minutes with OpenTelemetry or the Obseria Agent. Free for 14 days.