diff --git a/meter/meter.go b/meter/meter.go index 4de74df9..05fc84ac 100644 --- a/meter/meter.go +++ b/meter/meter.go @@ -88,6 +88,16 @@ func (k byKey) Swap(i, j int) { k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1] } +// BuildLables used to sort labels and delete duplicates. +// Last value wins in case of duplicate label keys. +func BuildLabels(labels ...string) []string { + if len(labels)%2 == 1 { + labels = labels[:len(labels)-1] + } + sort.Sort(byKey(labels)) + return labels +} + // BuildName used to combine metric with labels. // If labels count is odd, drop last element func BuildName(name string, labels ...string) string { diff --git a/meter/meter_test.go b/meter/meter_test.go index 88d16835..ddff5d91 100644 --- a/meter/meter_test.go +++ b/meter/meter_test.go @@ -14,12 +14,44 @@ func TestNoopMeter(t *testing.T) { cnt.Inc() } +func testEq(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +func TestBuildLabels(t *testing.T) { + type testData struct { + src []string + dst []string + } + + data := []testData{ + testData{ + src: []string{"zerolabel", "value3", "firstlabel", "value2"}, + dst: []string{"firstlabel", "value2", "zerolabel", "value3"}, + }, + } + + for _, d := range data { + if !testEq(d.dst, BuildLabels(d.src...)) { + t.Fatalf("slices not properly sorted: %v %v", d.dst, d.src) + } + } +} + func TestBuildName(t *testing.T) { data := map[string][]string{ - // `my_metric{firstlabel="value2",zerolabel="value3"}`: []string{ - // "my_metric", - // "zerolabel", "value3", "firstlabel", "value2", - // }, + `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",