Skip to content

Commit aeacf50

Browse files
Add app
1 parent 10b0fb8 commit aeacf50

File tree

6 files changed

+196
-1
lines changed

6 files changed

+196
-1
lines changed

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

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
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+
> [!IMPORTANT]
10+
> The <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface described in this article is deprecated and might be removed in future versions of .NET. We recommend migrating to the metrics-based approach described in the [.NET extensions metrics](built-in-metrics-diagnostics.md#microsoftextensionsdiagnosticsresourcemonitoring) article.
11+
912
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.
1013

1114
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.
@@ -57,6 +60,59 @@ The following is an example of the output from the preceding code:
5760

5861
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).
5962

63+
## Migrate to metrics-based resource monitoring
64+
65+
Since the <xref:Microsoft.Extensions.Diagnostics.ResourceMonitoring.IResourceMonitor> interface is deprecated, we recommend migrating to the metrics-based approach. The `Microsoft.Extensions.Diagnostics.ResourceMonitoring` package now provides several [metrics](built-in-metrics-diagnostics.md#microsoftextensionsdiagnosticsresourcemonitoring) that you can use instead, for instance:
66+
67+
- `container.cpu.limit.utilization`: The CPU consumption of the running containerized application relative to resource limit in range `[0, 1]`. Available for containerized apps on Linux and Windows.
68+
- `container.cpu.request.utilization`: The CPU consumption of the running containerized application relative to resource request in range `[0, 1]`. Available for containerized apps on Linux.
69+
- `container.memory.limit.utilization`: The memory consumption of the running containerized application relative to resource limit in range `[0, 1]`. Available for containerized apps on Linux and Windows.
70+
71+
### Example metrics-based resource monitoring
72+
73+
To use the metrics-based approach:
74+
75+
1. Add the `Microsoft.Extensions.Diagnostics.ResourceMonitoring` package to your project.
76+
2. Add the resource monitoring services to your dependency injection container:
77+
78+
```csharp
79+
services.AddResourceMonitoring();
80+
```
81+
82+
3. Configure metrics collection using any OpenTelemetry-compatible metrics collector. For example:
83+
84+
```csharp
85+
services.AddOpenTelemetry()
86+
.WithMetrics(builder =>
87+
{
88+
builder.AddMeter("Microsoft.Extensions.Diagnostics.ResourceMonitoring");
89+
builder.AddConsoleExporter(); // Or any other exporter you prefer
90+
});
91+
```
92+
93+
4. Now you can observe the resource usage metrics through your configured metrics exporter.
94+
95+
For more detailed information about the available metrics and how to collect them, see [.NET extensions metrics: Microsoft.Extensions.Diagnostics.ResourceMonitoring](built-in-metrics-diagnostics.md#microsoftextensionsdiagnosticsresourcemonitoring) and [Metrics collection](metrics-collection.md).
96+
97+
### 1:1 migration from `IResourceMonitor` to metrics
98+
99+
This chapter provides a 1:1 migration guide from the deprecated `IResourceMonitor` interface to the metrics-based approach. This is useful in case you need to manually listen to resource utilization metrics in your application. We provide this documentation for the sake of completeness, because, otherwise, you typically don't have to listen to metrics manually, as they are are automatically collected and exported to back-ends using the respective metrics exporters.
100+
101+
:::code source="snippets/resource-monitoring-with-manual-metrics/Program.cs" id="monitor" highlight="20-41,53-56":::
102+
103+
The preceding code:
104+
105+
- Creates a cancellation token source and a cancellation token.
106+
- Creates a new `Table` instance, configuring it with a title, caption, and columns.
107+
- Performs a live render of the `Table` instance, passing in a delegate that will be invoked every three seconds.
108+
- 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.
109+
110+
The following is an example of the output from the preceding code:
111+
112+
:::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.":::
113+
114+
For the 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).
115+
60116
## Kubernetes probes
61117

62118
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:
@@ -72,3 +128,4 @@ To add support for Kubernetes probes, add a package reference to [Microsoft.Exte
72128
## See also
73129

74130
- [.NET extensions metrics](built-in-metrics-diagnostics.md)
131+
- [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)