Skip to content

Commit

Permalink
Fix textfile crashes with duplicate metrics
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Reedy <[email protected]>
  • Loading branch information
breed808 committed May 12, 2021
1 parent 95f10f1 commit 4293497
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 0 deletions.
32 changes: 32 additions & 0 deletions collector/textfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -65,6 +66,31 @@ func NewTextFileCollector() (Collector, error) {
}, nil
}

// Given a metric family, determine if any two entries are duplicates.
// Duplicates will be detected where the metric name, labels and label values are identical.
func duplicateMetricEntry(metricFamilies map[string]*dto.MetricFamily) bool {
uniqueMetrics := make(map[string]map[string]string)
for _, metricFamily := range metricFamilies {
metric_name := *metricFamily.Name
for _, metric := range metricFamily.Metric {
metric_labels := metric.GetLabel()
labels := make(map[string]string)
for _, label := range metric_labels {
labels[label.GetName()] = label.GetValue()
}
// Check if key is present before appending
_, mapContainsKey := uniqueMetrics[metric_name]

// Duplicate metric found with identical labels & label values
if mapContainsKey == true && reflect.DeepEqual(uniqueMetrics[metric_name], labels) {
return true
}
uniqueMetrics[metric_name] = labels
}
}
return false
}

func convertMetricFamily(metricFamily *dto.MetricFamily, ch chan<- prometheus.Metric) {
var valType prometheus.ValueType
var val float64
Expand Down Expand Up @@ -271,6 +297,12 @@ fileLoop:
// a failure does not appear fresh.
mtimes[f.Name()] = f.ModTime()

if duplicateMetricEntry(parsedFamilies) {
log.Errorf("Duplicate metrics detected in file: %q", path)
error = 1.0
continue
}

for _, mf := range parsedFamilies {
convertMetricFamily(mf, ch)
}
Expand Down
104 changes: 104 additions & 0 deletions collector/textfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"io/ioutil"
"strings"
"testing"

dto "github.com/prometheus/client_model/go"
)

func TestCRFilter(t *testing.T) {
Expand Down Expand Up @@ -45,3 +47,105 @@ func TestCheckBOM(t *testing.T) {
}
}
}

func TestDuplicateMetricEntry(t *testing.T) {
metric_name := "windows_sometest"
metric_help := "This is a Test."
metric_type := dto.MetricType_GAUGE

gauge_value := 1.0

gauge := dto.Gauge{
Value: &gauge_value,
}

label1_name := "display_name"
label1_value := "foobar"

label1 := dto.LabelPair{
Name: &label1_name,
Value: &label1_value,
}

label2_name := "display_version"
label2_value := "13.4.0"

label2 := dto.LabelPair{
Name: &label2_name,
Value: &label2_value,
}

metric1 := dto.Metric{
Label: []*dto.LabelPair{&label1, &label2},
Gauge: &gauge,
}

metric2 := dto.Metric{
Label: []*dto.LabelPair{&label1, &label2},
Gauge: &gauge,
}

duplicate := dto.MetricFamily{
Name: &metric_name,
Help: &metric_help,
Type: &metric_type,
Metric: []*dto.Metric{&metric1, &metric2},
}

duplicateFamily := make(map[string]*dto.MetricFamily)
duplicateFamily["test"] = &duplicate

// Ensure detection for duplicate metrics
if !duplicateMetricEntry(duplicateFamily) {
t.Errorf("Duplicate not found in duplicateFamily")
}

label3_name := "test"
label3_value := "1.0"

label3 := dto.LabelPair{
Name: &label3_name,
Value: &label3_value,
}
metric3 := dto.Metric{
Label: []*dto.LabelPair{&label1, &label2, &label3},
Gauge: &gauge,
}

differentLabels := dto.MetricFamily{
Name: &metric_name,
Help: &metric_help,
Type: &metric_type,
Metric: []*dto.Metric{&metric1, &metric3},
}
duplicateFamily["test"] = &differentLabels

// Additional label on second metric should not be cause for duplicate detection
if duplicateMetricEntry(duplicateFamily) {
t.Errorf("Unexpected duplicate found in differentLabels")
}

label4_value := "2.0"

label4 := dto.LabelPair{
Name: &label3_name,
Value: &label4_value,
}
metric4 := dto.Metric{
Label: []*dto.LabelPair{&label1, &label2, &label4},
Gauge: &gauge,
}

differentValues := dto.MetricFamily{
Name: &metric_name,
Help: &metric_help,
Type: &metric_type,
Metric: []*dto.Metric{&metric3, &metric4},
}
duplicateFamily["test"] = &differentValues

// Additional label with different values metric should not be cause for duplicate detection
if duplicateMetricEntry(duplicateFamily) {
t.Errorf("Unexpected duplicate found in differentValues")
}
}

0 comments on commit 4293497

Please sign in to comment.