using System.Diagnostics; using System.Diagnostics.Metrics; using StellaOps.Policy.Determinization.Models; namespace StellaOps.Policy.Engine.Gates.Determinization; /// /// OpenTelemetry metrics for determinization gate and observation state tracking. /// public sealed class DeterminizationGateMetrics : IDisposable { private readonly Meter _meter; private readonly Counter _evaluationsTotal; private readonly Counter _ruleMatchesTotal; private readonly Counter _stateTransitionsTotal; private readonly Histogram _entropyDistribution; private readonly Histogram _trustScoreDistribution; private readonly Histogram _evaluationDurationMs; public const string MeterName = "StellaOps.Policy.Engine.DeterminizationGate"; public DeterminizationGateMetrics() { _meter = new Meter(MeterName, "1.0.0"); _evaluationsTotal = _meter.CreateCounter( "stellaops_policy_determinization_evaluations_total", unit: "{evaluations}", description: "Total number of determinization gate evaluations"); _ruleMatchesTotal = _meter.CreateCounter( "stellaops_policy_determinization_rule_matches_total", unit: "{matches}", description: "Total number of determinization rule matches by rule name"); _stateTransitionsTotal = _meter.CreateCounter( "stellaops_policy_observation_state_transitions_total", unit: "{transitions}", description: "Total number of observation state transitions"); _entropyDistribution = _meter.CreateHistogram( "stellaops_policy_determinization_entropy", unit: "1", description: "Distribution of entropy scores evaluated"); _trustScoreDistribution = _meter.CreateHistogram( "stellaops_policy_determinization_trust_score", unit: "1", description: "Distribution of trust scores evaluated"); _evaluationDurationMs = _meter.CreateHistogram( "stellaops_policy_determinization_evaluation_duration_ms", unit: "ms", description: "Duration of determinization gate evaluations"); } /// /// Record a gate evaluation. /// public void RecordEvaluation( PolicyVerdictStatus status, string environment, string? matchedRule) { _evaluationsTotal.Add(1, new KeyValuePair("status", status.ToString().ToLowerInvariant()), new KeyValuePair("environment", environment), new KeyValuePair("rule", matchedRule ?? "none")); } /// /// Record a rule match. /// public void RecordRuleMatch( string ruleName, PolicyVerdictStatus status, string environment) { _ruleMatchesTotal.Add(1, new KeyValuePair("rule", ruleName), new KeyValuePair("status", status.ToString().ToLowerInvariant()), new KeyValuePair("environment", environment)); } /// /// Record an observation state transition. /// public void RecordStateTransition( ObservationState fromState, ObservationState toState, string trigger, string environment) { _stateTransitionsTotal.Add(1, new KeyValuePair("from_state", fromState.ToString().ToLowerInvariant()), new KeyValuePair("to_state", toState.ToString().ToLowerInvariant()), new KeyValuePair("trigger", trigger), new KeyValuePair("environment", environment)); } /// /// Record entropy value from evaluation. /// public void RecordEntropy(double entropy, string environment) { _entropyDistribution.Record( entropy, new KeyValuePair("environment", environment)); } /// /// Record trust score from evaluation. /// public void RecordTrustScore(double trustScore, string environment) { _trustScoreDistribution.Record( trustScore, new KeyValuePair("environment", environment)); } /// /// Record evaluation duration. /// public void RecordDuration(TimeSpan duration, string environment) { _evaluationDurationMs.Record( duration.TotalMilliseconds, new KeyValuePair("environment", environment)); } /// /// Create a timer scope for measuring evaluation duration. /// public IDisposable StartEvaluationTimer(string environment) { return new DurationScope(this, environment); } public void Dispose() { _meter.Dispose(); } private sealed class DurationScope : IDisposable { private readonly DeterminizationGateMetrics _metrics; private readonly string _environment; private readonly Stopwatch _stopwatch; public DurationScope(DeterminizationGateMetrics metrics, string environment) { _metrics = metrics; _environment = environment; _stopwatch = Stopwatch.StartNew(); } public void Dispose() { _stopwatch.Stop(); _metrics.RecordDuration(_stopwatch.Elapsed, _environment); } } }