diff --git a/statsd/aggregator.go b/statsd/aggregator.go index 5542c9ea..33eb930a 100644 --- a/statsd/aggregator.go +++ b/statsd/aggregator.go @@ -172,14 +172,22 @@ func (a *aggregator) flushMetrics() []metric { return metrics } +// getContext returns the context for a metric name and tags. +// +// The context is the metric name and tags separated by a separator symbol. +// It is not intended to be used as a metric name but as a unique key to aggregate func getContext(name string, tags []string) string { c, _ := getContextAndTags(name, tags) return c } +// getContextAndTags returns the context and tags for a metric name and tags. +// +// See getContext for usage for context +// The tags are the tags separated by a separator symbol and can be re-used to pass down to the writer func getContextAndTags(name string, tags []string) (string, string) { if len(tags) == 0 { - return name + nameSeparatorSymbol, "" + return name, "" } n := len(name) + len(nameSeparatorSymbol) + len(tagSeparatorSymbol)*(len(tags)-1) for _, s := range tags { diff --git a/statsd/aggregator_test.go b/statsd/aggregator_test.go index 472f08e1..162fb463 100644 --- a/statsd/aggregator_test.go +++ b/statsd/aggregator_test.go @@ -377,7 +377,7 @@ func TestGetContextAndTags(t *testing.T) { testName: "no tags", name: "name", tags: nil, - wantContext: "name:", + wantContext: "name", wantTags: "", }, { @@ -403,3 +403,21 @@ func TestGetContextAndTags(t *testing.T) { }) } } + +func BenchmarkGetContext(b *testing.B) { + name := "test.metric" + tags := []string{"tag:tag", "foo:bar"} + for i := 0; i < b.N; i++ { + getContext(name, tags) + } + b.ReportAllocs() +} + +func BenchmarkGetContextNoTags(b *testing.B) { + name := "test.metric" + var tags []string + for i := 0; i < b.N; i++ { + getContext(name, tags) + } + b.ReportAllocs() +} diff --git a/statsd/statsd_benchmark_test.go b/statsd/statsd_benchmark_test.go index b3143bac..79092695 100644 --- a/statsd/statsd_benchmark_test.go +++ b/statsd/statsd_benchmark_test.go @@ -26,7 +26,15 @@ func setupUDSClientServer(b *testing.B, options []statsd.Option) (*statsd.Client } go func() { for { - _, err := conn.Accept() + c, err := conn.Accept() + // We need to read everything from the socket to avoid blocking the sender + buf := make([]byte, 1024) + for { + _, err = c.Read(buf) + if err != nil { + break + } + } if err != nil { return } @@ -76,8 +84,9 @@ func benchmarkStatsdDifferentMetrics(b *testing.B, transport string, extraOption b.RunParallel(func(pb *testing.PB) { testNumber := atomic.AddInt32(&n, 1) name := fmt.Sprintf("test.metric%d", testNumber) + tags := []string{"tag:tag"} for pb.Next() { - client.Gauge(name, 1, []string{"tag:tag"}, 1) + client.Gauge(name, 1, tags, 1) } }) client.Flush() @@ -96,7 +105,8 @@ func benchmarkStatsdSameMetrics(b *testing.B, transport string, extraOptions ... b.RunParallel(func(pb *testing.PB) { for pb.Next() { - client.Gauge("test.metric", 1, []string{"tag:tag"}, 1) + tags := []string{"tag:tag"} + client.Gauge("test.metric", 1, tags, 1) } }) client.Flush()