Skip to content

Commit a33f947

Browse files
committed
[FAB-5903]Add statsd reporter and test
This patch add a statsd reporter which support tagging. The current implementation add tag pairs to metrics name. The test use a mock statsd udp server to receive the metrics. Change-Id: I80b4c1e8bda65c65c1b36989e5366e19bb745e8f Signed-off-by: grapebaba <281165273@qq.com>
1 parent decef7c commit a33f947

File tree

12 files changed

+978
-0
lines changed

12 files changed

+978
-0
lines changed

common/metrics/tally_provider.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import (
1212
"sync"
1313
"time"
1414

15+
"sort"
16+
17+
"github.com/cactus/go-statsd-client/statsd"
1518
"github.com/uber-go/tally"
19+
statsdreporter "github.com/uber-go/tally/statsd"
1620
)
1721

1822
var scopeRegistryKey = tally.KeyForPrefixedStringMap
@@ -181,6 +185,65 @@ func (s *scope) SubScope(prefix string) Scope {
181185
return subScope
182186
}
183187

188+
type statsdReporter struct {
189+
reporter tally.StatsReporter
190+
}
191+
192+
func newStatsdReporter(statsd statsd.Statter, opts statsdreporter.Options) tally.StatsReporter {
193+
reporter := statsdreporter.NewReporter(statsd, opts)
194+
return &statsdReporter{reporter: reporter}
195+
}
196+
197+
func (r *statsdReporter) ReportCounter(name string, tags map[string]string, value int64) {
198+
r.reporter.ReportCounter(tagsToName(name, tags), tags, value)
199+
}
200+
201+
func (r *statsdReporter) ReportGauge(name string, tags map[string]string, value float64) {
202+
r.reporter.ReportGauge(tagsToName(name, tags), tags, value)
203+
}
204+
205+
func (r *statsdReporter) ReportTimer(name string, tags map[string]string, interval time.Duration) {
206+
r.reporter.ReportTimer(tagsToName(name, tags), tags, interval)
207+
}
208+
209+
func (r *statsdReporter) ReportHistogramValueSamples(
210+
name string,
211+
tags map[string]string,
212+
buckets tally.Buckets,
213+
bucketLowerBound,
214+
bucketUpperBound float64,
215+
samples int64,
216+
) {
217+
r.reporter.ReportHistogramValueSamples(tagsToName(name, tags), tags, buckets, bucketLowerBound, bucketUpperBound, samples)
218+
}
219+
220+
func (r *statsdReporter) ReportHistogramDurationSamples(
221+
name string,
222+
tags map[string]string,
223+
buckets tally.Buckets,
224+
bucketLowerBound,
225+
bucketUpperBound time.Duration,
226+
samples int64,
227+
) {
228+
r.reporter.ReportHistogramDurationSamples(tagsToName(name, tags), tags, buckets, bucketLowerBound, bucketUpperBound, samples)
229+
}
230+
231+
func (r *statsdReporter) Capabilities() tally.Capabilities {
232+
return r
233+
}
234+
235+
func (r *statsdReporter) Reporting() bool {
236+
return true
237+
}
238+
239+
func (r *statsdReporter) Tagging() bool {
240+
return true
241+
}
242+
243+
func (r *statsdReporter) Flush() {
244+
// no-op
245+
}
246+
184247
func (s *scope) fullyQualifiedName(name string) string {
185248
if len(s.prefix) == 0 {
186249
return name
@@ -217,3 +280,17 @@ func copyStringMap(stringMap map[string]string) map[string]string {
217280
}
218281
return result
219282
}
283+
284+
func tagsToName(name string, tags map[string]string) string {
285+
var keys []string
286+
for k := range tags {
287+
keys = append(keys, k)
288+
}
289+
sort.Strings(keys)
290+
291+
for _, k := range keys {
292+
name = name + tally.DefaultSeparator + k + "-" + tags[k]
293+
}
294+
295+
return name
296+
}

common/metrics/tally_provider_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@ import (
1212
"testing"
1313
"time"
1414

15+
"io"
16+
"net"
17+
"strings"
18+
19+
"github.com/cactus/go-statsd-client/statsd"
1520
"github.com/stretchr/testify/assert"
1621
"github.com/uber-go/tally"
22+
statsdreporter "github.com/uber-go/tally/statsd"
1723
)
1824

25+
const statsdAddr string = "127.0.0.1:8125"
26+
1927
type testIntValue struct {
2028
val int64
2129
tags map[string]string
@@ -340,3 +348,52 @@ func TestSubScopeTagged(t *testing.T) {
340348
"env": "test",
341349
}, r.counters[namespace+".sub.haha"].tags)
342350
}
351+
352+
func TestMetricsByStatsdReporter(t *testing.T) {
353+
t.Parallel()
354+
udpAddr, err := net.ResolveUDPAddr("udp", statsdAddr)
355+
if err != nil {
356+
t.Fatal(err)
357+
}
358+
359+
server, err := net.ListenUDP("udp", udpAddr)
360+
if err != nil {
361+
t.Fatal(err)
362+
}
363+
defer server.Close()
364+
365+
r := newTestStatsdReporter()
366+
opts := tally.ScopeOptions{
367+
Prefix: namespace,
368+
Separator: tally.DefaultSeparator,
369+
Reporter: r}
370+
371+
s, c := newRootScope(opts, 1*time.Second)
372+
defer c.Close()
373+
subs := s.SubScope("peer").Tagged(map[string]string{"component": "committer", "env": "test"})
374+
subs.Counter("success_total").Inc(1)
375+
subs.Gauge("channel_total").Update(4)
376+
377+
buffer := make([]byte, 4096)
378+
n, _ := io.ReadAtLeast(server, buffer, 1)
379+
result := string(buffer[:n])
380+
381+
expected := []string{
382+
`hyperledger.fabric.peer.success_total.component-committer.env-test:1|c`,
383+
`hyperledger.fabric.peer.channel_total.component-committer.env-test:4|g`,
384+
}
385+
386+
for i, res := range strings.Split(result, "\n") {
387+
if res != expected[i] {
388+
t.Errorf("Got `%s`, expected `%s`", res, expected[i])
389+
}
390+
}
391+
}
392+
393+
func newTestStatsdReporter() tally.StatsReporter {
394+
statter, _ := statsd.NewBufferedClient(statsdAddr,
395+
"", 100*time.Millisecond, 512)
396+
397+
opts := statsdreporter.Options{}
398+
return newStatsdReporter(statter, opts)
399+
}

vendor/github.com/cactus/go-statsd-client/LICENSE.md

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/cactus/go-statsd-client/statsd/buffer_pool.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)