smira / go-statsd

Go statsd client library with zero allocation overhead, great performance and reconnects
MIT License
109 stars 18 forks source link
golang monitoring statsd statsite zero-allocation

Build Status Documentation Go Report Card codecov License FOSSA Status

Go statsd client library with zero allocation overhead, great performance and automatic reconnects.

Client has zero memory allocation per metric sent:

Zero memory allocation

As metrics could be sent by the application at very high rate (e.g. hundreds of metrics per one request), it is important that sending metrics doesn't cause any additional GC or CPU pressure. go-statsd is using buffer pools and it tries to avoid allocations while building statsd packets.

Reconnecting to statsd

With modern container-based platforms with dynamic DNS statsd server might change its address when container gets rescheduled. As statsd packets are delivered over UDP, there's no easy way for the client to figure out that packets are going nowhere. go-statsd supports configurable reconnect interval which forces DNS resolution.

While client is reconnecting, metrics are still processed and buffered.

Dropping metrics

When buffer pool is exhausted, go-statsd starts dropping packets. Number of dropped packets is reported via Client.GetLostPackets() and every minute logged using log.Printf(). Usually packets should never be dropped, if that happens it's usually signal of enormous metric volume.

Stastd server

Any statsd-compatible server should work well with go-statsd, statsite works exceptionally well as it has great performance and low memory footprint even with huge number of metrics.

Usage

Initialize client instance with options, one client per application is usually enough:

client := statsd.NewClient("localhost:8125",
    statsd.MaxPacketSize(1400),
    statsd.MetricPrefix("web."))

Send metrics as events happen in the application, metrics will be packed together and delivered to statsd server:

start := time.Now()
client.Incr("requests.http", 1)
// ...
client.PrecisionTiming("requests.route.api.latency", time.Since(start))

Shutdown client during application shutdown to flush all the pending metrics:

client.Close()

Tagging

Metrics could be tagged to support aggregation on TSDB side. go-statsd supports tags in InfluxDB , Datadog and Graphite formats. Format and default tags (applied to every metric) are passed as options to the client initialization:

client := statsd.NewClient("localhost:8125",
    statsd.TagStyle(TagFormatDatadog),
    statsd.DefaultTags(statsd.StringTag("app", "billing")))

For every metric sent, tags could be added as the last argument(s) to the function call:

client.Incr("request", 1,
    statsd.StringTag("procotol", "http"), statsd.IntTag("port", 80))

Benchmark

Benchmark comparing several clients:

Benchmark results:

BenchmarkAlexcesaro-12       5000000           333 ns/op           0 B/op          0 allocs/op
BenchmarkGoStatsd-12        10000000           230 ns/op          23 B/op          0 allocs/op
BenchmarkCactus-12           3000000           604 ns/op           5 B/op          0 allocs/op
BenchmarkG2s-12               200000          7499 ns/op         576 B/op         21 allocs/op
BenchmarkQuipo-12            1000000          1048 ns/op         384 B/op          7 allocs/op
BenchmarkUnix4ever-12        1000000          1695 ns/op         408 B/op         18 allocs/op

Origins

Ideas were borrowed from the following stastd clients:

Talks

I gave a talk about design and optimizations which went into go-statsd at Gophercon Russia 2018: slides, source.

License

License is MIT License.

FOSSA Status