|
@@ -25,6 +25,7 @@ import (
|
|
"sync"
|
|
"sync"
|
|
"unicode/utf8"
|
|
"unicode/utf8"
|
|
|
|
|
|
|
|
+ "github.com/cespare/xxhash/v2"
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/prometheus/common/expfmt"
|
|
"github.com/prometheus/common/expfmt"
|
|
|
|
|
|
@@ -74,7 +75,7 @@ func NewRegistry() *Registry {
|
|
// NewPedanticRegistry returns a registry that checks during collection if each
|
|
// NewPedanticRegistry returns a registry that checks during collection if each
|
|
// collected Metric is consistent with its reported Desc, and if the Desc has
|
|
// collected Metric is consistent with its reported Desc, and if the Desc has
|
|
// actually been registered with the registry. Unchecked Collectors (those whose
|
|
// actually been registered with the registry. Unchecked Collectors (those whose
|
|
-// Describe methed does not yield any descriptors) are excluded from the check.
|
|
|
|
|
|
+// Describe method does not yield any descriptors) are excluded from the check.
|
|
//
|
|
//
|
|
// Usually, a Registry will be happy as long as the union of all collected
|
|
// Usually, a Registry will be happy as long as the union of all collected
|
|
// Metrics is consistent and valid even if some metrics are not consistent with
|
|
// Metrics is consistent and valid even if some metrics are not consistent with
|
|
@@ -266,7 +267,7 @@ func (r *Registry) Register(c Collector) error {
|
|
descChan = make(chan *Desc, capDescChan)
|
|
descChan = make(chan *Desc, capDescChan)
|
|
newDescIDs = map[uint64]struct{}{}
|
|
newDescIDs = map[uint64]struct{}{}
|
|
newDimHashesByName = map[string]uint64{}
|
|
newDimHashesByName = map[string]uint64{}
|
|
- collectorID uint64 // Just a sum of all desc IDs.
|
|
|
|
|
|
+ collectorID uint64 // All desc IDs XOR'd together.
|
|
duplicateDescErr error
|
|
duplicateDescErr error
|
|
)
|
|
)
|
|
go func() {
|
|
go func() {
|
|
@@ -293,12 +294,12 @@ func (r *Registry) Register(c Collector) error {
|
|
if _, exists := r.descIDs[desc.id]; exists {
|
|
if _, exists := r.descIDs[desc.id]; exists {
|
|
duplicateDescErr = fmt.Errorf("descriptor %s already exists with the same fully-qualified name and const label values", desc)
|
|
duplicateDescErr = fmt.Errorf("descriptor %s already exists with the same fully-qualified name and const label values", desc)
|
|
}
|
|
}
|
|
- // If it is not a duplicate desc in this collector, add it to
|
|
|
|
|
|
+ // If it is not a duplicate desc in this collector, XOR it to
|
|
// the collectorID. (We allow duplicate descs within the same
|
|
// the collectorID. (We allow duplicate descs within the same
|
|
// collector, but their existence must be a no-op.)
|
|
// collector, but their existence must be a no-op.)
|
|
if _, exists := newDescIDs[desc.id]; !exists {
|
|
if _, exists := newDescIDs[desc.id]; !exists {
|
|
newDescIDs[desc.id] = struct{}{}
|
|
newDescIDs[desc.id] = struct{}{}
|
|
- collectorID += desc.id
|
|
|
|
|
|
+ collectorID ^= desc.id
|
|
}
|
|
}
|
|
|
|
|
|
// Are all the label names and the help string consistent with
|
|
// Are all the label names and the help string consistent with
|
|
@@ -360,7 +361,7 @@ func (r *Registry) Unregister(c Collector) bool {
|
|
var (
|
|
var (
|
|
descChan = make(chan *Desc, capDescChan)
|
|
descChan = make(chan *Desc, capDescChan)
|
|
descIDs = map[uint64]struct{}{}
|
|
descIDs = map[uint64]struct{}{}
|
|
- collectorID uint64 // Just a sum of the desc IDs.
|
|
|
|
|
|
+ collectorID uint64 // All desc IDs XOR'd together.
|
|
)
|
|
)
|
|
go func() {
|
|
go func() {
|
|
c.Describe(descChan)
|
|
c.Describe(descChan)
|
|
@@ -368,7 +369,7 @@ func (r *Registry) Unregister(c Collector) bool {
|
|
}()
|
|
}()
|
|
for desc := range descChan {
|
|
for desc := range descChan {
|
|
if _, exists := descIDs[desc.id]; !exists {
|
|
if _, exists := descIDs[desc.id]; !exists {
|
|
- collectorID += desc.id
|
|
|
|
|
|
+ collectorID ^= desc.id
|
|
descIDs[desc.id] = struct{}{}
|
|
descIDs[desc.id] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -875,9 +876,9 @@ func checkMetricConsistency(
|
|
}
|
|
}
|
|
|
|
|
|
// Is the metric unique (i.e. no other metric with the same name and the same labels)?
|
|
// Is the metric unique (i.e. no other metric with the same name and the same labels)?
|
|
- h := hashNew()
|
|
|
|
- h = hashAdd(h, name)
|
|
|
|
- h = hashAddByte(h, separatorByte)
|
|
|
|
|
|
+ h := xxhash.New()
|
|
|
|
+ h.WriteString(name)
|
|
|
|
+ h.Write(separatorByteSlice)
|
|
// Make sure label pairs are sorted. We depend on it for the consistency
|
|
// Make sure label pairs are sorted. We depend on it for the consistency
|
|
// check.
|
|
// check.
|
|
if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) {
|
|
if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) {
|
|
@@ -888,18 +889,19 @@ func checkMetricConsistency(
|
|
dtoMetric.Label = copiedLabels
|
|
dtoMetric.Label = copiedLabels
|
|
}
|
|
}
|
|
for _, lp := range dtoMetric.Label {
|
|
for _, lp := range dtoMetric.Label {
|
|
- h = hashAdd(h, lp.GetName())
|
|
|
|
- h = hashAddByte(h, separatorByte)
|
|
|
|
- h = hashAdd(h, lp.GetValue())
|
|
|
|
- h = hashAddByte(h, separatorByte)
|
|
|
|
|
|
+ h.WriteString(lp.GetName())
|
|
|
|
+ h.Write(separatorByteSlice)
|
|
|
|
+ h.WriteString(lp.GetValue())
|
|
|
|
+ h.Write(separatorByteSlice)
|
|
}
|
|
}
|
|
- if _, exists := metricHashes[h]; exists {
|
|
|
|
|
|
+ hSum := h.Sum64()
|
|
|
|
+ if _, exists := metricHashes[hSum]; exists {
|
|
return fmt.Errorf(
|
|
return fmt.Errorf(
|
|
"collected metric %q { %s} was collected before with the same name and label values",
|
|
"collected metric %q { %s} was collected before with the same name and label values",
|
|
name, dtoMetric,
|
|
name, dtoMetric,
|
|
)
|
|
)
|
|
}
|
|
}
|
|
- metricHashes[h] = struct{}{}
|
|
|
|
|
|
+ metricHashes[hSum] = struct{}{}
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|