Namespaces, assemblies, projects and directories, the solution, binaries, images, systemd units, config paths, environment variables, protocol method names, the media type and the raw chunk magic all move to MoShiro/moshiro. Existing data and deployments are not compatible and must be recreated. Also fix the architecture tests after the solution layout change and make the update tests independent of their order.
75 lines
3.7 KiB
C#
75 lines
3.7 KiB
C#
namespace MoShiro.Backend.Analysis;
|
|
|
|
public sealed record PresetDef(string Id, string Label, IReadOnlyList<string> MetricIds);
|
|
|
|
/// <summary>
|
|
/// 指标注册表:存储、降采样、API、目录都由它驱动。新增指标时,在对应的 Metrics 文件里加一行声明,
|
|
/// 再把它放进这里的 <see cref="All"/>(显式注册,AOT 安全,不使用反射)。
|
|
/// </summary>
|
|
public static class MetricRegistry
|
|
{
|
|
public static readonly IReadOnlyList<MetricDef> All =
|
|
[
|
|
LinkMetrics.Rtt, LinkMetrics.LossUp, LinkMetrics.LossDown, LinkMetrics.LossTotal,
|
|
LinkMetrics.JitterUp, LinkMetrics.JitterDown, LinkMetrics.LossRun, LinkMetrics.Reorder, LinkMetrics.Dup, LinkMetrics.SamplesUdp,
|
|
TcpMetrics.Rtt, TcpMetrics.Slow, TcpMetrics.Stall, TcpMetrics.StallMax, TcpMetrics.Retrans, TcpMetrics.Srtt, TcpMetrics.BulkRate, TcpMetrics.BulkPeak, TcpMetrics.SamplesTcp,
|
|
SessionMetrics.ConnectSuccess, SessionMetrics.ConnectTcp, SessionMetrics.ConnectTls,
|
|
SessionMetrics.FailTimeout, SessionMetrics.FailReset, SessionMetrics.FailTls,
|
|
SessionMetrics.HoldResets, SessionMetrics.HoldLifetime,
|
|
SessionMetrics.TrainLoss, SessionMetrics.TrainJitter, SessionMetrics.TrainRate, SessionMetrics.SamplesConnect,
|
|
];
|
|
|
|
/// <summary>指标分组:前端按分组展示,新增指标只需要把它加进分组。</summary>
|
|
public static readonly IReadOnlyList<PresetDef> Presets =
|
|
[
|
|
new("udp", "UDP", ["loss.up", "loss.down", "loss.total", "rtt.p50", "rtt.p95", "rtt.p99", "jitter.up.p95", "jitter.down.p95", "loss.run_max", "reorder", "dup"]),
|
|
new("tcp", "TCP", ["tcp.rtt.p50", "tcp.rtt.p95", "tcp.rtt.p99", "tcp.rtt.p999", "tcp.rtt.max", "tcp.rtt.tail", "tcp.slow", "tcp.stall.per_min", "tcp.stall_max", "tcp.retrans", "tcp.srtt.p95"]),
|
|
new("connect", "Connect", ["connect.success", "connect.tcp_ms.p95", "connect.tls_ms.p95", "connect.fail.timeout", "connect.fail.rst", "connect.fail.tls"]),
|
|
new("session", "Session", ["hold.resets.per_h", "hold.lifetime_max"]),
|
|
new("scores", "Scores", ["score.base", "score.mc", "score.hy2", "score.reality"]),
|
|
];
|
|
|
|
private static readonly Dictionary<string, MetricDef> s_byId = All.ToDictionary(m => m.Id, StringComparer.Ordinal);
|
|
|
|
private static readonly Dictionary<string, (MetricDef Def, MetricExport Export)> s_byExport = BuildExportIndex();
|
|
|
|
public static MetricDef? Find(string metricId) => s_byId.GetValueOrDefault(metricId);
|
|
|
|
/// <summary>按导出 id(例如 <c>rtt.p95</c>)查找。</summary>
|
|
public static bool TryFindExport(string exportId, out MetricDef def, out MetricExport export)
|
|
{
|
|
if (s_byExport.TryGetValue(exportId, out (MetricDef Def, MetricExport Export) found))
|
|
{
|
|
def = found.Def;
|
|
export = found.Export;
|
|
return true;
|
|
}
|
|
|
|
def = null!;
|
|
export = null!;
|
|
return false;
|
|
}
|
|
|
|
public static PresetDef? FindPreset(string id) => Presets.FirstOrDefault(p => p.Id == id);
|
|
|
|
public static IEnumerable<(MetricDef Def, MetricExport Export)> AllExports() =>
|
|
All.SelectMany(def => def.Exports.Select(export => (def, export)));
|
|
|
|
private static Dictionary<string, (MetricDef, MetricExport)> BuildExportIndex()
|
|
{
|
|
var index = new Dictionary<string, (MetricDef, MetricExport)>(StringComparer.Ordinal);
|
|
foreach (MetricDef def in All)
|
|
{
|
|
foreach (MetricExport export in def.Exports)
|
|
{
|
|
if (!index.TryAdd(export.Id, (def, export)))
|
|
{
|
|
throw new InvalidOperationException($"duplicate export id {export.Id}");
|
|
}
|
|
}
|
|
}
|
|
|
|
return index;
|
|
}
|
|
}
|