Merge pull request #474 from prometheus/beorn7/testing

Add check for duplicated label name
This commit is contained in:
Björn Rabenstein 2018-10-01 19:40:01 +02:00 committed by GitHub
commit 0a8115f42e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 9 deletions

View File

@ -787,6 +787,8 @@ func checkMetricConsistency(
dtoMetric *dto.Metric, dtoMetric *dto.Metric,
metricHashes map[uint64]struct{}, metricHashes map[uint64]struct{},
) error { ) error {
name := metricFamily.GetName()
// Type consistency with metric family. // Type consistency with metric family.
if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil ||
metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil ||
@ -795,33 +797,42 @@ func checkMetricConsistency(
metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil {
return fmt.Errorf( return fmt.Errorf(
"collected metric %q { %s} is not a %s", "collected metric %q { %s} is not a %s",
metricFamily.GetName(), dtoMetric, metricFamily.GetType(), name, dtoMetric, metricFamily.GetType(),
) )
} }
previousLabelName := ""
for _, labelPair := range dtoMetric.GetLabel() { for _, labelPair := range dtoMetric.GetLabel() {
if !checkLabelName(labelPair.GetName()) { labelName := labelPair.GetName()
if labelName == previousLabelName {
return fmt.Errorf( return fmt.Errorf(
"collected metric %q { %s} has a label with an invalid name: %s", "collected metric %q { %s} has two or more labels with the same name: %s",
metricFamily.GetName(), dtoMetric, labelPair.GetName(), 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( return fmt.Errorf(
"collected metric %q { %s} must not have an explicit %q label", "collected metric %q { %s} must not have an explicit %q label",
metricFamily.GetName(), dtoMetric, quantileLabel, name, dtoMetric, quantileLabel,
) )
} }
if !utf8.ValidString(labelPair.GetValue()) { if !utf8.ValidString(labelPair.GetValue()) {
return fmt.Errorf( return fmt.Errorf(
"collected metric %q { %s} has a label named %q whose value is not utf8: %#v", "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)? // Is the metric unique (i.e. no other metric with the same name and the same labels)?
h := hashNew() h := hashNew()
h = hashAdd(h, metricFamily.GetName()) h = hashAdd(h, name)
h = hashAddByte(h, separatorByte) h = hashAddByte(h, separatorByte)
// 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.
@ -835,7 +846,7 @@ func checkMetricConsistency(
if _, exists := metricHashes[h]; exists { if _, exists := metricHashes[h]; 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",
metricFamily.GetName(), dtoMetric, name, dtoMetric,
) )
} }
metricHashes[h] = struct{}{} metricHashes[h] = struct{}{}

View File

@ -307,6 +307,32 @@ collected metric named "complex_count" collides with previously collected summar
histogramCountCollisionMsg := []byte(`An error has occurred during metrics gathering: histogramCountCollisionMsg := []byte(`An error has occurred during metrics gathering:
collected metric named "complex_count" collides with previously collected histogram named "complex" collected metric named "complex_count" collides with previously collected histogram named "complex"
`)
externalMetricFamilyWithDuplicateLabel := &dto.MetricFamily{
Name: proto.String("broken_metric"),
Help: proto.String("The registry should detect the duplicate label."),
Type: dto.MetricType_COUNTER.Enum(),
Metric: []*dto.Metric{
{
Label: []*dto.LabelPair{
{
Name: proto.String("foo"),
Value: proto.String("bar"),
},
{
Name: proto.String("foo"),
Value: proto.String("baz"),
},
},
Counter: &dto.Counter{
Value: proto.Float64(2.7),
},
},
},
}
duplicateLabelMsg := []byte(`An error has occurred during metrics gathering:
collected metric "broken_metric" { label:<name:"foo" value:"bar" > label:<name:"foo" value:"baz" > counter:<value:2.7 > } has two or more labels with the same name: foo
`) `)
type output struct { type output struct {
@ -646,6 +672,20 @@ collected metric named "complex_count" collides with previously collected histog
externalMetricFamilyWithBucketSuffix, externalMetricFamilyWithBucketSuffix,
}, },
}, },
{ // 22
headers: map[string]string{
"Accept": "text/plain",
},
out: output{
headers: map[string]string{
"Content-Type": `text/plain; charset=utf-8`,
},
body: duplicateLabelMsg,
},
externalMF: []*dto.MetricFamily{
externalMetricFamilyWithDuplicateLabel,
},
},
} }
for i, scenario := range scenarios { for i, scenario := range scenarios {
registry := prometheus.NewPedanticRegistry() registry := prometheus.NewPedanticRegistry()