101 lines
3.5 KiB
C#
101 lines
3.5 KiB
C#
namespace MoonlightServers.Daemon.Helpers;
|
|
|
|
public partial class SystemMetrics
|
|
{
|
|
/// <summary>Network throughput for a single interface, computed between two samples.</summary>
|
|
/// <param name="Name">Interface name, e.g. <c>eth0</c>, <c>ens3</c>.</param>
|
|
/// <param name="RxBytesPerSec">Received bytes per second.</param>
|
|
/// <param name="TxBytesPerSec">Transmitted bytes per second.</param>
|
|
/// <param name="RxPacketsPerSec">Received packets per second.</param>
|
|
/// <param name="TxPacketsPerSec">Transmitted packets per second.</param>
|
|
/// <param name="RxErrors">Cumulative receive error count (not a rate).</param>
|
|
/// <param name="TxErrors">Cumulative transmit error count (not a rate).</param>
|
|
public record NetworkInterfaceInfo(
|
|
string Name,
|
|
long RxBytesPerSec,
|
|
long TxBytesPerSec,
|
|
long RxPacketsPerSec,
|
|
long TxPacketsPerSec,
|
|
long RxErrors,
|
|
long TxErrors
|
|
);
|
|
|
|
// Network
|
|
private record RawNetLine(
|
|
string Iface,
|
|
long RxBytes,
|
|
long RxPackets,
|
|
long RxErrors,
|
|
long TxBytes,
|
|
long TxPackets,
|
|
long TxErrors
|
|
);
|
|
|
|
private static async Task<List<RawNetLine>> ReadRawNetStatsAsync()
|
|
{
|
|
var lines = await File.ReadAllLinesAsync("/proc/net/dev");
|
|
var result = new List<RawNetLine>();
|
|
|
|
// The first two lines are the column-header banner.
|
|
foreach (var line in lines.Skip(2))
|
|
{
|
|
var colon = line.IndexOf(':');
|
|
if (colon < 0)
|
|
continue;
|
|
|
|
var iface = line[..colon].Trim();
|
|
|
|
// Skip loopback and ephemeral veth pairs created by container runtimes.
|
|
if (iface == "lo" || iface.StartsWith("veth", StringComparison.Ordinal))
|
|
continue;
|
|
|
|
var f = line[(colon + 1)..].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
|
if (f.Length < 16)
|
|
continue;
|
|
|
|
// Column layout (after the colon, 0-based):
|
|
// RX: [0]bytes [1]packets [2]errs [3]drop [4]fifo [5]frame [6]compressed [7]multicast
|
|
// TX: [8]bytes [9]packets [10]errs [11]drop [12]fifo [13]colls [14]carrier [15]compressed
|
|
result.Add(new RawNetLine(
|
|
Iface: iface,
|
|
RxBytes: long.Parse(f[0]),
|
|
RxPackets: long.Parse(f[1]),
|
|
RxErrors: long.Parse(f[2]),
|
|
TxBytes: long.Parse(f[8]),
|
|
TxPackets: long.Parse(f[9]),
|
|
TxErrors: long.Parse(f[10])
|
|
));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static IReadOnlyList<NetworkInterfaceInfo> ComputeNetworkRates(
|
|
List<RawNetLine> s1,
|
|
List<RawNetLine> s2,
|
|
double intervalSecs
|
|
)
|
|
{
|
|
var prev = s1.ToDictionary(x => x.Iface);
|
|
var result = new List<NetworkInterfaceInfo>();
|
|
var div = intervalSecs > 0 ? intervalSecs : 1.0;
|
|
|
|
foreach (var cur in s2)
|
|
{
|
|
if (!prev.TryGetValue(cur.Iface, out var p))
|
|
continue;
|
|
|
|
result.Add(new NetworkInterfaceInfo(
|
|
Name: cur.Iface,
|
|
RxBytesPerSec: (long)((cur.RxBytes - p.RxBytes) / div),
|
|
TxBytesPerSec: (long)((cur.TxBytes - p.TxBytes) / div),
|
|
RxPacketsPerSec: (long)((cur.RxPackets - p.RxPackets) / div),
|
|
TxPacketsPerSec: (long)((cur.TxPackets - p.TxPackets) / div),
|
|
RxErrors: cur.RxErrors,
|
|
TxErrors: cur.TxErrors
|
|
));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} |