Description
Proposed topic or title
Capturing CPU and memory metrics within your application
Location in table of contents.
Metrics and diagnostics
Reason for the article
This stems from this discussion. The existing IResourceMonitor
which was very easy to use is now deprecated with this message:
This API is obsolete and will be removed in a future version. Consider using Resource Monitoring observable instruments.
As someone new to metrics, I found it unclear and confusing on how to proceed. Ideally, consumers should be able to easily capture CPU and memory metrics in a way that is cgroup aware. I understand there are existing examples of capturing custom metrics, but there is no simple example that shows how to get CPU and memory. The major difference here is that CPU and memory are metrics that get computed outside of the user's application unlike the existing custom metrics example. Showing a simple console app example for capturing CPU and memory using only System.Diagnostics.Metrics
would be largely beneficial to consumers.
I tried putting together a simple example which is shown below. One thing in particular was that I was not able to get any of my callbacks to fire in this example until I started calling listener.RecordObservableInstruments()
explicitly every few seconds. Is this expected? It was all unclear to me. I only knew to try this because a StackOverflow user commented about it on my question here.
using MeterListener listener = new();
listener.InstrumentPublished = (instrument, l) =>
{
l.EnableMeasurementEvents(instrument);
};
listener.SetMeasurementEventCallback<long>((instrument, value, tags, state) =>
{
Console.WriteLine("{0} = {1} {2}", instrument.Name, value, instrument.Unit);
});
listener.SetMeasurementEventCallback<double>((instrument, value, tags, state) =>
{
Console.WriteLine("{0} = {1} {2}", instrument.Name, value, instrument.Unit);
});
listener.SetMeasurementEventCallback<decimal>((instrument, value, tags, state) =>
{
Console.WriteLine("{0} = {1} {2}", instrument.Name, value, instrument.Unit);
});
listener.Start();
Console.WriteLine("Listening for metrics...");
List<byte[]> memory = [];
while (true)
{
var array = new byte[1024];
var index = Random.Shared.Next(array.Length);
array[index] = (byte)Random.Shared.Next(0, 255); // Touch memory to make sure it's being used
Console.WriteLine(array[index]);
memory.Add(array); // Keep adding memory
await Task.Delay(TimeSpan.FromSeconds(3));
listener.RecordObservableInstruments(); // IF YOU DON'T CALL THIS, THEN THE CALLBACKS WILL NEVER FIRE
}
So anyhow, I think it would be very useful to have a clear and concise document that shows how to get these values within the C# application in a dead simple console app that uses only System.Diagnostics.Metrics
and not open telemetry.
Article abstract
This article aims to provide a simple, self-contained C# console app that demonstrates how to collect and hook into the metrics that are captured by the runtime such as CPU and memory using only System.Diagnostics.Metrics
. This example is targeted at consumers who need a straightforward way to track system resource usage within their applications without relying on external libraries like OpenTelemetry or external tooling like Prometheus, etc.
Relevant searches
dotnet metrics, capturing CPU and memory C#, C# CPU and memory, C# metrics cgroup, C# metrics, etc.