Check duplicates across entire textfile set

Check all textfile metrics will be checked for duplicates. If duplicates
are detected, drop all metrics and log error.

Signed-off-by: Ben Reedy <breed808@breed808.com>
This commit is contained in:
Ben Reedy
2021-05-16 12:29:09 +10:00
parent 4293497b29
commit 5072879dca
2 changed files with 24 additions and 15 deletions

View File

@@ -66,9 +66,9 @@ func NewTextFileCollector() (Collector, error) {
}, nil }, nil
} }
// Given a metric family, determine if any two entries are duplicates. // Given a slice of metric families, determine if any two entries are duplicates.
// Duplicates will be detected where the metric name, labels and label values are identical. // Duplicates will be detected where the metric name, labels and label values are identical.
func duplicateMetricEntry(metricFamilies map[string]*dto.MetricFamily) bool { func duplicateMetricEntry(metricFamilies []*dto.MetricFamily) bool {
uniqueMetrics := make(map[string]map[string]string) uniqueMetrics := make(map[string]map[string]string)
for _, metricFamily := range metricFamilies { for _, metricFamily := range metricFamilies {
metric_name := *metricFamily.Name metric_name := *metricFamily.Name
@@ -249,6 +249,10 @@ func (c *textFileCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Met
error = 1.0 error = 1.0
} }
// Create empty metricFamily slice here and append parsedFamilies to it inside the loop.
// Once loop is complete, raise error if any duplicates are present.
// This will ensure that duplicate metrics are correctly detected between multiple .prom files.
var metricFamilies = []*dto.MetricFamily{}
fileLoop: fileLoop:
for _, f := range files { for _, f := range files {
if !strings.HasSuffix(f.Name(), ".prom") { if !strings.HasSuffix(f.Name(), ".prom") {
@@ -297,18 +301,20 @@ fileLoop:
// a failure does not appear fresh. // a failure does not appear fresh.
mtimes[f.Name()] = f.ModTime() mtimes[f.Name()] = f.ModTime()
if duplicateMetricEntry(parsedFamilies) { for _, metricFamily := range parsedFamilies {
log.Errorf("Duplicate metrics detected in file: %q", path) metricFamilies = append(metricFamilies, metricFamily)
error = 1.0
continue
}
for _, mf := range parsedFamilies {
convertMetricFamily(mf, ch)
} }
} }
c.exportMTimes(mtimes, ch) if duplicateMetricEntry(metricFamilies) {
log.Errorf("Duplicate metrics detected in files")
error = 1.0
} else {
for _, mf := range metricFamilies {
convertMetricFamily(mf, ch)
c.exportMTimes(mtimes, ch)
}
}
// Export if there were errors. // Export if there were errors.
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -92,8 +92,8 @@ func TestDuplicateMetricEntry(t *testing.T) {
Metric: []*dto.Metric{&metric1, &metric2}, Metric: []*dto.Metric{&metric1, &metric2},
} }
duplicateFamily := make(map[string]*dto.MetricFamily) duplicateFamily := []*dto.MetricFamily{}
duplicateFamily["test"] = &duplicate duplicateFamily = append(duplicateFamily, &duplicate)
// Ensure detection for duplicate metrics // Ensure detection for duplicate metrics
if !duplicateMetricEntry(duplicateFamily) { if !duplicateMetricEntry(duplicateFamily) {
@@ -118,7 +118,9 @@ func TestDuplicateMetricEntry(t *testing.T) {
Type: &metric_type, Type: &metric_type,
Metric: []*dto.Metric{&metric1, &metric3}, Metric: []*dto.Metric{&metric1, &metric3},
} }
duplicateFamily["test"] = &differentLabels
duplicateFamily = []*dto.MetricFamily{}
duplicateFamily = append(duplicateFamily, &differentLabels)
// Additional label on second metric should not be cause for duplicate detection // Additional label on second metric should not be cause for duplicate detection
if duplicateMetricEntry(duplicateFamily) { if duplicateMetricEntry(duplicateFamily) {
@@ -142,7 +144,8 @@ func TestDuplicateMetricEntry(t *testing.T) {
Type: &metric_type, Type: &metric_type,
Metric: []*dto.Metric{&metric3, &metric4}, Metric: []*dto.Metric{&metric3, &metric4},
} }
duplicateFamily["test"] = &differentValues duplicateFamily = []*dto.MetricFamily{}
duplicateFamily = append(duplicateFamily, &differentValues)
// Additional label with different values metric should not be cause for duplicate detection // Additional label with different values metric should not be cause for duplicate detection
if duplicateMetricEntry(duplicateFamily) { if duplicateMetricEntry(duplicateFamily) {