From 0143d472469c8dfe44f23f1440123e27d415baae Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sun, 16 Aug 2026 20:05:43 +0000 Subject: [PATCH] metrics: extract boolGauge to simplify RecordInventory Resolves the SonarQube go:S3776 cognitive-complexity finding on RecordInventory by replacing the pvc.Healthy if/else with a boolGauge helper. Adds tests locking the pvc_backup_health gauge to exactly 1 for healthy and 0 for unhealthy with unchanged metric identity and labels. Closes #9 Co-Authored-By: Claude Fable 5 --- internal/server/metrics.go | 15 ++++++---- internal/server/metrics_test.go | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/internal/server/metrics.go b/internal/server/metrics.go index 5893b8e..0b25506 100644 --- a/internal/server/metrics.go +++ b/internal/server/metrics.go @@ -162,11 +162,7 @@ func (t *telemetry) RecordInventory(inv api.InventoryResponse) { } reasonLabels["reason"] = reason setMetric(t.pvcBackupHealthReason, reasonLabels, 1) - if pvc.Healthy { - setMetric(t.pvcBackupHealth, labels, 1) - } else { - setMetric(t.pvcBackupHealth, labels, 0) - } + setMetric(t.pvcBackupHealth, labels, boolGauge(pvc.Healthy)) if pvc.LastBackupAt == "" { continue } @@ -325,6 +321,15 @@ func incMetric(target map[string]metricSample, labels map[string]string) { target[key] = sample } +// boolGauge converts a boolean state into the Prometheus gauge convention of +// 1 for true and 0 for false. +func boolGauge(value bool) float64 { + if value { + return 1 + } + return 0 +} + func setMetric(target map[string]metricSample, labels map[string]string, value float64) { key := metricKey(labels) target[key] = metricSample{labels: cloneLabels(labels), value: value} diff --git a/internal/server/metrics_test.go b/internal/server/metrics_test.go index ab6f924..8431ce8 100644 --- a/internal/server/metrics_test.go +++ b/internal/server/metrics_test.go @@ -1,6 +1,7 @@ package server import ( + "strings" "testing" "time" @@ -160,6 +161,55 @@ func TestTelemetryRecordInventoryPopulatesAndResetsMetrics(t *testing.T) { } } +func TestBoolGaugeMapsHealthToPrometheusValues(t *testing.T) { + if got := boolGauge(true); got != 1 { + t.Fatalf("expected boolGauge(true) to be 1, got %v", got) + } + if got := boolGauge(false); got != 0 { + t.Fatalf("expected boolGauge(false) to be 0, got %v", got) + } +} + +func TestTelemetryRecordInventoryHealthGaugeIdentity(t *testing.T) { + telemetry := newTelemetry() + + telemetry.RecordInventory(api.InventoryResponse{ + Namespaces: []api.NamespaceInventory{ + { + Name: "apps", + PVCs: []api.PVCInventory{ + { + Namespace: "apps", + PVC: "data", + Volume: "pv-apps-data", + Driver: "restic", + Healthy: true, + }, + { + Namespace: "apps", + PVC: "cache", + Volume: "pv-apps-cache", + Driver: "longhorn", + Healthy: false, + HealthReason: "stale", + }, + }, + }, + }, + }) + + rendered := telemetry.render() + for _, line := range []string{ + "# TYPE pvc_backup_health gauge", + `pvc_backup_health{driver="restic",namespace="apps",pvc="data",volume="pv-apps-data"} 1`, + `pvc_backup_health{driver="longhorn",namespace="apps",pvc="cache",volume="pv-apps-cache"} 0`, + } { + if !strings.Contains(rendered, line+"\n") { + t.Fatalf("expected rendered metrics to contain %q, got:\n%s", line, rendered) + } + } +} + func TestTelemetryRecordB2UsageTracksBucketsAndFallbackTimestamp(t *testing.T) { telemetry := newTelemetry() scannedAt := time.Date(2026, 4, 20, 16, 30, 0, 0, time.UTC)