Skip to content

Commit 5b198ed

Browse files
author
Evgenii Fedorov
committed
initial commit
1 parent 10b0fb8 commit 5b198ed

File tree

6 files changed

+216
-10
lines changed

6 files changed

+216
-10
lines changed

docs/core/diagnostics/diagnostic-resource-monitoring.md

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,57 @@
11
---
22
title: Diagnostic resource monitoring
33
description: Learn how to use the diagnostic resource monitoring library in .NET.
4-
ms.date: 11/29/2023
4+
ms.date: 07/09/2025
55
---
66

77
# Resource monitoring
88

9-
Resource monitoring involves the continuous measurement of resource utilization over a specified period. The [Microsoft.Extensions.Diagnostics.ResourceMonitoring](https://www.nuget.org/packages/Microsoft.Extensions.Diagnostics.ResourceMonitoring) NuGet package offers a collection of APIs tailored for monitoring the resource utilization of your .NET applications.
9+
Resource monitoring involves the continuous measurement of resource utilization values, such as CPU, memory, and network usage. The [Microsoft.Extensions.Diagnostics.ResourceMonitoring](https://www.nuget.org/packages/Microsoft.Extensions.Diagnostics.ResourceMonitoring) NuGet package offers a collection of APIs tailored for monitoring the resource utilization of your .NET applications.
1010

11-
The <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface furnishes methods for retrieving real-time information concerning process resource utilization. This interface supports the retrieval of data related to CPU and memory usage and is currently compatible with both Windows and Linux platforms. All resource monitoring diagnostic information is published to OpenTelemetry by default, so there's no need to manually publish this yourself.
11+
The measurements can be consumed in two ways:
1212

13-
In addition, the resource monitoring library reports various diagnostic metrics. For more information, see [Diagnostic Metrics: `Microsoft.Extensions.Diagnostics.ResourceMonitoring`](built-in-metrics-diagnostics.md#microsoftextensionsdiagnosticsresourcemonitoring).
13+
- Use [.NET metrics](metrics.md).
14+
- Use the <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface. This interface is deprecated, use the metrics-based approach instead. If you still need to listen to metric values manually, see [Migrate to metrics-based resource monitoring](#migrate-to-metrics-based-resource-monitoring).
1415

15-
## Example resource monitoring usage
16+
> [!IMPORTANT]
17+
> The <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring?displayProperty=fullName> package assumes that the consumer will register logging providers with the `Microsoft.Extensions.Logging` package. If you don't register logging, the call to `AddResourceMonitoring` will throw an exception. Furthermore, you can enable internal library logging by configuring the [`Debug`](xref:Microsoft.Extensions.Logging.LogLevel.Debug) log level for the `Microsoft.Extensions.Diagnostics.ResourceMonitoring` category as per the [guide](../extensions/logging.md#log-category).
18+
19+
## Use .NET metrics of resource monitoring
20+
21+
To consume .NET metrics produced by the Resource monitoring library:
22+
23+
1. Add the `Microsoft.Extensions.Diagnostics.ResourceMonitoring` package to your project.
24+
1. Add the resource monitoring services to your dependency injection container:
25+
26+
```csharp
27+
services.AddResourceMonitoring();
28+
```
29+
30+
1. Configure metrics collection using any OpenTelemetry-compatible metrics collector. For example:
31+
32+
```csharp
33+
services.AddOpenTelemetry()
34+
.WithMetrics(builder =>
35+
{
36+
builder.AddMeter("Microsoft.Extensions.Diagnostics.ResourceMonitoring");
37+
builder.AddConsoleExporter(); // Or any other metrics exporter
38+
});
39+
```
40+
41+
1. Now you can observe the resource usage metrics through your configured metrics exporter.
42+
43+
For information about available metrics, see [.NET extensions metrics: Microsoft.Extensions.Diagnostics.ResourceMonitoring](built-in-metrics-diagnostics.md#microsoftextensionsdiagnosticsresourcemonitoring).
44+
45+
For information about metrics collection, see [Metrics collection](metrics-collection.md).
46+
47+
## Use the `IResourceMonitor` interface
48+
49+
> [!CAUTION]
50+
> The <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface described in this section is deprecated and might be removed in future versions of .NET. [Migrate to the metrics-based approach](#migrate-to-metrics-based-resource-monitoring).
51+
52+
The <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface furnishes methods for retrieving real-time information concerning process resource utilization. This interface supports the retrieval of data related to CPU and memory usage and is currently compatible with both Windows and Linux platforms.
53+
54+
### Example resource monitoring usage
1655

1756
The following example demonstrates how to use the `IResourceMonitor` interface to retrieve information about the current process's CPU and memory usage.
1857

@@ -24,9 +63,6 @@ The preceding code:
2463
- Builds a new <xref:Microsoft.Extensions.DependencyInjection.ServiceProvider> instance from the `ServiceCollection` instance.
2564
- Gets an instance of the <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface from the `ServiceProvider` instance.
2665

27-
> [!IMPORTANT]
28-
> The <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring?displayProperty=fullName> package assumes that the consumer will register logging providers with the `Microsoft.Extensions.Logging` package. If you don't register logging, the call to `AddResourceMonitoring` will throw an exception. Furthermore, you can enable internal library logging by configuring the [`Debug`](xref:Microsoft.Extensions.Logging.LogLevel.Debug) log level for the `Microsoft.Extensions.Diagnostics.ResourceMonitoring` category as per the [guide](../extensions/logging.md#log-category).
29-
3066
At this point, with the `IResourceMonitor` implementation you'll ask for resource utilization with the <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor.GetUtilization%2A?displayProperty=nameWithType> method. The `GetUtilization` method returns a <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.ResourceUtilization> instance that contains the following information:
3167

3268
- <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.ResourceUtilization.CpuUsedPercentage?displayProperty=nameWithType>: CPU usage as a percentage.
@@ -38,7 +74,7 @@ At this point, with the `IResourceMonitor` implementation you'll ask for resourc
3874
- <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.SystemResources.GuaranteedCpuUnits?displayProperty=nameWithType>: Guaranteed CPU in units.
3975
- <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.SystemResources.MaximumCpuUnits?displayProperty=nameWithType>: Maximum CPU in units.
4076

41-
## Extend resource monitoring with Spectre.Console
77+
### Extend resource monitoring with Spectre.Console
4278

4379
Extending this example, you can leverage [Spectre.Console](https://www.nuget.org/packages/Spectre.Console), a well-regarded .NET library designed to simplify the development of visually appealing, cross-platform console applications. With Spectre, you'll be able to present resource utilization data in a tabular format. The following code illustrates the usage of the `IResourceMonitor` interface to access details regarding the CPU and memory usage of the current process, then presenting this data in a table:
4480

@@ -57,6 +93,37 @@ The following is an example of the output from the preceding code:
5793

5894
For the source code of this example, see the [Resource monitoring sample](https://github.com/dotnet/docs/tree/main/docs/core/diagnostics/snippets/resource-monitoring).
5995

96+
### Migrate to metrics-based resource monitoring
97+
98+
Since the <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface is deprecated, migrate to the metrics-based approach. The `Microsoft.Extensions.Diagnostics.ResourceMonitoring` package provides several metrics that you can use instead, for instance:
99+
100+
- `container.cpu.limit.utilization`: The CPU consumption share of the running containerized application relative to resource limit in range `[0, 1]`. Available for containerized apps on Linux and Windows.
101+
- `container.cpu.request.utilization`: The CPU consumption share of the running containerized application relative to resource request in range `[0, 1]`. Available for containerized apps on Linux.
102+
- `container.memory.limit.utilization`: The memory consumption share of the running containerized application relative to resource limit in range `[0, 1]`. Available for containerized apps on Linux and Windows.
103+
104+
See the [Built-in metrics: Microsoft.Extensions.Diagnostics.ResourceMonitoring](built-in-metrics-diagnostics.md#microsoftextensionsdiagnosticsresourcemonitoring) section for more information about the available metrics.
105+
106+
#### Migration guide
107+
108+
This section provides a migration guide from the deprecated `IResourceMonitor` interface to the metrics-based approach. You only need this guide if you manually listen to resource utilization metrics in your application. In most cases, you don't need to listen to metrics manually because they're automatically collected and exported to back-ends using metrics exporters, as described in [Use .NET metrics of Resource monitoring](#use-net-metrics-of-resource-monitoring).
109+
110+
If you have code similar to the `IResourceMonitor` [example usage](#example-resource-monitoring-usage), update it as follows:
111+
112+
:::code source="snippets/resource-monitoring-with-manual-metrics/Program.cs" id="monitor" :::
113+
114+
The preceding code:
115+
116+
- Creates a cancellation token source and a cancellation token.
117+
- Creates a new `Table` instance, configuring it with a title, caption, and columns.
118+
- Performs a live render of the `Table` instance, passing in a delegate that will be invoked every three seconds.
119+
- Gets the current resource utilization information using a callback set with the `SetMeasurementEventCallback` method and displays it as a new row in the `Table` instance.
120+
121+
The following is an example of the output from the preceding code:
122+
123+
:::image type="content" source="media/resource-monitoring-with-manual-metrics-output.png" lightbox="media/resource-monitoring-with-manual-metrics-output.png" alt-text="Example Resource Monitoring with manual metrics app output.":::
124+
125+
For the complete source code of this example, see the [Resource monitoring with manual metrics sample](https://github.com/dotnet/docs/tree/main/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics).
126+
60127
## Kubernetes probes
61128

62129
In addition to resource monitoring, apps that exist within a Kubernetes cluster report their health through diagnostic probes. The [Microsoft.Extensions.Diagnostics.Probes](https://www.nuget.org/packages/Microsoft.Extensions.Diagnostics.Probes) NuGet package provides support for Kubernetes probes. It externalizes various [health checks](diagnostic-health-checks.md) that align with various Kubernetes probes, for example:
@@ -65,10 +132,11 @@ In addition to resource monitoring, apps that exist within a Kubernetes cluster
65132
- Readiness
66133
- Startup
67134

68-
The library communicates the apps current health to a Kubernetes hosting environment. If a process reports as being unhealthy, Kubernetes doesn't send it any traffic, providing the process time to recover or terminate.
135+
The library communicates the app's current health to a Kubernetes hosting environment. If a process reports as being unhealthy, Kubernetes doesn't send it any traffic, providing the process time to recover or terminate.
69136

70137
To add support for Kubernetes probes, add a package reference to [Microsoft.Extensions.Diagnostics.Probes](https://www.nuget.org/packages/Microsoft.Extensions.Diagnostics.Probes). On an <xref:Microsoft.Extensions.DependencyInjection.IServiceCollection> instance, call <xref:Microsoft.Extensions.DependencyInjection.KubernetesProbesExtensions.AddKubernetesProbes%2A>.
71138

72139
## See also
73140

74141
- [.NET extensions metrics](built-in-metrics-diagnostics.md)
142+
- [Observability with OpenTelemetry](observability-with-otel.md)
Loading
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM mcr.microsoft.com/dotnet/runtime:9.0 AS base
2+
WORKDIR /app
3+
4+
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
5+
WORKDIR /src
6+
COPY ["ResourceMonitoring/ResourceMonitoring.csproj", "ResourceMonitoring/"]
7+
RUN dotnet restore "ResourceMonitoring/ResourceMonitoring.csproj"
8+
COPY . .
9+
WORKDIR "/src/ResourceMonitoring"
10+
RUN dotnet build "ResourceMonitoring.csproj" -c Debug -o /app/build
11+
12+
FROM build AS publish
13+
RUN dotnet publish "ResourceMonitoring.csproj" -c Debug -o /app/publish /p:UseAppHost=false
14+
15+
FROM base AS final
16+
RUN apt-get update && apt-get install -y gdb
17+
WORKDIR /app
18+
COPY --from=publish /app/publish .
19+
ENTRYPOINT ["dotnet", "ResourceMonitoring.dll"]
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System.Diagnostics.Metrics;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Hosting;
4+
using Microsoft.Extensions.Logging;
5+
using Spectre.Console;
6+
7+
// <setup>
8+
var app = Host.CreateDefaultBuilder()
9+
.ConfigureServices(services =>
10+
{
11+
services.AddLogging(static builder => builder.AddConsole())
12+
.AddResourceMonitoring();
13+
})
14+
.Build();
15+
16+
var logger = app.Services.GetRequiredService<ILogger<Program>>();
17+
await app.StartAsync();
18+
// </setup>
19+
20+
using var cancellationTokenSource = new CancellationTokenSource();
21+
var token = cancellationTokenSource.Token;
22+
Console.CancelKeyPress += (_, e) =>
23+
{
24+
e.Cancel = true;
25+
cancellationTokenSource.Cancel();
26+
};
27+
28+
// <monitor>
29+
await StartMonitoringAsync(logger, token);
30+
31+
async Task StartMonitoringAsync(ILogger logger, CancellationToken cancellationToken)
32+
{
33+
var table = new Table()
34+
.Centered()
35+
.Title("Resource Monitoring", new Style(foreground: Color.Purple, decoration: Decoration.Bold))
36+
.RoundedBorder()
37+
.BorderColor(Color.Cyan1)
38+
.AddColumns(
39+
[
40+
new TableColumn("Time").Centered(),
41+
new TableColumn("CPU limit %").Centered(),
42+
new TableColumn("CPU request %").Centered(),
43+
new TableColumn("Memory limit %").Centered(),
44+
]);
45+
46+
const string rmMeterName = "Microsoft.Extensions.Diagnostics.ResourceMonitoring";
47+
using var meter = new Meter(rmMeterName);
48+
using var meterListener = new MeterListener
49+
{
50+
InstrumentPublished = (instrument, listener) =>
51+
{
52+
if (instrument.Meter.Name == rmMeterName &&
53+
instrument.Name.StartsWith("container."))
54+
{
55+
listener.EnableMeasurementEvents(instrument, null);
56+
}
57+
}
58+
};
59+
60+
var samples = new Dictionary<string, double>();
61+
meterListener.SetMeasurementEventCallback<double>((instrument, value, _, _) =>
62+
{
63+
if (instrument.Meter.Name == rmMeterName)
64+
{
65+
samples[instrument.Name] = value;
66+
}
67+
});
68+
meterListener.Start();
69+
70+
await AnsiConsole.Live(table)
71+
.StartAsync(async ctx =>
72+
{
73+
var window = TimeSpan.FromSeconds(5);
74+
while (cancellationToken.IsCancellationRequested is false)
75+
{
76+
meterListener.RecordObservableInstruments();
77+
78+
table.AddRow(
79+
[
80+
$"{DateTime.Now:T}",
81+
$"{samples["container.cpu.limit.utilization"]:p}",
82+
$"{samples["container.cpu.request.utilization"]:p}",
83+
$"{samples["container.memory.limit.utilization"]:p}",
84+
]);
85+
86+
ctx.Refresh();
87+
88+
await Task.Delay(window);
89+
}
90+
});
91+
}
92+
// </monitor>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"profiles": {
3+
"Container (Dockerfile)": {
4+
"commandName": "Docker"
5+
}
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
13+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.6" />
14+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
15+
<PackageReference Include="Microsoft.Extensions.Diagnostics.ResourceMonitoring" Version="9.6.0" />
16+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
17+
<PackageReference Include="Spectre.Console" Version="0.50.0" />
18+
</ItemGroup>
19+
20+
</Project>

0 commit comments

Comments
 (0)