From 27409156167c5e0d5b3c87f0fb9e1bda7b80ff4d Mon Sep 17 00:00:00 2001 From: "davidzhang.zc" Date: Mon, 24 May 2021 09:30:19 +0800 Subject: [PATCH 1/4] sanitize metric labels for AlibabaCloudLogService metrics (#3429) --- .../metricsdata_to_logservice.go | 9 +++- .../sanitize.go | 52 +++++++++++++++++++ .../sanitize_test.go | 32 ++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 exporter/alibabacloudlogserviceexporter/sanitize.go create mode 100644 exporter/alibabacloudlogserviceexporter/sanitize_test.go diff --git a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go index 03eed997c406..bdb77bb75352 100644 --- a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go +++ b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go @@ -51,7 +51,14 @@ func (kv *KeyValues) Swap(i, j int) { kv.keyValues[i], kv.keyValues[j] = kv.keyValues[j], kv.keyValues[i] } func (kv *KeyValues) Less(i, j int) bool { return kv.keyValues[i].Key < kv.keyValues[j].Key } -func (kv *KeyValues) Sort() { sort.Sort(kv) } + +func (kv *KeyValues) Sort() { + // sanitize label keys before sort + for index := range kv.keyValues { + kv.keyValues[index].Key = sanitize(kv.keyValues[index].Key) + } + sort.Sort(kv) +} func (kv *KeyValues) Replace(key, value string) { findIndex := sort.Search(len(kv.keyValues), func(index int) bool { diff --git a/exporter/alibabacloudlogserviceexporter/sanitize.go b/exporter/alibabacloudlogserviceexporter/sanitize.go new file mode 100644 index 000000000000..63256e70e1b5 --- /dev/null +++ b/exporter/alibabacloudlogserviceexporter/sanitize.go @@ -0,0 +1,52 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package alibabacloudlogserviceexporter + +import ( + "strings" + "unicode" +) + +// The code for sanitize is mostly copied from: +// https://github.com/open-telemetry/opentelemetry-collector/blob/2e84285efc665798d76773b9901727e8836e9d8f/exporter/prometheusexporter/sanitize.go + +// sanitize replaces non-alphanumeric characters with underscores in s. +func sanitize(s string) string { + if len(s) == 0 { + return s + } + + // Note: No length limit for label keys because Prometheus doesn't + // define a length limit, thus we should NOT be truncating label keys. + // See https://github.com/orijtech/prometheus-go-metrics-exporter/issues/4. + + s = strings.Map(sanitizeRune, s) + if unicode.IsDigit(rune(s[0])) { + s = "key_" + s + } + if s[0] == '_' { + s = "key" + s + } + return s +} + +// converts anything that is not a letter or digit to an underscore +func sanitizeRune(r rune) rune { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return r + } + // Everything else turns into an underscore + return '_' +} \ No newline at end of file diff --git a/exporter/alibabacloudlogserviceexporter/sanitize_test.go b/exporter/alibabacloudlogserviceexporter/sanitize_test.go new file mode 100644 index 000000000000..bc02a64a9845 --- /dev/null +++ b/exporter/alibabacloudlogserviceexporter/sanitize_test.go @@ -0,0 +1,32 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package alibabacloudlogserviceexporter + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// The code for sanitize is mostly copied from: +// https://github.com/open-telemetry/opentelemetry-collector/blob/2e84285efc665798d76773b9901727e8836e9d8f/exporter/prometheusexporter/sanitize_test.go + +func TestSanitize(t *testing.T) { + require.Equal(t, "", sanitize(""), "") + require.Equal(t, "key_test", sanitize("_test")) + require.Equal(t, "key_0test", sanitize("0test")) + require.Equal(t, "test", sanitize("test")) + require.Equal(t, "test__", sanitize("test_/")) +} \ No newline at end of file From 335d410bfb5878f13c6107256365e34b128e97e1 Mon Sep 17 00:00:00 2001 From: "davidzhang.zc" Date: Mon, 24 May 2021 09:58:43 +0800 Subject: [PATCH 2/4] add new lines at end of file --- exporter/alibabacloudlogserviceexporter/sanitize.go | 2 +- exporter/alibabacloudlogserviceexporter/sanitize_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/alibabacloudlogserviceexporter/sanitize.go b/exporter/alibabacloudlogserviceexporter/sanitize.go index 63256e70e1b5..8749513641e0 100644 --- a/exporter/alibabacloudlogserviceexporter/sanitize.go +++ b/exporter/alibabacloudlogserviceexporter/sanitize.go @@ -49,4 +49,4 @@ func sanitizeRune(r rune) rune { } // Everything else turns into an underscore return '_' -} \ No newline at end of file +} diff --git a/exporter/alibabacloudlogserviceexporter/sanitize_test.go b/exporter/alibabacloudlogserviceexporter/sanitize_test.go index bc02a64a9845..1bfdd7c5fbf9 100644 --- a/exporter/alibabacloudlogserviceexporter/sanitize_test.go +++ b/exporter/alibabacloudlogserviceexporter/sanitize_test.go @@ -29,4 +29,4 @@ func TestSanitize(t *testing.T) { require.Equal(t, "key_0test", sanitize("0test")) require.Equal(t, "test", sanitize("test")) require.Equal(t, "test__", sanitize("test_/")) -} \ No newline at end of file +} From b5d1ebd870ebf4664c35ea0f5bfa7534bb7e1332 Mon Sep 17 00:00:00 2001 From: "davidzhang.zc" Date: Wed, 26 May 2021 14:41:18 +0800 Subject: [PATCH 3/4] refine code --- .../metricsdata_to_logservice.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go index bdb77bb75352..75ca4f22e3f1 100644 --- a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go +++ b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go @@ -53,14 +53,11 @@ func (kv *KeyValues) Swap(i, j int) { func (kv *KeyValues) Less(i, j int) bool { return kv.keyValues[i].Key < kv.keyValues[j].Key } func (kv *KeyValues) Sort() { - // sanitize label keys before sort - for index := range kv.keyValues { - kv.keyValues[index].Key = sanitize(kv.keyValues[index].Key) - } sort.Sort(kv) } func (kv *KeyValues) Replace(key, value string) { + key = sanitize(key) findIndex := sort.Search(len(kv.keyValues), func(index int) bool { return kv.keyValues[index].Key >= key }) @@ -71,6 +68,7 @@ func (kv *KeyValues) Replace(key, value string) { func (kv *KeyValues) AppendMap(mapVal map[string]string) { for key, value := range mapVal { + key = sanitize(key) kv.keyValues = append(kv.keyValues, KeyValue{ Key: key, Value: value, @@ -79,6 +77,7 @@ func (kv *KeyValues) AppendMap(mapVal map[string]string) { } func (kv *KeyValues) Append(key, value string) { + key = sanitize(key) kv.keyValues = append(kv.keyValues, KeyValue{ key, value, From d119db10b3efaa073bf93517ad9e0d5eb6b1100c Mon Sep 17 00:00:00 2001 From: "davidzhang.zc" Date: Fri, 28 May 2021 17:50:44 +0800 Subject: [PATCH 4/4] refine code as review comments --- .../metricsdata_to_logservice.go | 6 +----- .../metricsdata_to_logservice_test.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go index 75ca4f22e3f1..b5319f1a2227 100644 --- a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go +++ b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice.go @@ -68,11 +68,7 @@ func (kv *KeyValues) Replace(key, value string) { func (kv *KeyValues) AppendMap(mapVal map[string]string) { for key, value := range mapVal { - key = sanitize(key) - kv.keyValues = append(kv.keyValues, KeyValue{ - Key: key, - Value: value, - }) + kv.Append(key, value) } } diff --git a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice_test.go b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice_test.go index 80ab4ede2462..786bb0f8f22f 100644 --- a/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice_test.go +++ b/exporter/alibabacloudlogserviceexporter/metricsdata_to_logservice_test.go @@ -170,3 +170,16 @@ func TestMetricCornerCases(t *testing.T) { }) assert.Equal(t, label.String(), "a#$#b") } + +func TestMetricLabelSanitize(t *testing.T) { + var label KeyValues + label.Append("_test", "key_test") + label.Append("0test", "key_0test") + label.AppendMap(map[string]string{ + "test_normal": "test_normal", + "0test": "key_0test", + }) + assert.Equal(t, label.String(), "key_test#$#key_test|key_0test#$#key_0test|test_normal#$#test_normal|key_0test#$#key_0test") + label.Sort() + assert.Equal(t, label.String(), "key_0test#$#key_0test|key_0test#$#key_0test|key_test#$#key_test|test_normal#$#test_normal") +}