| | | 1 | | using System.Diagnostics.Metrics; |
| | | 2 | | |
| | | 3 | | namespace ProjectTemplate.Infrastructure.Data.Auditing; |
| | | 4 | | |
| | | 5 | | public sealed class ApplicationAuditReconciliationMetrics : IDisposable |
| | | 6 | | { |
| | 2 | 7 | | public static readonly ApplicationAuditReconciliationSummary DisabledSummary = |
| | 2 | 8 | | new(false, null, 0, 0, 0, 0, 0, 0, 0); |
| | | 9 | | |
| | 16 | 10 | | private readonly Meter _meter = new("ProjectTemplate.AuditReconciliation", "1.0.0"); |
| | 16 | 11 | | private ApplicationAuditReconciliationSummary _summary = DisabledSummary; |
| | | 12 | | private long _pendingDeliveryCount; |
| | | 13 | | private double _oldestPendingAgeSeconds; |
| | | 14 | | private long _totalRetryCount; |
| | | 15 | | |
| | 16 | 16 | | public ApplicationAuditReconciliationMetrics() |
| | | 17 | | { |
| | 16 | 18 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.findings.open", |
| | 16 | 19 | | () => _summary.OpenFindingCount); |
| | 16 | 20 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.findings.error", |
| | 16 | 21 | | () => _summary.ErrorFindingCount); |
| | 16 | 22 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.findings.critical", |
| | 16 | 23 | | () => _summary.CriticalFindingCount); |
| | 16 | 24 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.manifest_failures", |
| | 16 | 25 | | () => _summary.ManifestVerificationFailureCount); |
| | 16 | 26 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.missing_completions", |
| | 16 | 27 | | () => _summary.MissingCompletionCount); |
| | 16 | 28 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.stale_delivery", |
| | 16 | 29 | | () => _summary.StaleDeliveryCount); |
| | 16 | 30 | | _meter.CreateObservableGauge("ncat.audit.reconciliation.dead_letters", |
| | 16 | 31 | | () => _summary.DeadLetterCount); |
| | 16 | 32 | | _meter.CreateObservableGauge("ncat.audit.outbox.pending", |
| | 16 | 33 | | () => Interlocked.Read(ref _pendingDeliveryCount)); |
| | 16 | 34 | | _meter.CreateObservableGauge("ncat.audit.outbox.oldest_pending_age_seconds", |
| | 16 | 35 | | () => Volatile.Read(ref _oldestPendingAgeSeconds)); |
| | 16 | 36 | | _meter.CreateObservableGauge("ncat.audit.outbox.retry_count", |
| | 16 | 37 | | () => Interlocked.Read(ref _totalRetryCount)); |
| | 16 | 38 | | } |
| | | 39 | | |
| | 0 | 40 | | public DateTime? LastRunUtc => _summary.LastRunUtc; |
| | | 41 | | |
| | | 42 | | public void Update(ApplicationAuditReconciliationSummary summary) |
| | | 43 | | { |
| | 16 | 44 | | ArgumentNullException.ThrowIfNull(summary); |
| | 16 | 45 | | _summary = summary; |
| | 16 | 46 | | } |
| | | 47 | | |
| | | 48 | | public void UpdateDelivery(ApplicationAuditCompletionOutboxHealth health) |
| | | 49 | | { |
| | 0 | 50 | | ArgumentNullException.ThrowIfNull(health); |
| | 0 | 51 | | Interlocked.Exchange(ref _pendingDeliveryCount, health.BacklogCount); |
| | 0 | 52 | | Volatile.Write(ref _oldestPendingAgeSeconds, health.OldestPendingAge?.TotalSeconds ?? 0); |
| | 0 | 53 | | Interlocked.Exchange(ref _totalRetryCount, health.TotalRetryCount); |
| | 0 | 54 | | } |
| | | 55 | | |
| | | 56 | | public void Dispose() |
| | | 57 | | { |
| | 16 | 58 | | _meter.Dispose(); |
| | 16 | 59 | | } |
| | | 60 | | } |