using System; using System.Collections.Generic; using System.Diagnostics.Metrics; namespace StellaOps.Concelier.Models; /// /// Emits telemetry for OSV vs GHSA parity reports so QA dashboards can track regression trends. /// public static class OsvGhsaParityDiagnostics { private static readonly Meter Meter = new("StellaOps.Concelier.Models.OsvGhsaParity"); private static readonly Counter TotalCounter = Meter.CreateCounter( "concelier.osv_ghsa.total", unit: "count", description: "Total GHSA identifiers evaluated for OSV parity."); private static readonly Counter IssueCounter = Meter.CreateCounter( "concelier.osv_ghsa.issues", unit: "count", description: "Parity issues grouped by dataset, issue kind, and field mask."); public static void RecordReport(OsvGhsaParityReport report, string dataset) { ArgumentNullException.ThrowIfNull(report); dataset = NormalizeDataset(dataset); if (report.TotalGhsaIds > 0) { TotalCounter.Add(report.TotalGhsaIds, CreateTotalTags(dataset)); } if (!report.HasIssues) { return; } foreach (var issue in report.Issues) { IssueCounter.Add(1, CreateIssueTags(dataset, issue)); } } private static KeyValuePair[] CreateTotalTags(string dataset) => new[] { new KeyValuePair("dataset", dataset), }; private static KeyValuePair[] CreateIssueTags(string dataset, OsvGhsaParityIssue issue) { var mask = issue.FieldMask.IsDefaultOrEmpty ? "none" : string.Join('|', issue.FieldMask); return new[] { new KeyValuePair("dataset", dataset), new KeyValuePair("issueKind", issue.IssueKind), new KeyValuePair("fieldMask", mask), }; } private static string NormalizeDataset(string dataset) { if (string.IsNullOrWhiteSpace(dataset)) { return "default"; } return dataset.Trim().ToLowerInvariant(); } }