|
| 1 | +--- |
| 2 | +title: Migrate from .NET Windows Performance Counters to .NET Core metrics |
| 3 | +description: Learn how to migrate from .NET Framework Windows Performance Counters to .NET Core/NET 5+ metrics using EventCounters and Meters. |
| 4 | +ms.date: 04/27/2025 |
| 5 | +--- |
| 6 | + |
| 7 | +# Migrate from .NET Framework Windows Performance Counters to .NET metrics |
| 8 | + |
| 9 | +.NET Framework applications, which only run on Windows, can use Windows Performance Counters to monitor application health and performance. However, in .NET Core and later versions, the platform provides [cross-platform alternatives](compare-metric-apis.md) through the [EventCounters](./event-counters.md) and [System.Diagnostics.Metrics](./metrics.md) APIs. |
| 10 | + |
| 11 | +This article provides guidance on migrating from Windows Performance Counters to the newer metrics systems available in modern .NET versions. |
| 12 | + |
| 13 | +## A short history of .NET metrics |
| 14 | + |
| 15 | +.NET applications can be monitored using different mechanisms depending on the .NET version and platform: |
| 16 | + |
| 17 | +- **.NET Framework**: Primarily uses Windows Performance Counters (Windows only) |
| 18 | +- **.NET Core 3.0-3.1, .NET 5+**: Introduced EventCounters (cross-platform) and built-in [runtime metrics](./available-counters.md#systemruntime-counters), [networking metrics](./available-counters.md#systemnethttp-counters), and [ASP.NET metrics](./available-counters.md#microsoft-aspnetcore-server-kestrel-counters) using these APIs |
| 19 | +- **.NET 6+**: Added System.Diagnostics.Metrics API (cross-platform, OpenTelemetry compatible) |
| 20 | +- **.NET 8+**: Added built-in [networking metrics](./built-in-metrics-system-net.md) and [ASP.NET metrics](/aspnet/core/log-mon/metrics/built-in) using the new System.Diagnostics.Metrics API |
| 21 | +- **.NET 9+**: Added built-in [runtime metrics](./built-in-metrics-runtime.md) using the new System.Diagnostics.Metrics API |
| 22 | + |
| 23 | +The newer metrics systems offer several advantages: |
| 24 | + |
| 25 | +- **Cross-platform operation**: Works on Windows, Linux, macOS |
| 26 | +- **Container-friendly**: Works in containerized environments |
| 27 | +- **Modern tooling**: Integrates with OpenTelemetry and observability platforms |
| 28 | +- **Supports xcopy install**: No additional installation steps or privileges are required |
| 29 | + |
| 30 | +For more information, see the [Metrics API comparison](compare-metric-apis.md). |
| 31 | + |
| 32 | +## Collect metrics in modern .NET applications |
| 33 | + |
| 34 | +To collect and analyze metrics, see the [System.Diagnostics.Metrics](./metrics-collection.md) and [EventCounters](./event-counters.md) guides. |
| 35 | + |
| 36 | +## Map common Windows Performance Counters to modern metrics |
| 37 | + |
| 38 | +If the monitoring system for your .NET Framework application uses runtime-provided Windows Performance Counters, you'll need to select alternative [EventCounters](./event-counters.md) |
| 39 | +or [System.Diagnostics.Metrics](./metrics.md)-based metrics instead. The following tables show alternatives for many common counters. Not all .NET Framework counters have been ported to new alternatives. |
| 40 | +In some cases, infrequently used counters were discontinued, and in other cases, implementation changes in the platform have made certain counters irrelevant. |
| 41 | + |
| 42 | +### Memory counters |
| 43 | + |
| 44 | +| Windows Performance Counter | EventCounter equivalent | Metrics API equivalent | |
| 45 | +|----------------------------|--------------------------|------------------------| |
| 46 | +| `.NET CLR Memory\# Bytes in all Heaps` | `System.Runtime\GC Heap Size` (`gc-heap-size`) | `System.Runtime\dotnet.gc.last_collection.heap.size` | |
| 47 | +| `.NET CLR Memory\# Gen 0 Collections` | `System.Runtime\Gen 0 GC Count` (`gen-0-gc-count`) | `System.Runtime\dotnet.gc.collections` with attribute `gc.heap.generation=gen0` | |
| 48 | +| `.NET CLR Memory\# Gen 1 Collections` | `System.Runtime\Gen 1 GC Count` (`gen-1-gc-count`) | `System.Runtime\dotnet.gc.collections` with attribute `gc.heap.generation=gen1` | |
| 49 | +| `.NET CLR Memory\# Gen 2 Collections` | `System.Runtime\Gen 2 GC Count` (`gen-2-gc-count`) | `System.Runtime\dotnet.gc.collections` with attribute `gc.heap.generation=gen2` | |
| 50 | +| `.NET CLR Memory\% Time in GC` | `System.Runtime\% Time in GC since last GC` (`time-in-gc`) | `System.Runtime\dotnet.gc.pause.time` (calculate as percentage of total time) | |
| 51 | +| `.NET CLR Memory\# Total committed Bytes` | None | `System.Runtime\dotnet.gc.last_collection.memory.committed_size` | |
| 52 | +| `.NET CLR Memory\Large Object Heap Size` | `System.Runtime\LOH Size` (`loh-size`) | `System.Runtime\dotnet.gc.last_collection.heap.size` with attribute `gc.heap.generation=loh` | |
| 53 | +| `.NET CLR Memory\Allocated Bytes/sec` | `System.Runtime\Allocation Rate` (`alloc-rate`) | Calculate rate from `System.Runtime\dotnet.gc.heap.total_allocated` | |
| 54 | + |
| 55 | +> [!NOTE] |
| 56 | +> `dotnet.gc.pause.time` allows an improved calculation that avoids some undesirable behavior in the older `% Time in GC` metric. `% Time in GC` computed |
| 57 | +> 100 * `pause_time_in_most_recent_GC` / `time_between_most_recent_two_GCs`. In some cases two GCs would occur very close together producing a high value |
| 58 | +> based on a tiny non-representative portion of the overall time interval. `gc.heap.pause.time` accumulates the total time the GC has paused application threads |
| 59 | +> so far in a process, which allows computing the GC pause time during any measured time interval. This is a truer measurement of GC overhead, but the change in calculation |
| 60 | +> means the metrics might not match even when the underlying GC behavior is unchanged. |
| 61 | +
|
| 62 | +### JIT and Loading counters |
| 63 | + |
| 64 | +| Windows Performance Counter | EventCounter equivalent | Metrics API equivalent | |
| 65 | +|----------------------------|--------------------------|------------------------| |
| 66 | +| `.NET CLR Jit\# of Methods Jitted` | `System.Runtime\Methods Jitted Count` (`methods-jitted-count`) | `System.Runtime\dotnet.jit.compiled_methods` | |
| 67 | +| `.NET CLR Jit\IL Bytes Jitted` | `System.Runtime\IL Bytes Jitted` (`il-bytes-jitted`) | `System.Runtime\dotnet.jit.compiled_il.size` | |
| 68 | +| `.NET CLR Loading\Current Assemblies` | `System.Runtime\Number of Assemblies Loaded` (`assembly-count`) | `System.Runtime\dotnet.assembly.count` | |
| 69 | +| `.NET CLR Jit\Total # of IL Bytes Jitted` | `System.Runtime\IL Bytes Jitted` (`il-bytes-jitted`) | `System.Runtime\dotnet.jit.compiled_il.size` | |
| 70 | + |
| 71 | +### Threading counters |
| 72 | + |
| 73 | +| Windows Performance Counter | EventCounter equivalent | Metrics API equivalent | |
| 74 | +|----------------------------|--------------------------|------------------------| |
| 75 | +| `.NET CLR LocksAndThreads\Current Queue Length` | `System.Runtime\ThreadPool Queue Length` (`threadpool-queue-length`) | `System.Runtime\dotnet.thread_pool.queue.length` | |
| 76 | +| `.NET CLR LocksAndThreads\Contention Rate / sec` | `System.Runtime\Monitor Lock Contention Count` (`monitor-lock-contention-count`) | Calculate rate from `System.Runtime\dotnet.monitor.lock_contentions` | |
| 77 | + |
| 78 | +### Exceptions counters |
| 79 | + |
| 80 | +| Windows Performance Counter | EventCounter equivalent | Metrics API equivalent | |
| 81 | +|----------------------------|--------------------------|------------------------| |
| 82 | +| `.NET CLR Exceptions\# of Exceps Thrown / sec` | `System.Runtime\Exception Count` (`exception-count`) | Calculate rate from `System.Runtime\dotnet.exceptions` | |
| 83 | +| `.NET CLR Exceptions\# of Exceps Thrown` | None | `System.Runtime\dotnet.exceptions` | |
| 84 | + |
| 85 | +### Socket networking counters |
| 86 | + |
| 87 | +| Windows Performance Counter | EventCounter equivalent | Metrics API equivalent | |
| 88 | +|----------------------------|--------------------------|------------------------| |
| 89 | +| `.NET CLR Networking\Bytes Received` | `System.Net.Sockets\Bytes Received` (`bytes-received`) | None | |
| 90 | +| `.NET CLR Networking\Bytes Sent` | `System.Net.Sockets\Bytes Sent` (`bytes-sent`) | None | |
| 91 | +| `.NET CLR Networking\Connections Established` | `System.Net.Sockets\Outgoing Connections Established` (`outgoing-connections-established`) | None | |
| 92 | +| `.NET CLR Networking\Datagrams Received` | `System.Net.Sockets\Datagrams Received` (`datagrams-received`) | None | |
| 93 | +| `.NET CLR Networking\Datagrams Sent` | `System.Net.Sockets\Datagrams Sent` (`datagrams-sent`) | None | |
| 94 | + |
| 95 | +### DNS networking counters |
| 96 | + |
| 97 | +| Windows Performance Counter | EventCounter equivalent | Metrics API equivalent | |
| 98 | +|----------------------------|--------------------------|------------------------| |
| 99 | +| `.NET CLR Networking\DNS Lookups` | `System.Net.NameResolution\DNS Lookups Requested` (`dns-lookups-requested`) | Sum the histogram buckets in `System.Net.NameResolution\dns.lookup.duration` | |
| 100 | +| `.NET CLR Networking\DNS Resolution Time` | `System.Net.NameResolution\Average DNS Lookup Duration` (`dns-lookups-duration`) | `System.Net.NameResolution\dns.lookup.duration` | |
| 101 | + |
| 102 | +### HttpWebRequest counters |
| 103 | + |
| 104 | +`HttpWebRequest` has been superseded by <xref:System.Net.Http.HttpClient>. To learn what metrics are built-in, see the HttpClient [EventCounters](./available-counters.md#systemnethttp-counters) and [System.Diagnostics.Metrics](./built-in-metrics-system-net.md#systemnethttp). |
| 105 | + |
| 106 | +### ASP.NET counters |
| 107 | + |
| 108 | +ASP.NET has changed dramatically between .NET Framework and .NET Core. Many counters are obsolete or are measured differently than in the past. To learn what metrics are built-in, see the ASP.NET [EventCounters](./available-counters.md#microsoftaspnetcorehosting-counters) and [System.Diagnostics.Metrics](/aspnet/core/log-mon/metrics/built-in). |
| 109 | + |
| 110 | +## Next steps |
| 111 | + |
| 112 | +- Learn more about [EventCounters in .NET](./event-counters.md) |
| 113 | +- Explore the [System.Diagnostics.Metrics API](./metrics.md) |
| 114 | +- Understand how to [collect metrics](./metrics-collection.md) |
| 115 | +- Review [well-known EventCounters](./available-counters.md) and [built-in metrics](./built-in-metrics.md) |
0 commit comments