namespace MoonlightServers.Daemon.Helpers;
public partial class SystemMetrics
{
/// Network throughput for a single interface, computed between two samples.
/// Interface name, e.g. eth0, ens3.
/// Received bytes per second.
/// Transmitted bytes per second.
/// Received packets per second.
/// Transmitted packets per second.
/// Cumulative receive error count (not a rate).
/// Cumulative transmit error count (not a rate).
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> ReadRawNetStatsAsync()
{
var lines = await File.ReadAllLinesAsync("/proc/net/dev");
var result = new List();
// 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 ComputeNetworkRates(
List s1,
List s2,
double intervalSecs
)
{
var prev = s1.ToDictionary(x => x.Iface);
var result = new List();
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;
}
}