From c6ba2a91e688f33f54b25e407922c73de29b68cc Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Wed, 21 Jul 2021 12:39:59 +0300 Subject: [PATCH] meter: BuildName func to combine metric name with labels into string Signed-off-by: Vasiliy Tolstov --- meter/meter.go | 61 ++++++++++++++++++++++++++++----------------- meter/meter_test.go | 20 +++++++++++---- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/meter/meter.go b/meter/meter.go index 500971cc..4de74df9 100644 --- a/meter/meter.go +++ b/meter/meter.go @@ -3,8 +3,9 @@ package meter import ( "io" - "reflect" "sort" + "strconv" + "strings" "time" ) @@ -77,36 +78,50 @@ type Summary interface { UpdateDuration(time.Time) } +// sort labels alphabeticaly by label name type byKey []string func (k byKey) Len() int { return len(k) / 2 } func (k byKey) Less(i, j int) bool { return k[i*2] < k[j*2] } func (k byKey) Swap(i, j int) { - k[i*2], k[i*2+1], k[j*2], k[j*2+1] = k[j*2], k[j*2+1], k[i*2], k[i*2+1] + k[i*2], k[j*2] = k[j*2], k[i*2] + k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1] } -func Sort(slice *[]string) { - bk := byKey(*slice) - if bk.Len() <= 1 { - return +// BuildName used to combine metric with labels. +// If labels count is odd, drop last element +func BuildName(name string, labels ...string) string { + if len(labels)%2 == 1 { + labels = labels[:len(labels)-1] } - sort.Sort(bk) - v := reflect.ValueOf(slice).Elem() - cnt := 0 - key := 0 - val := 1 - for key < v.Len() { - if len(bk) > key+2 && bk[key] == bk[key+2] { - key += 2 - val += 2 - continue + + sort.Sort(byKey(labels)) + + idx := 0 + for { + if labels[idx] == labels[idx+2] { + copy(labels[idx:], labels[idx+2:]) + labels = labels[:len(labels)-2] + } else { + idx += 2 + } + if idx+2 >= len(labels) { + break } - v.Index(cnt).Set(v.Index(key)) - cnt++ - v.Index(cnt).Set(v.Index(val)) - cnt++ - key += 2 - val += 2 } - v.SetLen(cnt) + + var b strings.Builder + _, _ = b.WriteString(name) + _, _ = b.WriteRune('{') + for idx := 0; idx < len(labels); idx += 2 { + if idx > 0 { + _, _ = b.WriteRune(',') + } + _, _ = b.WriteString(labels[idx]) + _, _ = b.WriteString(`=`) + _, _ = b.WriteString(strconv.Quote(labels[idx+1])) + } + _, _ = b.WriteRune('}') + + return b.String() } diff --git a/meter/meter_test.go b/meter/meter_test.go index bec47f78..88d16835 100644 --- a/meter/meter_test.go +++ b/meter/meter_test.go @@ -14,11 +14,21 @@ func TestNoopMeter(t *testing.T) { cnt.Inc() } -func TestLabelsSort(t *testing.T) { - ls := []string{"server", "http", "register", "mdns", "broker", "broker1", "broker", "broker2", "server", "tcp"} - Sort(&ls) +func TestBuildName(t *testing.T) { + data := map[string][]string{ + // `my_metric{firstlabel="value2",zerolabel="value3"}`: []string{ + // "my_metric", + // "zerolabel", "value3", "firstlabel", "value2", + // }, + `my_metric{broker="broker2",register="mdns",server="tcp"}`: []string{ + "my_metric", + "broker", "broker1", "broker", "broker2", "server", "http", "server", "tcp", "register", "mdns", + }, + } - if ls[0] != "broker" || ls[1] != "broker2" { - t.Fatalf("sort error: %v", ls) + for e, d := range data { + if x := BuildName(d[0], d[1:]...); x != e { + t.Fatalf("expect: %s, result: %s", e, x) + } } }