Testing Golang Prometheus Instrumentation
// Publicado em: 28 de março de 2023Instrumenting an application means collecting data points to further analyze its performance, diagnose errors and understand behaviour. These measurements will help you answer questions like:
- How many times did my code failed in this specific way?
- How long is it taking to run this operation?
- What was the memory usage in this particular point in time?
Being able to answer these and many other questions in a production ready app is essential. It helps everyone responsible for the code to make better decisions, prioritize features and support necessary changes. All these benefits are only possible if you trust your metrics, if you are sure they represent reality.
One way to be confident about your software, and thus your metrics, is to test the code generating them and this is what we will cover today.
Prometheus Metrics
Prometheus is one of the leading time series databases, often used to store data representing metrics. The Internet is full of articles on its features, usage, deployment etc, so I won’t be covering the basics here. If you are new to Prometheus, I recommend reading these pieces:
Testing Prometheus Metrics with Golang
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
registry = prometheus.NewRegistry()
simpleCounterTotal = promauto.NewCounter(prometheus.CounterOpts{
Namespace: "myapp",
Name: "simple_counter_total",
})
temperature = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "myapp",
Name: "temperature",
}, []string{"city"})
)
func init() {
registry.MustRegister(simpleCounterTotal, temperature)
}
func incrementSimpleCounterTotal() {
simpleCounterTotal.Inc()
}
func setCityTemperature(city string, t float64) {
temperature.WithLabelValues(city).Set(t)
}
func main() {
incrementSimpleCounterTotal()
setCityTemperature("berlin", 30)
http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
http.ListenAndServe(":8000", nil)
}
package main
import (
"testing"
dto "github.com/prometheus/client_model/go"
)
var (
metric dto.Metric
)
func Test_IncrementSimpleCounterTotal(t *testing.T) {
incrementSimpleCounterTotal()
err := simpleCounterTotal.Write(&metric)
if err != nil {
t.Fail()
}
if metric.GetCounter().GetValue() != 1.0 {
t.Fail()
}
metric.Reset()
}
func Test_Temperature(t *testing.T) {
setCityTemperature("berlin", 30)
err := temperature.WithLabelValues("berlin").Write(&metric)
if err != nil {
t.Fail()
}
if metric.GetGauge().GetValue() != 30 {
t.Fail()
}
metric.Reset()
}