Skip to content

[New article]: Capturing CPU and memory metrics using cgroup aware APIs. #47072

Open
@roblappcoupa

Description

@roblappcoupa

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions