Skip to content

Commit 87309aa

Browse files
committed
just swallow the duplicate registration error
Signed-off-by: Mohammed Al Sahaf <[email protected]>
1 parent e6eba2b commit 87309aa

File tree

4 files changed

+35
-28
lines changed

4 files changed

+35
-28
lines changed

context.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"log"
2222
"log/slog"
2323
"reflect"
24-
"sync"
2524

2625
"github.com/caddyserver/certmagic"
2726
"github.com/prometheus/client_golang/prometheus"
@@ -63,7 +62,7 @@ type Context struct {
6362
// See standard library context package's documentation.
6463
func NewContext(ctx Context) (Context, context.CancelFunc) {
6564
r := prometheus.NewPedanticRegistry()
66-
newCtx := Context{moduleInstances: make(map[string][]Module), cfg: ctx.cfg, metricsRegistry: &registryGatherer{registry: r, gatherer: r, tracker: make(map[string]*sync.Once)}}
65+
newCtx := Context{moduleInstances: make(map[string][]Module), cfg: ctx.cfg, metricsRegistry: &registryGatherer{registry: r, gatherer: r}}
6766
c, cancel := context.WithCancel(ctx.Context)
6867
wrappedCancel := func() {
6968
cancel()
@@ -105,10 +104,7 @@ func (ctx *Context) FileSystems() FileSystems {
105104

106105
// Returns the active metrics registry for the context
107106
// EXPERIMENTAL: This API is subject to change.
108-
func (ctx *Context) GetMetricsRegistry() RegistererGatherer {
109-
if ctx.Module() != nil {
110-
ctx.metricsRegistry.callerModule = ctx.Module().CaddyModule().String()
111-
}
107+
func (ctx *Context) GetMetricsRegistry() MetricsRegistererGatherer {
112108
return ctx.metricsRegistry
113109
}
114110

metrics.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package caddy
22

33
import (
4+
"errors"
45
"net/http"
5-
"sync"
66

77
"github.com/prometheus/client_golang/prometheus"
88
io_prometheus_client "github.com/prometheus/client_model/go"
@@ -85,48 +85,59 @@ func (d *delegator) Unwrap() http.ResponseWriter {
8585
return d.ResponseWriter
8686
}
8787

88-
type RegistererGatherer interface {
88+
type MetricsRegistererGatherer interface {
8989
prometheus.Registerer
9090
prometheus.Gatherer
9191
}
9292
type registryGatherer struct {
9393
registry prometheus.Registerer
9494
gatherer prometheus.Gatherer
95-
tracker map[string]*sync.Once
96-
97-
callerModule string
9895
}
9996

10097
// Gather implements prometheus.Gatherer.
10198
func (r *registryGatherer) Gather() ([]*io_prometheus_client.MetricFamily, error) {
10299
return r.gatherer.Gather()
103100
}
104101

105-
// MustRegister implements prometheus.Registerer.
102+
// MustRegister calls `MustRegister` on the backing registry one collector
103+
// at a time to capture the module at which the call may have panicked. Panics
104+
// of duplicate registration are ignored.
106105
func (r *registryGatherer) MustRegister(cs ...prometheus.Collector) {
107-
if _, ok := r.tracker[r.callerModule]; !ok {
108-
r.tracker[r.callerModule] = &sync.Once{}
106+
var current prometheus.Collector
107+
defer func() {
108+
if r := recover(); r != nil {
109+
err, ok := r.(error)
110+
if !ok {
111+
panic(r)
112+
}
113+
if !errors.Is(err, prometheus.AlreadyRegisteredError{
114+
ExistingCollector: current,
115+
NewCollector: current,
116+
}) {
117+
panic(err)
118+
}
119+
}
120+
}()
121+
for _, current = range cs {
122+
r.registry.MustRegister(current)
109123
}
110-
r.tracker[r.callerModule].Do(func() {
111-
r.registry.MustRegister(cs...)
112-
})
113124
}
114125

115-
// Register implements prometheus.Registerer.
126+
// Register implements prometheus.Registerer. Errors of duplicate registration
127+
// are ignored.
116128
func (r *registryGatherer) Register(c prometheus.Collector) error {
117-
var err error
118-
if _, ok := r.tracker[r.callerModule]; !ok {
119-
r.tracker[r.callerModule] = &sync.Once{}
129+
if err := r.registry.Register(c); err != nil &&
130+
!errors.Is(err, prometheus.AlreadyRegisteredError{
131+
ExistingCollector: c,
132+
NewCollector: c,
133+
}) {
134+
return err
120135
}
121-
r.tracker[r.callerModule].Do(func() {
122-
err = r.registry.Register(c)
123-
})
124-
return err
136+
return nil
125137
}
126138

127139
// Unregister implements prometheus.Registerer.
128140
func (r *registryGatherer) Unregister(c prometheus.Collector) bool {
129-
delete(r.tracker, r.callerModule)
130141
return r.registry.Unregister(c)
131142
}
132143

modules/metrics/adminmetrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func init() {
3131
// See the Metrics module for a configurable endpoint that is usable if the
3232
// Admin API is disabled.
3333
type AdminMetrics struct {
34-
registry caddy.RegistererGatherer
34+
registry caddy.MetricsRegistererGatherer
3535

3636
metricsHandler http.Handler
3737
}

modules/metrics/metrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ var (
107107
_ caddyfile.Unmarshaler = (*Metrics)(nil)
108108
)
109109

110-
func createMetricsHandler(logger promhttp.Logger, enableOpenMetrics bool, registry caddy.RegistererGatherer) http.Handler {
110+
func createMetricsHandler(logger promhttp.Logger, enableOpenMetrics bool, registry caddy.MetricsRegistererGatherer) http.Handler {
111111
return promhttp.InstrumentMetricHandler(registry,
112112
promhttp.HandlerFor(registry, promhttp.HandlerOpts{
113113
// will only log errors if logger is non-nil

0 commit comments

Comments
 (0)