diff --git a/prometheus/promhttp/http.go b/prometheus/promhttp/http.go index 52de01f..d5070f3 100644 --- a/prometheus/promhttp/http.go +++ b/prometheus/promhttp/http.go @@ -135,8 +135,8 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO panic(err) } } - hasEscapedCollisions = opts.Registry.HasEscapedCollision() } + hasEscapedCollisions = reg.HasEscapedCollision() // Select compression formats to offer based on default or user choice. var compressions []string diff --git a/prometheus/promhttp/http_test.go b/prometheus/promhttp/http_test.go index c5a2cc5..358bea6 100644 --- a/prometheus/promhttp/http_test.go +++ b/prometheus/promhttp/http_test.go @@ -81,6 +81,10 @@ func (g *mockTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(), return mfs, func() { g.doneInvoked++ }, err } +func (g *mockTransactionGatherer) HasEscapedCollision() bool { + return g.g.HasEscapedCollision() +} + func readCompressedBody(r io.Reader, comp Compression) (string, error) { switch comp { case Gzip: @@ -567,9 +571,7 @@ func TestEscapedCollisions(t *testing.T) { Help: "A test metric with dots", })) - handler := HandlerFor(reg, HandlerOpts{ - Registry: reg, - }) + handler := HandlerFor(reg, HandlerOpts{}) t.Run("fail case", func(t *testing.T) { writer := httptest.NewRecorder() diff --git a/prometheus/registry.go b/prometheus/registry.go index 9504360..a4a4d8c 100644 --- a/prometheus/registry.go +++ b/prometheus/registry.go @@ -137,11 +137,6 @@ type Registerer interface { // instance must only collect consistent metrics throughout its // lifetime. Unregister(Collector) bool - - // HasEscapedCollision returns true if any two of the registered metrics would - // be the same when escaped to underscores. This is needed to prevent - // duplicate metric issues when being scraped by a legacy system. - HasEscapedCollision() bool } // Gatherer is the interface for the part of a registry in charge of gathering @@ -169,6 +164,11 @@ type Gatherer interface { // expose an incomplete result and instead disregard the returned // MetricFamily protobufs in case the returned error is non-nil. Gather() ([]*dto.MetricFamily, error) + + // HasEscapedCollision returns true if any two of the registered metrics would + // be the same when escaped to underscores. This is needed to prevent + // duplicate metric issues when being scraped by a legacy system. + HasEscapedCollision() bool } // Register registers the provided Collector with the DefaultRegisterer. @@ -205,6 +205,10 @@ func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) { return gf() } +func (gf GathererFunc) HasEscapedCollision() bool { + return false +} + // AlreadyRegisteredError is returned by the Register method if the Collector to // be registered has already been registered before, or a different Collector // that collects the same metrics has been registered before. Registration fails @@ -872,6 +876,15 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() } +func (gs Gatherers) HasEscapedCollision() bool { + for _, g := range gs { + if g.HasEscapedCollision() { + return true + } + } + return false +} + // checkSuffixCollisions checks for collisions with the “magic” suffixes the // Prometheus text format and the internal metric representation of the // Prometheus server add while flattening Summaries and Histograms. @@ -1103,6 +1116,15 @@ func (r *MultiTRegistry) Gather() (mfs []*dto.MetricFamily, done func(), err err }, errs.MaybeUnwrap() } +func (r *MultiTRegistry) HasEscapedCollision() bool { + for _, g := range r.tGatherers { + if g.HasEscapedCollision() { + return true + } + } + return false +} + // TransactionalGatherer represents transactional gatherer that can be triggered to notify gatherer that memory // used by metric family is no longer used by a caller. This allows implementations with cache. type TransactionalGatherer interface { @@ -1128,6 +1150,11 @@ type TransactionalGatherer interface { // Important: done is expected to be triggered (even if the error occurs!) // once caller does not need returned slice of dto.MetricFamily. Gather() (_ []*dto.MetricFamily, done func(), err error) + + // HasEscapedCollision returns true if any two of the registered metrics would + // be the same when escaped to underscores. This is needed to prevent + // duplicate metric issues when being scraped by a legacy system. + HasEscapedCollision() bool } // ToTransactionalGatherer transforms Gatherer to transactional one with noop as done function. @@ -1144,3 +1171,7 @@ func (g *noTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(), er mfs, err := g.g.Gather() return mfs, func() {}, err } + +func (g *noTransactionGatherer) HasEscapedCollision() bool { + return g.g.HasEscapedCollision() +} diff --git a/prometheus/registry_test.go b/prometheus/registry_test.go index 38dc731..e0f5bd0 100644 --- a/prometheus/registry_test.go +++ b/prometheus/registry_test.go @@ -1364,6 +1364,10 @@ func (g *tGatherer) Gather() (_ []*dto.MetricFamily, done func(), err error) { }, func() { g.done = true }, g.err } +func (g *tGatherer) HasEscapedCollision() bool { + return false +} + func TestNewMultiTRegistry(t *testing.T) { treg := &tGatherer{} diff --git a/prometheus/wrap.go b/prometheus/wrap.go index a80caa8..25da157 100644 --- a/prometheus/wrap.go +++ b/prometheus/wrap.go @@ -117,10 +117,6 @@ func (r *wrappingRegisterer) Unregister(c Collector) bool { }) } -func (r *wrappingRegisterer) HasEscapedCollision() bool { - return r.wrappedRegisterer.HasEscapedCollision() -} - type wrappingCollector struct { wrappedCollector Collector prefix string