From 5b041929ea71ecd0881a3738d49bbeac9cda2b15 Mon Sep 17 00:00:00 2001 From: Jeesmon Jacob Date: Wed, 31 Jan 2024 09:09:43 -0500 Subject: [PATCH] Add flag to control metric tag conversion --- README.md | 10 ++++++---- adapter.go | 8 +++++--- backend/writer.go | 32 +++++++++++++++++--------------- backend/writer_test.go | 42 +++++++++++++++++++++++++++++++++++------- 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 7eddddc..c34ec98 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,9 @@ The adapter takes the following parameters: -buffer-size int Metric buffer size (ignored in proxy mode). -convert-paths - Convert metric names/tags to use period instead of underscores. (default true) + Convert metric names to use period instead of underscores. (default true) +-convert-tag-paths + Convert metric tags to use period instead of underscores. (default true) -debug Print detailed debug messages. -flush-interval int @@ -44,8 +46,8 @@ The adapter takes the following parameters: Port/address to listen to on the format '[address:]port'. If no address is specified, the adapter listens to all interfaces. -metrics-name-override value list of name and overrides in the format 'key1=value1, key2,value2...' - key = original name of the metrics which is coming from prometheus - value = name user wish to override with + key = original name of the metrics which is coming from prometheus + value = name user wish to override with no prefix and pathConversion will be applied to these metrics. -prefix string Prefix for metric names. If omitted, no prefix is added. @@ -72,7 +74,7 @@ The adapter is available as a Docker image. To run it as a Docker container with the parameters discussed above: ``` -docker run wavefronthq/prometheus-storage-adapter -proxy=localhost -proxy-port=2878 -listen=1234 -prefix=prom -convert-paths=true +docker run wavefronthq/prometheus-storage-adapter -proxy=localhost -proxy-port=2878 -listen=1234 -prefix=prom -convert-paths=true -convert-tag-paths=true ``` ## Integrating with Prometheus diff --git a/adapter.go b/adapter.go index 6bfe817..0352979 100644 --- a/adapter.go +++ b/adapter.go @@ -37,7 +37,7 @@ func parseTags(s string) map[string]string { return tags } -//struct to define the custom type to handle the arguments in key=value pair format. +// struct to define the custom type to handle the arguments in key=value pair format. type metricsFilter struct { filter map[string]string } @@ -78,6 +78,7 @@ func main() { var bufferSize int var flushInterval int var convertPaths bool + var convertTagPaths bool var metricsFilter metricsFilter flag.StringVar(&prefix, "prefix", "", "Prefix for metric names. If omitted, no prefix is added.") @@ -91,7 +92,8 @@ func main() { flag.IntVar(&batchSize, "batch-size", 0, "Metric sending batch size (ignored in proxy mode).") flag.IntVar(&bufferSize, "buffer-size", 0, "Metric buffer size (ignored in proxy mode).") flag.IntVar(&flushInterval, "flush-interval", 0, "Metric flush interval (in seconds).") - flag.BoolVar(&convertPaths, "convert-paths", true, "Convert metric names/tags to use period instead of underscores.") + flag.BoolVar(&convertPaths, "convert-paths", true, "Convert metric names to use period instead of underscores.") + flag.BoolVar(&convertTagPaths, "convert-tag-paths", true, "Convert metric tags to use period instead of underscores.") flag.Var(&metricsFilter, "metrics-name-override", " list of name and overrides in the format 'key1=value1, key2,value2...'\n"+ " key = original name of the metrics which is coming from prometheus \n"+ " value = name user wish to override with \n"+ @@ -145,7 +147,7 @@ func main() { log.Fatal(err) return } - mw := backend.NewMetricWriter(sender, prefix, parseTags(tags), convertPaths, metricsFilter.filter) + mw := backend.NewMetricWriter(sender, prefix, parseTags(tags), convertPaths, convertTagPaths, metricsFilter.filter) // Install metric receiver http.HandleFunc("/receive", func(w http.ResponseWriter, r *http.Request) { diff --git a/backend/writer.go b/backend/writer.go index 9178a2d..b9444be 100644 --- a/backend/writer.go +++ b/backend/writer.go @@ -13,25 +13,27 @@ import ( ) type MetricWriter struct { - prefix string - tags map[string]string - sender senders.Sender - convertPaths bool - metricsSent int64 - numErrors int64 - errorRate float64 - filters map[string]string + prefix string + tags map[string]string + sender senders.Sender + convertPaths bool + convertTagPaths bool + metricsSent int64 + numErrors int64 + errorRate float64 + filters map[string]string } var tagValueReplacer = strings.NewReplacer("\"", "\\\"", "*", "-") -func NewMetricWriter(sender senders.Sender, prefix string, tags map[string]string, convertPaths bool, filters map[string]string) *MetricWriter { +func NewMetricWriter(sender senders.Sender, prefix string, tags map[string]string, convertPaths bool, convertTagPaths bool, filters map[string]string) *MetricWriter { return &MetricWriter{ - sender: sender, - prefix: prefix, - tags: tags, - convertPaths: convertPaths, - filters: filters, + sender: sender, + prefix: prefix, + tags: tags, + convertPaths: convertPaths, + convertTagPaths: convertTagPaths, + filters: filters, } } @@ -94,7 +96,7 @@ func (w *MetricWriter) buildMetricName(name string) string { } func (w *MetricWriter) buildTagName(name string) string { - if name != "__name__" && w.convertPaths { + if name != "__name__" && w.convertTagPaths { name = strings.Replace(name, "_", ".", -1) } return name diff --git a/backend/writer_test.go b/backend/writer_test.go index 29a1775..39bc0d2 100644 --- a/backend/writer_test.go +++ b/backend/writer_test.go @@ -124,7 +124,7 @@ func TestRoundtrips(t *testing.T) { Host: "localhost", MetricsPort: 4711, }) require.NoError(t, err) - w := NewMetricWriter(sender, "prom", map[string]string{}, false, map[string]string{ + w := NewMetricWriter(sender, "prom", map[string]string{}, false, false, map[string]string{ "status_request_per_second": "status.request_per_second", }) for _, test := range testCases { @@ -186,22 +186,22 @@ func TestBuildName(t *testing.T) { testName := "metric_name_with_underscore" filters := make(map[string]string, 0) // empty prefix and convert=true - w := NewMetricWriter(sender, "", map[string]string{}, true, filters) + w := NewMetricWriter(sender, "", map[string]string{}, true, true, filters) name := w.buildMetricName(testName) require.Equal(t, "metric.name.with.underscore", name) // empty prefix and convert=false - w = NewMetricWriter(sender, "", map[string]string{}, false, filters) + w = NewMetricWriter(sender, "", map[string]string{}, false, false, filters) name = w.buildMetricName(testName) require.Equal(t, testName, name) // non-empty prefix and convert=true - w = NewMetricWriter(sender, "prom", map[string]string{}, true, filters) + w = NewMetricWriter(sender, "prom", map[string]string{}, true, true, filters) name = w.buildMetricName(testName) require.Equal(t, "prom.metric.name.with.underscore", name) // non-empty prefix and convert=false - w = NewMetricWriter(sender, "prom", map[string]string{}, false, filters) + w = NewMetricWriter(sender, "prom", map[string]string{}, false, false, filters) name = w.buildMetricName(testName) require.Equal(t, "prom_"+testName, name) @@ -211,13 +211,41 @@ func TestBuildName(t *testing.T) { } //filter metrics that should not have any prefix and names would be set to custom value - w = NewMetricWriter(sender, "prom", map[string]string{}, true, filters) + w = NewMetricWriter(sender, "prom", map[string]string{}, true, true, filters) name = w.buildMetricName("metrics_availability") require.Equal(t, "metrics.availability", name) //filter metrics that should have prefix - w = NewMetricWriter(sender, "prom", map[string]string{}, true, filters) + w = NewMetricWriter(sender, "prom", map[string]string{}, true, true, filters) name = w.buildMetricName("metrics_availability_1") require.Equal(t, "prom.metrics.availability.1", name) + testTagName := "tag_name_with_underscore" + // empty prefix, convertPaths=true and convertTagPaths=true + w = NewMetricWriter(sender, "", map[string]string{}, true, true, filters) + name = w.buildMetricName(testName) + tag := w.buildTagName(testTagName) + require.Equal(t, "metric.name.with.underscore", name) + require.Equal(t, "tag.name.with.underscore", tag) + + // empty prefix, convertPaths=true and convertTagPaths=false + w = NewMetricWriter(sender, "", map[string]string{}, true, false, filters) + name = w.buildMetricName(testName) + tag = w.buildTagName(testTagName) + require.Equal(t, "metric.name.with.underscore", name) + require.Equal(t, testTagName, tag) + + // empty prefix, convertPaths=false and convertTagPaths=true + w = NewMetricWriter(sender, "", map[string]string{}, false, true, filters) + name = w.buildMetricName(testName) + tag = w.buildTagName(testTagName) + require.Equal(t, testName, name) + require.Equal(t, "tag.name.with.underscore", tag) + + // empty prefix, convertPaths=false and convertTagPaths=false + w = NewMetricWriter(sender, "", map[string]string{}, false, false, filters) + name = w.buildMetricName(testName) + tag = w.buildTagName(testTagName) + require.Equal(t, testName, name) + require.Equal(t, testTagName, tag) }