forked from mirror/client_golang
Add wrapping of Registerers with labels and prefix
Essentially middleware for Registerers! Signed-off-by: beorn7 <beorn@soundcloud.com>
This commit is contained in:
parent
7858729281
commit
84d7aa0cd9
|
@ -17,7 +17,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
|
@ -539,6 +539,11 @@ func processMetric(
|
||||||
registeredDescIDs map[uint64]struct{},
|
registeredDescIDs map[uint64]struct{},
|
||||||
) error {
|
) error {
|
||||||
desc := metric.Desc()
|
desc := metric.Desc()
|
||||||
|
// Wrapped metrics collected by an unchecked Collector can have an
|
||||||
|
// invalid Desc.
|
||||||
|
if desc.err != nil {
|
||||||
|
return desc.err
|
||||||
|
}
|
||||||
dtoMetric := &dto.Metric{}
|
dtoMetric := &dto.Metric{}
|
||||||
if err := metric.Write(dtoMetric); err != nil {
|
if err := metric.Write(dtoMetric); err != nil {
|
||||||
return fmt.Errorf("error collecting metric %v: %s", desc, err)
|
return fmt.Errorf("error collecting metric %v: %s", desc, err)
|
||||||
|
|
|
@ -17,9 +17,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValueType is an enumeration of metric types that represent a simple value.
|
// ValueType is an enumeration of metric types that represent a simple value.
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright 2018 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WrapWith returns a Registerer wrapping the provided Registerer. Collectors
|
||||||
|
// registered with the returned Registerer will be registered with the wrapped
|
||||||
|
// Registerer in a modified way. The modified Collector adds the provided Labels
|
||||||
|
// to all Metrics it collects (as ConstLabels). The Metrics collected by the
|
||||||
|
// unmodified Collector must not duplicate any of those labels.
|
||||||
|
//
|
||||||
|
// WrapWith provides a way to add fixed labels to a subset of Collectors. It
|
||||||
|
// should not be used to add fixed labels to all metrics exposed.
|
||||||
|
func WrapWith(labels Labels, reg Registerer) Registerer {
|
||||||
|
return &wrappingRegisterer{
|
||||||
|
wrappedRegisterer: reg,
|
||||||
|
labels: labels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapWithPrefix returns a Registerer wrapping the provided Registerer. Collectors
|
||||||
|
// registered with the returned Registerer will be registered with the wrapped
|
||||||
|
// Registerer in a modified way. The modified Collector adds the provided prefix
|
||||||
|
// to the name of all Metrics it collects.
|
||||||
|
//
|
||||||
|
// WrapWithPrefix is useful to have one place to prefix all metrics of a
|
||||||
|
// sub-system. To make this work, register metrics of the sub-system with the
|
||||||
|
// wrapping Registerer returned by WrapWithPrefix.
|
||||||
|
func WrapWithPrefix(prefix string, reg Registerer) Registerer {
|
||||||
|
return &wrappingRegisterer{
|
||||||
|
wrappedRegisterer: reg,
|
||||||
|
prefix: prefix,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappingRegisterer struct {
|
||||||
|
wrappedRegisterer Registerer
|
||||||
|
prefix string
|
||||||
|
labels Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *wrappingRegisterer) Register(c Collector) error {
|
||||||
|
return r.wrappedRegisterer.Register(&wrappingCollector{
|
||||||
|
wrappedCollector: c,
|
||||||
|
prefix: r.prefix,
|
||||||
|
labels: r.labels,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
|
||||||
|
for _, c := range cs {
|
||||||
|
if err := r.Register(c); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *wrappingRegisterer) Unregister(c Collector) bool {
|
||||||
|
return r.wrappedRegisterer.Unregister(&wrappingCollector{
|
||||||
|
wrappedCollector: c,
|
||||||
|
prefix: r.prefix,
|
||||||
|
labels: r.labels,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappingCollector struct {
|
||||||
|
wrappedCollector Collector
|
||||||
|
prefix string
|
||||||
|
labels Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *wrappingCollector) Collect(ch chan<- Metric) {
|
||||||
|
wrappedCh := make(chan Metric)
|
||||||
|
go func() {
|
||||||
|
c.wrappedCollector.Collect(wrappedCh)
|
||||||
|
close(wrappedCh)
|
||||||
|
}()
|
||||||
|
for m := range wrappedCh {
|
||||||
|
ch <- &wrappingMetric{
|
||||||
|
wrappedMetric: m,
|
||||||
|
prefix: c.prefix,
|
||||||
|
labels: c.labels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *wrappingCollector) Describe(ch chan<- *Desc) {
|
||||||
|
wrappedCh := make(chan *Desc)
|
||||||
|
go func() {
|
||||||
|
c.wrappedCollector.Describe(wrappedCh)
|
||||||
|
close(wrappedCh)
|
||||||
|
}()
|
||||||
|
for desc := range wrappedCh {
|
||||||
|
ch <- wrapDesc(desc, c.prefix, c.labels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappingMetric struct {
|
||||||
|
wrappedMetric Metric
|
||||||
|
prefix string
|
||||||
|
labels Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *wrappingMetric) Desc() *Desc {
|
||||||
|
return wrapDesc(m.wrappedMetric.Desc(), m.prefix, m.labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *wrappingMetric) Write(out *dto.Metric) error {
|
||||||
|
if err := m.wrappedMetric.Write(out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(m.labels) == 0 {
|
||||||
|
// No wrapping labels.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for ln, lv := range m.labels {
|
||||||
|
out.Label = append(out.Label, &dto.LabelPair{
|
||||||
|
Name: proto.String(ln),
|
||||||
|
Value: proto.String(lv),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sort.Sort(labelPairSorter(out.Label))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc {
|
||||||
|
constLabels := Labels{}
|
||||||
|
for _, lp := range desc.constLabelPairs {
|
||||||
|
constLabels[*lp.Name] = *lp.Value
|
||||||
|
}
|
||||||
|
for ln, lv := range labels {
|
||||||
|
if _, alreadyUsed := constLabels[ln]; alreadyUsed {
|
||||||
|
return &Desc{
|
||||||
|
fqName: desc.fqName,
|
||||||
|
help: desc.help,
|
||||||
|
variableLabels: desc.variableLabels,
|
||||||
|
constLabelPairs: desc.constLabelPairs,
|
||||||
|
err: fmt.Errorf("attempted wrapping with already existing label name %q", ln),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constLabels[ln] = lv
|
||||||
|
}
|
||||||
|
// NewDesc will do remaining validations.
|
||||||
|
newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels)
|
||||||
|
// Propagate errors if there was any. This will override any errer
|
||||||
|
// created by NewDesc above, i.e. earlier errors get precedence.
|
||||||
|
if desc.err != nil {
|
||||||
|
newDesc.err = desc.err
|
||||||
|
}
|
||||||
|
return newDesc
|
||||||
|
}
|
|
@ -0,0 +1,322 @@
|
||||||
|
// Copyright 2018 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// uncheckedCollector wraps a Collector but its Describe method yields no Desc.
|
||||||
|
type uncheckedCollector struct {
|
||||||
|
c Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u uncheckedCollector) Describe(_ chan<- *Desc) {}
|
||||||
|
func (u uncheckedCollector) Collect(c chan<- Metric) {
|
||||||
|
u.c.Collect(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toMetricFamilies(cs ...Collector) []*dto.MetricFamily {
|
||||||
|
reg := NewRegistry()
|
||||||
|
reg.MustRegister(cs...)
|
||||||
|
out, err := reg.Gather()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrap(t *testing.T) {
|
||||||
|
|
||||||
|
simpleCnt := NewCounter(CounterOpts{
|
||||||
|
Name: "simpleCnt",
|
||||||
|
Help: "helpSimpleCnt",
|
||||||
|
})
|
||||||
|
simpleCnt.Inc()
|
||||||
|
|
||||||
|
simpleGge := NewGauge(GaugeOpts{
|
||||||
|
Name: "simpleGge",
|
||||||
|
Help: "helpSimpleGge",
|
||||||
|
})
|
||||||
|
simpleGge.Set(3.14)
|
||||||
|
|
||||||
|
preCnt := NewCounter(CounterOpts{
|
||||||
|
Name: "pre_simpleCnt",
|
||||||
|
Help: "helpSimpleCnt",
|
||||||
|
})
|
||||||
|
preCnt.Inc()
|
||||||
|
|
||||||
|
barLabeledCnt := NewCounter(CounterOpts{
|
||||||
|
Name: "simpleCnt",
|
||||||
|
Help: "helpSimpleCnt",
|
||||||
|
ConstLabels: Labels{"foo": "bar"},
|
||||||
|
})
|
||||||
|
barLabeledCnt.Inc()
|
||||||
|
|
||||||
|
bazLabeledCnt := NewCounter(CounterOpts{
|
||||||
|
Name: "simpleCnt",
|
||||||
|
Help: "helpSimpleCnt",
|
||||||
|
ConstLabels: Labels{"foo": "baz"},
|
||||||
|
})
|
||||||
|
bazLabeledCnt.Inc()
|
||||||
|
|
||||||
|
labeledPreCnt := NewCounter(CounterOpts{
|
||||||
|
Name: "pre_simpleCnt",
|
||||||
|
Help: "helpSimpleCnt",
|
||||||
|
ConstLabels: Labels{"foo": "bar"},
|
||||||
|
})
|
||||||
|
labeledPreCnt.Inc()
|
||||||
|
|
||||||
|
twiceLabeledPreCnt := NewCounter(CounterOpts{
|
||||||
|
Name: "pre_simpleCnt",
|
||||||
|
Help: "helpSimpleCnt",
|
||||||
|
ConstLabels: Labels{"foo": "bar", "dings": "bums"},
|
||||||
|
})
|
||||||
|
twiceLabeledPreCnt.Inc()
|
||||||
|
|
||||||
|
barLabeledUncheckedCollector := uncheckedCollector{barLabeledCnt}
|
||||||
|
|
||||||
|
scenarios := map[string]struct {
|
||||||
|
prefix string // First wrap with this prefix.
|
||||||
|
labels Labels // Then wrap the result with these labels.
|
||||||
|
labels2 Labels // If any, wrap the prefix-wrapped one again.
|
||||||
|
preRegister []Collector
|
||||||
|
toRegister []struct { // If there are any labels2, register every other with that one.
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}
|
||||||
|
gatherFails bool
|
||||||
|
output []Collector
|
||||||
|
}{
|
||||||
|
"wrap nothing": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
},
|
||||||
|
"wrap with nothing": {
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}},
|
||||||
|
output: []Collector{simpleGge, simpleCnt},
|
||||||
|
},
|
||||||
|
"wrap counter with prefix": {
|
||||||
|
prefix: "pre_",
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}},
|
||||||
|
output: []Collector{simpleGge, preCnt},
|
||||||
|
},
|
||||||
|
"wrap counter with label pair": {
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}},
|
||||||
|
output: []Collector{simpleGge, barLabeledCnt},
|
||||||
|
},
|
||||||
|
"wrap counter with label pair and prefix": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}},
|
||||||
|
output: []Collector{simpleGge, labeledPreCnt},
|
||||||
|
},
|
||||||
|
"wrap counter with invalid prefix": {
|
||||||
|
prefix: "1+1",
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, true}},
|
||||||
|
output: []Collector{simpleGge},
|
||||||
|
},
|
||||||
|
"wrap counter with invalid label": {
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
labels: Labels{"42": "bar"},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, true}},
|
||||||
|
output: []Collector{simpleGge},
|
||||||
|
},
|
||||||
|
"counter registered twice but wrapped with different label values": {
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
labels2: Labels{"foo": "baz"},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}, {simpleCnt, false}},
|
||||||
|
output: []Collector{barLabeledCnt, bazLabeledCnt},
|
||||||
|
},
|
||||||
|
"counter registered twice but wrapped with different inconsistent label values": {
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
labels2: Labels{"bar": "baz"},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}, {simpleCnt, true}},
|
||||||
|
output: []Collector{barLabeledCnt},
|
||||||
|
},
|
||||||
|
"wrap counter with prefix and two labels": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bar", "dings": "bums"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{simpleCnt, false}},
|
||||||
|
output: []Collector{simpleGge, twiceLabeledPreCnt},
|
||||||
|
},
|
||||||
|
"wrap labeled counter with prefix and another label": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"dings": "bums"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledCnt, false}},
|
||||||
|
output: []Collector{simpleGge, twiceLabeledPreCnt},
|
||||||
|
},
|
||||||
|
"wrap labeled counter with prefix and inconsistent label": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bums"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledCnt, true}},
|
||||||
|
output: []Collector{simpleGge},
|
||||||
|
},
|
||||||
|
"wrap labeled counter with prefix and the same label again": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledCnt, true}},
|
||||||
|
output: []Collector{simpleGge},
|
||||||
|
},
|
||||||
|
"wrap labeled unchecked collector with prefix and another label": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"dings": "bums"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledUncheckedCollector, false}},
|
||||||
|
output: []Collector{simpleGge, twiceLabeledPreCnt},
|
||||||
|
},
|
||||||
|
"wrap labeled unchecked collector with prefix and inconsistent label": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bums"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledUncheckedCollector, false}},
|
||||||
|
gatherFails: true,
|
||||||
|
output: []Collector{simpleGge},
|
||||||
|
},
|
||||||
|
"wrap labeled unchecked collector with prefix and the same label again": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"foo": "bar"},
|
||||||
|
preRegister: []Collector{simpleGge},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledUncheckedCollector, false}},
|
||||||
|
gatherFails: true,
|
||||||
|
output: []Collector{simpleGge},
|
||||||
|
},
|
||||||
|
"wrap labeled unchecked collector with prefix and another label resulting in collision with pre-registered counter": {
|
||||||
|
prefix: "pre_",
|
||||||
|
labels: Labels{"dings": "bums"},
|
||||||
|
preRegister: []Collector{twiceLabeledPreCnt},
|
||||||
|
toRegister: []struct {
|
||||||
|
collector Collector
|
||||||
|
registrationFails bool
|
||||||
|
}{{barLabeledUncheckedCollector, false}},
|
||||||
|
gatherFails: true,
|
||||||
|
output: []Collector{twiceLabeledPreCnt},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for n, s := range scenarios {
|
||||||
|
t.Run(n, func(t *testing.T) {
|
||||||
|
reg := NewPedanticRegistry()
|
||||||
|
for _, c := range s.preRegister {
|
||||||
|
if err := reg.Register(c); err != nil {
|
||||||
|
t.Fatal("error registering with unwrapped registry:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preReg := WrapWithPrefix(s.prefix, reg)
|
||||||
|
lReg := WrapWith(s.labels, preReg)
|
||||||
|
l2Reg := WrapWith(s.labels2, preReg)
|
||||||
|
for i, tr := range s.toRegister {
|
||||||
|
var err error
|
||||||
|
if i%2 != 0 && len(s.labels2) != 0 {
|
||||||
|
err = l2Reg.Register(tr.collector)
|
||||||
|
} else {
|
||||||
|
err = lReg.Register(tr.collector)
|
||||||
|
}
|
||||||
|
if tr.registrationFails && err == nil {
|
||||||
|
t.Fatalf("registration with wrapping registry unexpectedly succeded for collector #%d", i)
|
||||||
|
}
|
||||||
|
if !tr.registrationFails && err != nil {
|
||||||
|
t.Fatalf("registration with wrapping registry failed for collector #%d: %s", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wantMF := toMetricFamilies(s.output...)
|
||||||
|
gotMF, err := reg.Gather()
|
||||||
|
if s.gatherFails && err == nil {
|
||||||
|
t.Fatal("gathering unexpectedly succeded")
|
||||||
|
}
|
||||||
|
if !s.gatherFails && err != nil {
|
||||||
|
t.Fatal("gathering failed:", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotMF, wantMF) {
|
||||||
|
var want, got []string
|
||||||
|
|
||||||
|
for i, mf := range wantMF {
|
||||||
|
want = append(want, fmt.Sprintf("%3d: %s", i, proto.MarshalTextString(mf)))
|
||||||
|
}
|
||||||
|
for i, mf := range gotMF {
|
||||||
|
got = append(got, fmt.Sprintf("%3d: %s", i, proto.MarshalTextString(mf)))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Fatalf(
|
||||||
|
"unexpected output of gathering:\n\nWANT:\n%s\n\nGOT:\n%s\n",
|
||||||
|
strings.Join(want, "\n"),
|
||||||
|
strings.Join(got, "\n"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue