Skip to content

[API Proposal]: Expose ISnapshotProvider interface and Snapshot struct #5385

@evgenyfedorov2

Description

@evgenyfedorov2

Background and motivation

The Microsoft.Extensions.Diagnostics.ResourceMonitoring.ISnapshotProvider interface is implemented three times in this repo:

  1. https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs
  2. https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs
  3. https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Linux/LinuxUtilizationProvider.cs

which confirms the interface is useful. In addition to that, in one of Microsoft internal repos we would like to implement this interface as well. Therefore, I propose to make the ISnapshotProvider interface public, so that everyone would benefit from that. Additionally, it will require making the Snapshot struct public because the GetSnapshost() method of the ISnapshotProvider interface returns a Snapshot.

API Proposal

namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring;

/// <summary>
/// An interface to be implemented by a provider that represents an underlying system and gets resources data about it.
/// </summary>

-internal interface ISnapshotProvider
+public interface ISnapshotProvider
{
    /// <summary>
    /// Gets the static values of CPU and memory limitations defined by the system.
    /// </summary>
    SystemResources Resources { get; }

    /// <summary>
    /// Get a snapshot of the resource utilization of the system.
    /// </summary>
    /// <returns>An appropriate sample.</returns>
#pragma warning disable S4049 // Properties should be preferred
    Snapshot GetSnapshot();
}
namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring;

/// <summary>
/// A snapshot of CPU and memory usage taken periodically over time.
/// </summary>

-internal readonly struct Snapshot
+public readonly struct Snapshot
{
    /// <summary>
    /// Gets the total CPU time that has elapsed since startup.
    /// </summary>
    public TimeSpan TotalTimeSinceStart { get; }

    /// <summary>
    /// Gets the amount of kernel time that has elapsed since startup.
    /// </summary>
    public TimeSpan KernelTimeSinceStart { get; }

    /// <summary>
    /// Gets the amount of user time that has elapsed since startup.
    /// </summary>
    public TimeSpan UserTimeSinceStart { get; }

    /// <summary>
    /// Gets the memory usage within the system in bytes.
    /// </summary>
    public ulong MemoryUsageInBytes { get; }

    /// <summary>
    /// Initializes a new instance of the <see cref="Snapshot"/> struct.
    /// </summary>
    /// <param name="totalTimeSinceStart">The time at which the snapshot was taken.</param>
    /// <param name="kernelTimeSinceStart">The amount of kernel time that has elapsed since startup.</param>
    /// <param name="userTimeSinceStart">The amount of user time that has elapsed since startup.</param>
    /// <param name="memoryUsageInBytes">The memory usage within the system in bytes.</param>
    public Snapshot(
        TimeSpan totalTimeSinceStart,
        TimeSpan kernelTimeSinceStart,
        TimeSpan userTimeSinceStart,
        ulong memoryUsageInBytes)
    {
        _ = Throw.IfLessThan(memoryUsageInBytes, 0);
        _ = Throw.IfLessThan(kernelTimeSinceStart.Ticks, 0);
        _ = Throw.IfLessThan(userTimeSinceStart.Ticks, 0);

        TotalTimeSinceStart = totalTimeSinceStart;
        KernelTimeSinceStart = kernelTimeSinceStart;
        UserTimeSinceStart = userTimeSinceStart;
        MemoryUsageInBytes = memoryUsageInBytes;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="Snapshot"/> struct.
    /// </summary>
    /// <param name="timeProvider">The time provider.</param>
    /// <param name="kernelTimeSinceStart">The amount of kernel time that has elapsed since startup.</param>
    /// <param name="userTimeSinceStart">The amount of user time that has elapsed since startup.</param>
    /// <param name="memoryUsageInBytes">The memory usage within the system in bytes.</param>
    /// <remarks>This is a internal constructor to be used in unit tests only.</remarks>
    internal Snapshot(
        TimeProvider timeProvider,
        TimeSpan kernelTimeSinceStart,
        TimeSpan userTimeSinceStart,
        ulong memoryUsageInBytes)
    {
        _ = Throw.IfLessThan(memoryUsageInBytes, 0);
        _ = Throw.IfLessThan(kernelTimeSinceStart.Ticks, 0);
        _ = Throw.IfLessThan(userTimeSinceStart.Ticks, 0);

        TotalTimeSinceStart = TimeSpan.FromTicks(timeProvider.GetUtcNow().Ticks);
        KernelTimeSinceStart = kernelTimeSinceStart;
        UserTimeSinceStart = userTimeSinceStart;
        MemoryUsageInBytes = memoryUsageInBytes;
    }
}

API Usage

Possible to have a custom implementation of ISnapshotProvider which then can be manually registered in Dependency Injection

internal sealed class MyCustomSnapshotProvider : ISnapshotProvider
{
  ...
}

services.AddSingleton<ISnapshotProvider, MyCustomSnapshotProvider>();

and injected into the ResourceMonitorService' constructor here https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitorService.cs#L55

Alternative Designs

No response

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions