divide long functions, replace strings.builder with bytes.buffer. (#13)

Co-authored-by: Chris Clayton <[email protected]>
This commit is contained in:
Chris Clayton
2024-06-17 10:23:41 +01:00
committed by GitHub
co-authored by Chris Clayton
parent de31912d2f
commit 12e4237997
2 changed files with 227 additions and 78 deletions
+136 -72
View File
@@ -1,129 +1,193 @@
package libpack_monitoring package libpack_monitoring
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"sort" "sort"
"strings" "strings"
"sync"
"unicode" "unicode"
libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config" libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config"
) )
func (ms *MetricsSetup) get_metrics_name(name string, labels map[string]string) (complete_name string) { // Cache for sorted label keys to avoid repeated sorting
var sortedLabelKeysCache = struct {
sync.RWMutex
m map[string][]string
}{m: make(map[string][]string)}
func (ms *MetricsSetup) get_metrics_name(name string, labels map[string]string) string {
const unknownPodName = "unknown" const unknownPodName = "unknown"
var sb strings.Builder var buf bytes.Buffer
// Prepare default labels without initializing a new map // Prepare default labels without initializing a new map
podName := unknownPodName podName := getPodName()
if hn, err := os.Hostname(); err == nil {
podName = hn
}
if labels == nil { if labels == nil {
labels = map[string]string{ labels = defaultLabels(podName)
"microservice": libpack_config.PKG_NAME,
"pod": podName,
}
} else { } else {
if _, exists := labels["microservice"]; !exists { ensureDefaultLabels(&labels, podName)
labels["microservice"] = libpack_config.PKG_NAME
}
if _, exists := labels["pod"]; !exists {
labels["pod"] = podName
}
} }
// Prefix handling // Prefix handling
if ms.metrics_prefix != "" { if ms.metrics_prefix != "" {
sb.WriteString(ms.metrics_prefix) buf.WriteString(ms.metrics_prefix)
sb.WriteString("_") buf.WriteString("_")
} }
sb.WriteString(name) buf.WriteString(name)
// Append labels if any // Append labels if any
if len(labels) > 0 { if len(labels) > 0 {
sb.WriteString("{") buf.WriteString("{")
appendSortedLabels(&buf, labels)
buf.WriteString("}")
}
keys := make([]string, 0, len(labels)) return buf.String()
}
func getPodName() string {
const unknownPodName = "unknown"
if hn, err := os.Hostname(); err == nil {
return hn
}
return unknownPodName
}
func defaultLabels(podName string) map[string]string {
return map[string]string{
"microservice": libpack_config.PKG_NAME,
"pod": podName,
}
}
func ensureDefaultLabels(labels *map[string]string, podName string) {
if *labels == nil {
*labels = make(map[string]string)
}
if _, exists := (*labels)["microservice"]; !exists {
(*labels)["microservice"] = libpack_config.PKG_NAME
}
if _, exists := (*labels)["pod"]; !exists {
(*labels)["pod"] = podName
}
}
func appendSortedLabels(buf *bytes.Buffer, labels map[string]string) {
keys := getSortedKeys(labels)
for i, k := range keys {
if i > 0 {
buf.WriteString(",")
}
buf.WriteString(k)
buf.WriteString("=\"")
buf.WriteString(labels[k])
buf.WriteString("\"")
}
}
func getSortedKeys(labels map[string]string) []string {
labelsKey := labelsToString(labels)
sortedLabelKeysCache.RLock()
keys, exists := sortedLabelKeysCache.m[labelsKey]
sortedLabelKeysCache.RUnlock()
if !exists {
keys = make([]string, 0, len(labels))
for k := range labels { for k := range labels {
keys = append(keys, k) keys = append(keys, k)
} }
sort.Strings(keys) sort.Strings(keys)
for i, k := range keys { sortedLabelKeysCache.Lock()
if i > 0 { sortedLabelKeysCache.m[labelsKey] = keys
sb.WriteString(",") sortedLabelKeysCache.Unlock()
}
sb.WriteString(k)
sb.WriteString("=\"")
sb.WriteString(labels[k])
sb.WriteString("\"")
}
sb.WriteString("}")
} }
return keys
}
func labelsToString(labels map[string]string) string {
var sb strings.Builder
for k, v := range labels {
sb.WriteString(k)
sb.WriteString("=")
sb.WriteString(v)
sb.WriteString(";")
}
return sb.String() return sb.String()
} }
// validate_metrics_name validates the name of the metric to adhere to the Prometheus naming conventions // validate_metrics_name validates the name of the metric to adhere to the Prometheus naming conventions
// https://prometheus.io/docs/practices/naming/ // https://prometheus.io/docs/practices/naming/
func validate_metrics_name(name string) error { func validate_metrics_name(name string) error {
var sb strings.Builder // Use strings.Builder for efficient string concatenation cleanedName := clean_metric_name(name)
// Track if the last character was an underscore to avoid duplicate underscores
lastWasUnderscore := false
for _, r := range name {
// Convert spaces to underscores and skip non-alphanumeric characters except underscores
if r == ' ' || (unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_') {
if r == ' ' || r == '_' {
if lastWasUnderscore {
continue // Skip if the previous character was also an underscore
}
r = '_' // Convert spaces to underscores
lastWasUnderscore = true
} else {
lastWasUnderscore = false
}
sb.WriteRune(r) // Add valid characters to the builder
}
}
// Trim leading and trailing underscores // Trim leading and trailing underscores
name_new := strings.Trim(sb.String(), "_") finalName := strings.Trim(cleanedName, "_")
// Check if the processed name matches the original input // Check if the processed name matches the original input
if name_new != name { if finalName != name {
return fmt.Errorf("Invalid metric name: %s, expected %s", name, name_new) return fmt.Errorf("Invalid metric name: %s, expected %s", name, finalName)
} }
return nil return nil
} }
func compile_metrics_with_labels(name string, labels map[string]string) string { // clean_metric_name processes the metric name according to Prometheus naming conventions
var totalLength int func clean_metric_name(name string) string {
totalLength += len(name) var buf bytes.Buffer
for k, v := range labels { lastWasUnderscore := false
totalLength += len(k) + len(v) + 2
for _, r := range name {
if is_allowed_rune(r) {
if is_special_rune(r) {
if lastWasUnderscore {
continue // Skip if the previous character was also an underscore
}
r = '_' // Convert spaces and special characters to underscores
lastWasUnderscore = true
} else {
lastWasUnderscore = false
}
buf.WriteRune(r)
} else if !lastWasUnderscore {
buf.WriteRune('_')
lastWasUnderscore = true
}
} }
var sb strings.Builder // Remove trailing underscore
sb.Grow(totalLength + 1) result := buf.String()
return strings.Trim(result, "_")
}
sb.WriteString(name) // is_allowed_rune checks if the rune is allowed in the metric name
func is_allowed_rune(r rune) bool {
return unicode.IsLetter(r) || unicode.IsDigit(r) || r == ' ' || r == '_'
}
// is_special_rune checks if the rune is a space or an underscore
func is_special_rune(r rune) bool {
return r == ' ' || r == '_'
}
func compile_metrics_with_labels(name string, labels map[string]string) string {
var buf bytes.Buffer
buf.WriteString(name)
// Collect keys and sort them // Collect keys and sort them
keys := make([]string, 0, len(labels)) keys := getSortedKeys(labels)
for k := range labels {
keys = append(keys, k)
}
sort.Strings(keys)
// Append sorted key-value pairs to the builder // Append sorted key-value pairs to the buffer
for _, k := range keys { for _, k := range keys {
sb.WriteString("_") buf.WriteString("_")
sb.WriteString(k) buf.WriteString(k)
sb.WriteString("_") buf.WriteString("_")
sb.WriteString(labels[k]) buf.WriteString(labels[k])
} }
return sb.String() return buf.String()
} }
+91 -6
View File
@@ -1,7 +1,6 @@
package libpack_monitoring package libpack_monitoring
import ( import (
"os"
"testing" "testing"
libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config" libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config"
@@ -134,10 +133,96 @@ func TestValidateMetricsName(t *testing.T) {
} }
} }
func getPodName() string { func TestCleanMetricName(t *testing.T) {
podName, err := os.Hostname() tests := []struct {
if err != nil { input string
return "unknown" expected string
}{
{"valid metric name", "valid_metric_name"},
{"valid@metric#name!", "valid_metric_name"},
{"__valid__metric__name__", "valid_metric_name"},
{" valid metric name ", "valid_metric_name"},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
assert.Equal(t, tt.expected, clean_metric_name(tt.input))
})
}
}
func TestDefaultLabels(t *testing.T) {
podName := "test-pod"
libpack_config.PKG_NAME = "example_microservice"
expected := map[string]string{
"microservice": "example_microservice",
"pod": podName,
}
assert.Equal(t, expected, defaultLabels(podName))
}
func TestEnsureDefaultLabels(t *testing.T) {
podName := "test-pod"
libpack_config.PKG_NAME = "example_microservice"
tests := []struct {
name string
inputLabels map[string]string
expectedLabels map[string]string
}{
{
name: "Nil labels",
inputLabels: nil,
expectedLabels: map[string]string{"microservice": "example_microservice", "pod": podName},
},
{
name: "Empty labels",
inputLabels: map[string]string{},
expectedLabels: map[string]string{"microservice": "example_microservice", "pod": podName},
},
{
name: "Partial labels",
inputLabels: map[string]string{"microservice": "test_service"},
expectedLabels: map[string]string{"microservice": "test_service", "pod": podName},
},
{
name: "Complete labels",
inputLabels: map[string]string{"microservice": "test_service", "pod": "custom_pod"},
expectedLabels: map[string]string{"microservice": "test_service", "pod": "custom_pod"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ensureDefaultLabels(&tt.inputLabels, podName)
assert.Equal(t, tt.expectedLabels, tt.inputLabels)
})
}
}
func TestLabelsToString(t *testing.T) {
tests := []struct {
labels map[string]string
expected string
}{
{
labels: map[string]string{"key1": "value1", "key2": "value2"},
expected: "key1=value1;key2=value2;",
},
{
labels: map[string]string{"a": "1", "b": "2"},
expected: "a=1;b=2;",
},
{
labels: map[string]string{},
expected: "",
},
}
for _, tt := range tests {
t.Run(tt.expected, func(t *testing.T) {
assert.Equal(t, tt.expected, labelsToString(tt.labels))
})
} }
return podName
} }