Golang Metrics Made Easy

In a recent side project I have been working on, I implemented a small TCP server that speaks Redis RESP3 protocol. However, there was one thing that I was missing. From my experience in building distributed systems, while many developers think about adding metrics to track performance, failure rate etc, sometimes it’s just not as easy to do so.

For that reason, I wanted to make sure that from an early stage the daemon is able to vend easily consumable metrics. Since this seems like the perfect problem that someone else has already solved, I searched the usual channels for answers.

This way I found go-metrics. go-metrics is an implementation of Coda Hale’s metric library but for Go. What struck me most was that it comes with a lot of connectors to other downstream systems. In addition, it was very straight-forward to expose these metrics using a local HTTP server.

The integration was very simple:

import (
    "github.com/rcrowley/go-metrics"
    "github.com/rcrowley/go-metrics/exp"
)

// http://localhost:8080/debug/metrics
exp.Exp(metrics.DefaultRegistry)

// Create a new child registry with a given prefix. Since the default registry
// is exported above, this registry will be visible as well.
registry := metrics.NewPrefixedChildRegistry(metrics.DefaultRegistry, "service.")

// Create a new timer that gives us versatile metrics
timer := metrics.NewRegisteredTimer("ResponseTime", registry)

// And use it.
timer.Time(func(){
    // Do expensive work...
})

From the above example, the following metrics will be exposed via the HTTP interface. As you can see the fidelity of the metrics is great. With just a couple of lines, we have mean, max, min and percentile information about our timer.

{
    "service.ResponseSize.max": 19,
    "service.ResponseSize.mean": 19,
    "service.ResponseSize.min": 19,
    "service.ResponseSize.std-dev": 0,
    "service.ResponseTime.50-percentile": 169511,
    "service.ResponseTime.75-percentile": 267262.25,
    "service.ResponseTime.95-percentile": 536905.6999999997,
    "service.ResponseTime.99-percentile": 1.1849336300000004e+06,
    "service.ResponseTime.999-percentile": 1.651854783e+06,
    "service.ResponseTime.count": 7904,
    "service.ResponseTime.fifteen-minute": 382.3157855858603,
    "service.ResponseTime.five-minute": 385.3222102344055,
    "service.ResponseTime.max": 1.652724e+06,
    "service.ResponseTime.mean": 217336.0359922179,
    "service.ResponseTime.mean-rate": 545.1636632191569,
    "service.ResponseTime.min": 18156,
    "service.ResponseTime.one-minute": 402.6758481574172,
    "service.ResponseTime.std-dev": 200807.1187961661,
}

To summarize, I can only recommend using go-metrics as a metrics subsystem in your next go project.