From 9283770f68f570f47ca20aa9c6f9de8cc50063ba Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Tue, 4 Feb 2025 10:55:30 +0300 Subject: [PATCH] reverseproxy: ignore duplicate collector registration error (#6820) Signed-off-by: Mohammed Al Sahaf --- modules/caddyhttp/reverseproxy/metrics.go | 36 +++++++++++++++-------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/metrics.go b/modules/caddyhttp/reverseproxy/metrics.go index 8a7105c1193..2488427304e 100644 --- a/modules/caddyhttp/reverseproxy/metrics.go +++ b/modules/caddyhttp/reverseproxy/metrics.go @@ -1,11 +1,12 @@ package reverseproxy import ( + "errors" "runtime/debug" + "sync" "time" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -13,6 +14,7 @@ import ( ) var reverseProxyMetrics = struct { + once sync.Once upstreamsHealthy *prometheus.GaugeVec logger *zap.Logger }{} @@ -21,12 +23,25 @@ func initReverseProxyMetrics(handler *Handler, registry *prometheus.Registry) { const ns, sub = "caddy", "reverse_proxy" upstreamsLabels := []string{"upstream"} - reverseProxyMetrics.upstreamsHealthy = promauto.With(registry).NewGaugeVec(prometheus.GaugeOpts{ - Namespace: ns, - Subsystem: sub, - Name: "upstreams_healthy", - Help: "Health status of reverse proxy upstreams.", - }, upstreamsLabels) + reverseProxyMetrics.once.Do(func() { + reverseProxyMetrics.upstreamsHealthy = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, + Subsystem: sub, + Name: "upstreams_healthy", + Help: "Health status of reverse proxy upstreams.", + }, upstreamsLabels) + }) + + // duplicate registration could happen if multiple sites with reverse proxy are configured; so ignore the error because + // there's no good way to capture having multiple sites with reverse proxy. If this happens, the metrics will be + // registered twice, but the second registration will be ignored. + if err := registry.Register(reverseProxyMetrics.upstreamsHealthy); err != nil && + !errors.Is(err, prometheus.AlreadyRegisteredError{ + ExistingCollector: reverseProxyMetrics.upstreamsHealthy, + NewCollector: reverseProxyMetrics.upstreamsHealthy, + }) { + panic(err) + } reverseProxyMetrics.logger = handler.logger.Named("reverse_proxy.metrics") } @@ -35,13 +50,8 @@ type metricsUpstreamsHealthyUpdater struct { handler *Handler } -const upstreamsHealthyMetrics caddy.CtxKey = "reverse_proxy_upstreams_healthy" - func newMetricsUpstreamsHealthyUpdater(handler *Handler, ctx caddy.Context) *metricsUpstreamsHealthyUpdater { - if set := ctx.Value(upstreamsHealthyMetrics); set == nil { - initReverseProxyMetrics(handler, ctx.GetMetricsRegistry()) - ctx = ctx.WithValue(upstreamsHealthyMetrics, true) - } + initReverseProxyMetrics(handler, ctx.GetMetricsRegistry()) reverseProxyMetrics.upstreamsHealthy.Reset() return &metricsUpstreamsHealthyUpdater{handler}