Files
Servers/MoonlightServers.Daemon/Helpers/SystemMetrics.cs

59 lines
2.4 KiB
C#

namespace MoonlightServers.Daemon.Helpers;
/// <summary>
/// Reads Linux system metrics directly from the <c>/proc</c> and <c>/sys</c>
/// pseudo-filesystems
/// </summary>
public static partial class SystemMetrics
{
public record SystemSnapshot(
CpuSnapshot Cpu,
MemoryInfo Memory,
IReadOnlyList<DiskInfo> Disks,
IReadOnlyList<NetworkInterfaceInfo> Network,
TimeSpan Uptime
);
/// <summary>
/// Collects a full system snapshot. The method waits <paramref name="sampleIntervalMs"/>
/// milliseconds between the two samples required to compute CPU and network rates.
/// All other reads happen in parallel during the second sampling window.
/// </summary>
/// <param name="sampleIntervalMs">
/// Interval between rate-measurement samples in milliseconds.
/// Larger values yield smoother CPU and network averages. Defaults to <c>500</c>.
/// </param>
/// <returns>A fully populated <see cref="SystemSnapshot"/>.</returns>
public static async Task<SystemSnapshot> ReadAllAsync(int sampleIntervalMs = 500)
{
// First samples — must complete before the delay.
var cpuSample1Task = ReadRawCpuStatsAsync();
var netSample1Task = ReadRawNetStatsAsync();
await Task.WhenAll(cpuSample1Task, netSample1Task);
await Task.Delay(sampleIntervalMs);
// Second samples + all independent reads run concurrently.
var cpuSample2Task = ReadRawCpuStatsAsync();
var netSample2Task = ReadRawNetStatsAsync();
var memTask = ReadMemoryAsync();
var diskTask = ReadDisksAsync();
var uptimeTask = ReadUptimeAsync();
var cpuNameTask = ReadCpuModelNameAsync();
await Task.WhenAll(cpuSample2Task, netSample2Task, memTask, diskTask, uptimeTask, cpuNameTask);
var cpu = ComputeCpuUsage(cpuNameTask.Result, cpuSample1Task.Result, cpuSample2Task.Result);
var network = ComputeNetworkRates(netSample1Task.Result, netSample2Task.Result, sampleIntervalMs / 1000.0);
return new SystemSnapshot(cpu, memTask.Result, diskTask.Result, network, uptimeTask.Result);
}
// Uptime
private static async Task<TimeSpan> ReadUptimeAsync()
{
var text = await File.ReadAllTextAsync("/proc/uptime");
var seconds = double.Parse(text.Split(' ')[0], System.Globalization.CultureInfo.InvariantCulture);
return TimeSpan.FromSeconds(seconds);
}
}