diff --git a/prometheus/registry.go b/prometheus/registry.go index 43e38e9..e422ef3 100644 --- a/prometheus/registry.go +++ b/prometheus/registry.go @@ -787,6 +787,8 @@ func checkMetricConsistency( dtoMetric *dto.Metric, metricHashes map[uint64]struct{}, ) error { + name := metricFamily.GetName() + // Type consistency with metric family. if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || @@ -795,33 +797,42 @@ func checkMetricConsistency( metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { return fmt.Errorf( "collected metric %q { %s} is not a %s", - metricFamily.GetName(), dtoMetric, metricFamily.GetType(), + name, dtoMetric, metricFamily.GetType(), ) } + previousLabelName := "" for _, labelPair := range dtoMetric.GetLabel() { - if !checkLabelName(labelPair.GetName()) { + labelName := labelPair.GetName() + if labelName == previousLabelName { return fmt.Errorf( - "collected metric %q { %s} has a label with an invalid name: %s", - metricFamily.GetName(), dtoMetric, labelPair.GetName(), + "collected metric %q { %s} has two or more labels with the same name: %s", + name, dtoMetric, labelName, ) } - if dtoMetric.Summary != nil && labelPair.GetName() == quantileLabel { + if !checkLabelName(labelName) { + return fmt.Errorf( + "collected metric %q { %s} has a label with an invalid name: %s", + name, dtoMetric, labelName, + ) + } + if dtoMetric.Summary != nil && labelName == quantileLabel { return fmt.Errorf( "collected metric %q { %s} must not have an explicit %q label", - metricFamily.GetName(), dtoMetric, quantileLabel, + name, dtoMetric, quantileLabel, ) } if !utf8.ValidString(labelPair.GetValue()) { return fmt.Errorf( "collected metric %q { %s} has a label named %q whose value is not utf8: %#v", - metricFamily.GetName(), dtoMetric, labelPair.GetName(), labelPair.GetValue()) + name, dtoMetric, labelName, labelPair.GetValue()) } + previousLabelName = labelName } // Is the metric unique (i.e. no other metric with the same name and the same labels)? h := hashNew() - h = hashAdd(h, metricFamily.GetName()) + h = hashAdd(h, name) h = hashAddByte(h, separatorByte) // Make sure label pairs are sorted. We depend on it for the consistency // check. @@ -835,7 +846,7 @@ func checkMetricConsistency( if _, exists := metricHashes[h]; exists { return fmt.Errorf( "collected metric %q { %s} was collected before with the same name and label values", - metricFamily.GetName(), dtoMetric, + name, dtoMetric, ) } metricHashes[h] = struct{}{} diff --git a/prometheus/registry_test.go b/prometheus/registry_test.go index 0c79261..b037931 100644 --- a/prometheus/registry_test.go +++ b/prometheus/registry_test.go @@ -330,7 +330,10 @@ collected metric named "complex_count" collides with previously collected histog }, }, } - duplicateLabelMsg := []byte(`duplicate label mumble mumble`) + duplicateLabelMsg := []byte(`An error has occurred during metrics gathering: + +collected metric "broken_metric" { label: label: counter: } has two or more labels with the same name: foo +`) type output struct { headers map[string]string @@ -675,7 +678,7 @@ collected metric named "complex_count" collides with previously collected histog }, out: output{ headers: map[string]string{ - "Content-Type": `text/plain; version=0.0.4; charset=utf-8`, + "Content-Type": `text/plain; charset=utf-8`, }, body: duplicateLabelMsg, },