From 4392beadc3b1e2818b6dffdab4c84e99329cf859 Mon Sep 17 00:00:00 2001 From: Sebastian Rabenhorst Date: Thu, 2 Nov 2023 14:08:13 +0100 Subject: [PATCH] Added config to honor labels in mappings Signed-off-by: Sebastian Rabenhorst --- pkg/exporter/exporter.go | 4 +++ pkg/exporter/exporter_test.go | 52 ++++++++++++++++++++++++++++++++++- pkg/mapper/mapping.go | 2 ++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/pkg/exporter/exporter.go b/pkg/exporter/exporter.go index 4bbed4d..f35cde5 100644 --- a/pkg/exporter/exporter.go +++ b/pkg/exporter/exporter.go @@ -105,6 +105,10 @@ func (b *Exporter) handleEvent(thisEvent event.Event) { } metricName = mapper.EscapeMetricName(mapping.Name) for label, value := range labels { + if _, ok := prometheusLabels[label]; mapping.HonorLabels && ok { + continue + } + prometheusLabels[label] = value } b.EventsActions.WithLabelValues(string(mapping.Action)).Inc() diff --git a/pkg/exporter/exporter_test.go b/pkg/exporter/exporter_test.go index a2bb948..2ac0874 100644 --- a/pkg/exporter/exporter_test.go +++ b/pkg/exporter/exporter_test.go @@ -277,7 +277,7 @@ mappings: // TestLabelParsing verifies that labels getting parsed out of metric // names are being properly created. func TestLabelParsing(t *testing.T) { - codes := [2]string{"200", "300"} + codes := [3]string{"200", "300", "400"} events := make(chan event.Events) go func() { @@ -292,6 +292,11 @@ func TestLabelParsing(t *testing.T) { CValue: 1, CLabels: make(map[string]string), }, + &event.CounterEvent{ + CMetricName: "counter.test.400", + CValue: 1, + CLabels: map[string]string{"code": "should be overwritten"}, + }, } events <- c close(events) @@ -329,6 +334,51 @@ mappings: } } +func TestHonorLabels(t *testing.T) { + metricName := "some_counter" + events := make(chan event.Events) + go func() { + c := event.Events{ + &event.CounterEvent{ + CMetricName: metricName, + CValue: 1, + CLabels: map[string]string{"some_label": "bar"}, + }, + } + events <- c + close(events) + }() + + config := ` +mappings: + - match: .* + match_type: regex + name: $0 + labels: + some_label: foo + honor_labels: true +` + testMapper := &mapper.MetricMapper{ + Logger: log.NewNopLogger(), + } + err := testMapper.InitFromYAMLString(config) + if err != nil { + t.Fatalf("Config load error: %s %s", config, err) + } + + ex := NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount) + ex.Listen(events) + + metrics, err := prometheus.DefaultGatherer.Gather() + if err != nil { + t.Fatalf("Cannot gather from DefaultGatherer: %v", err) + } + + if getFloat64(metrics, metricName, map[string]string{"some_label": "bar"}) == nil { + t.Fatalf("Could not find metrics for %s with label set", metricName) + } +} + // TestConflictingMetrics validates that the exporter will not register metrics // of different types that have overlapping names. func TestConflictingMetrics(t *testing.T) { diff --git a/pkg/mapper/mapping.go b/pkg/mapper/mapping.go index dda6423..80fb2a8 100644 --- a/pkg/mapper/mapping.go +++ b/pkg/mapper/mapping.go @@ -28,6 +28,7 @@ type MetricMapping struct { nameFormatter *fsm.TemplateFormatter regex *regexp.Regexp Labels prometheus.Labels `yaml:"labels"` + HonorLabels bool `yaml:"honor_labels"` labelKeys []string labelFormatters []*fsm.TemplateFormatter ObserverType ObserverType `yaml:"observer_type"` @@ -57,6 +58,7 @@ func (m *MetricMapping) UnmarshalYAML(unmarshal func(interface{}) error) error { m.Match = tmp.Match m.Name = tmp.Name m.Labels = tmp.Labels + m.HonorLabels = tmp.HonorLabels m.ObserverType = tmp.ObserverType m.LegacyBuckets = tmp.LegacyBuckets m.LegacyQuantiles = tmp.LegacyQuantiles