From 8f3a33a8915e87cf6b19f25a5a55a3a637c9b73b Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Fri, 2 Oct 2026 08:17:04 +0000 Subject: [PATCH] Serve the delivery duration histogram from boot (closes #267) webhooker_delivery_duration_seconds was absent from /metrics until the first delivery, while every other delivery series is materialised at zero when the collectors are registered. initSeries now materialises the histogram too, for the same four target types, so a scrape of an instance that has delivered nothing shows it with a zero count and sum. The registration test lists it with the other series, and a new route test scrapes /metrics on a freshly built instance and finds it for every target type. Model: opus-5-5 --- internal/metrics/metrics.go | 1 + internal/metrics/metrics_test.go | 1 + internal/server/routes_test.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 1d8f8f3..3658d9c 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -384,6 +384,7 @@ func (s *Set) initSeries() { s.deliveriesFailed.WithLabelValues(label) s.deliveryRetries.WithLabelValues(label) s.deliveryReplays.WithLabelValues(label) + s.deliveryDuration.WithLabelValues(label) s.deliveriesPending.WithLabelValues(label) s.deliveriesRetrying.WithLabelValues(label) s.circuitBreakersOpen.WithLabelValues(label) diff --git a/internal/metrics/metrics_test.go b/internal/metrics/metrics_test.go index a8b3a64..d89ea73 100644 --- a/internal/metrics/metrics_test.go +++ b/internal/metrics/metrics_test.go @@ -167,6 +167,7 @@ func TestKnownSeriesExistBeforeAnyDelivery(t *testing.T) { "webhooker_deliveries_succeeded_total", "webhooker_deliveries_failed_total", "webhooker_delivery_retries_total", + "webhooker_delivery_duration_seconds", "webhooker_circuit_breakers_open", } { assert.ElementsMatch(t, diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go index e9766a7..3c60a16 100644 --- a/internal/server/routes_test.go +++ b/internal/server/routes_test.go @@ -1524,3 +1524,31 @@ func TestTwoMetricsRoutersInOneProcess(t *testing.T) { } } } + +// TestMetricsScrapeBeforeAnyDelivery pins +// https://git.eeqj.de/sneak/webhooker/issues/267: an instance that +// has delivered nothing must still serve the delivery duration +// histogram, at zero, for every target type. +func TestMetricsScrapeBeforeAnyDelivery(t *testing.T) { + t.Parallel() + + env := newTestEnvWithConfig( + t, metricsConfig(t, metricsUser, metricsAuthValue), + ) + + scrape := env.metricsRequest(metricsUser, metricsAuthValue) + require.Equal(t, http.StatusOK, scrape.Code) + + for _, targetType := range []database.TargetType{ + database.TargetTypeHTTP, + database.TargetTypeDatabase, + database.TargetTypeLog, + database.TargetTypeSlack, + } { + assert.Contains( + t, scrape.Body.String(), + `webhooker_delivery_duration_seconds_count{target_type="`+ + string(targetType)+`"} 0`, + ) + } +}