http.ServerのメトリクスをPrometheusで出力する
https://prometheus.io/docs/tutorials/instrumenting_http_server_in_go/
package main
import (
"fmt"
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var pingCounter = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "ping_request_count",
Help: "No of request handled by Ping handler",
},
)
func ping(w http.ResponseWriter, req *http.Request) {
pingCounter.Inc()
fmt.Fprintf(w, "pong")
}
func main() {
prometheus.MustRegister(pingCounter)
http.HandleFunc("/ping", ping)
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8090", nil)
}
Echoの場合
package main
import (
"net/http"
promMiddleware "github.com/labstack/echo-contrib/prometheus"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
// /metrics でメトリクス情報が取れる
pm := promMiddleware.NewPrometheus("echo", nil)
pm.Use(e)
e.GET("/ping", func(c echo.Context) error {
return c.String(http.StatusOK, "pong")
})
e.Logger.Fatal(e.Start(":1323"))
}
自作のExporterを作る
Golangで簡単にPrometheusのExporterを作れる。 - ry’s Tech blog
prometheus.Collector
interfaceを満たすように作成して登録すればいい。
https://github.com/dgraph-io/ristretto (キャッシュライブラリ)でメトリクスをとってみる
package main
import (
"github.com/dgraph-io/ristretto"
"github.com/prometheus/client_golang/prometheus"
)
// CacheStatsCollector implements the prometheus.Collector interface.
type CacheStatsCollector struct {
cache *ristretto.Cache
// descriptions of exported metrics
hitsDesc *prometheus.Desc
missesDesc *prometheus.Desc
keysAddedDesc *prometheus.Desc
keysUpdatedDesc *prometheus.Desc
keysEvictedDesc *prometheus.Desc
costAddedDesc *prometheus.Desc
costEvictedDesc *prometheus.Desc
getsDroppedDesc *prometheus.Desc
getsKeptDesc *prometheus.Desc
ratioDesc *prometheus.Desc
lifeExpectancySecondsDesc *prometheus.Desc
}
// NewCacheStatsCollector for prometheus.
func NewCacheStatsCollector(cache *ristretto.Cache) *CacheStatsCollector {
labels := prometheus.Labels{"name": "ristretto"}
return &CacheStatsCollector{
cache: cache,
hitsDesc: prometheus.NewDesc("ristretto_hits_total", "The number of hits in the cache.", nil, labels),
missesDesc: prometheus.NewDesc("ristretto_misses_total", "The number of misses in the cache.", nil, labels),
keysAddedDesc: prometheus.NewDesc("ristretto_keys_added", "The number of keys added in the cache.", nil, labels),
keysUpdatedDesc: prometheus.NewDesc("ristretto_keys_updated", "The number of keys updated in the cache.", nil, labels),
keysEvictedDesc: prometheus.NewDesc("ristretto_keys_evicted", "The number of keys evicted in the cache.", nil, labels),
costAddedDesc: prometheus.NewDesc("ristretto_cost_added", "The number of cost added in the cache.", nil, labels),
costEvictedDesc: prometheus.NewDesc("ristretto_cost_evicted", "The number of cost evicted in the cache.", nil, labels),
getsDroppedDesc: prometheus.NewDesc("ristretto_gets_dropped", "The number of gets dropped in the cache.", nil, labels),
getsKeptDesc: prometheus.NewDesc("ristretto_gets_kept", "The number of gets kept in the cache.", nil, labels),
ratioDesc: prometheus.NewDesc("ristretto_ratio", "The hit ratio of the cache.", nil, labels),
lifeExpectancySecondsDesc: prometheus.NewDesc("ristretto_life_expectancy_seconds", "The seconds of life expectancy of the cache.", nil, labels),
}
}
// Describe implements the prometheus.Collector interface.
func (c CacheStatsCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.hitsDesc
ch <- c.missesDesc
ch <- c.keysAddedDesc
ch <- c.keysUpdatedDesc
ch <- c.keysEvictedDesc
ch <- c.costAddedDesc
ch <- c.costEvictedDesc
ch <- c.getsDroppedDesc
ch <- c.getsKeptDesc
ch <- c.ratioDesc
ch <- c.lifeExpectancySecondsDesc
}
// Collect implements the prometheus.Collector interface.
func (c CacheStatsCollector) Collect(ch chan<- prometheus.Metric) {
metrics := c.cache.Metrics
ch <- prometheus.MustNewConstMetric(c.hitsDesc, prometheus.CounterValue, float64(metrics.Hits()))
ch <- prometheus.MustNewConstMetric(c.missesDesc, prometheus.CounterValue, float64(metrics.Misses()))
ch <- prometheus.MustNewConstMetric(c.keysAddedDesc, prometheus.CounterValue, float64(metrics.KeysAdded()))
ch <- prometheus.MustNewConstMetric(c.keysUpdatedDesc, prometheus.CounterValue, float64(metrics.KeysUpdated()))
ch <- prometheus.MustNewConstMetric(c.keysEvictedDesc, prometheus.CounterValue, float64(metrics.KeysEvicted()))
ch <- prometheus.MustNewConstMetric(c.costAddedDesc, prometheus.CounterValue, float64(metrics.CostAdded()))
ch <- prometheus.MustNewConstMetric(c.costEvictedDesc, prometheus.CounterValue, float64(metrics.CostEvicted()))
ch <- prometheus.MustNewConstMetric(c.getsDroppedDesc, prometheus.CounterValue, float64(metrics.GetsDropped()))
ch <- prometheus.MustNewConstMetric(c.getsKeptDesc, prometheus.CounterValue, float64(metrics.GetsKept()))
ch <- prometheus.MustNewConstMetric(c.ratioDesc, prometheus.CounterValue, float64(metrics.Ratio()))
ch <- prometheus.MustNewConstMetric(c.lifeExpectancySecondsDesc, prometheus.CounterValue, float64(metrics.LifeExpectancySeconds().Count))
}
func main() {
cache, _ := ristretto.NewCache(&ristretto.Config{
NumCounters: 10000,
MaxCost: 100000,
BufferItems: 64,
Metrics: true,
})
collector := NewCacheStatsCollector(cache)
prometheus.MustRegister(collector)
http.Handle("/metrics", promhttp.Handler())
http.Handle("/set", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
k := r.URL.Query().Get("key")
v := r.URL.Query().Get("value")
cache.Set(k, v, 1)
}))
http.Handle("/get", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
k := r.URL.Query().Get("key")
if v, ok := cache.Get(k); ok {
vs, _ := v.(string)
w.Write([]byte(vs))
}
}))
http.ListenAndServe(":2112", nil)
}
$ curl 'localhost:2112/set?key=foo&value=bar'
$ curl localhost:2112/metrics
# HELP ristretto_misses_total The number of misses in the cache.
# TYPE ristretto_misses_total counter
ristretto_misses_total{name="ristretto"} 1
# HELP ristretto_ratio The hit ratio of the cache.
# TYPE ristretto_ratio counter
ristretto_ratio{name="ristretto"} 0
$ curl 'localhost:2112/get?key=foo&value=bar'
bar
$ curl localhost:2112/metrics | rg 'ristretto'
# HELP ristretto_misses_total The number of misses in the cache.
# TYPE ristretto_misses_total counter
ristretto_misses_total{name="ristretto"} 1
# HELP ristretto_ratio The hit ratio of the cache.
# TYPE ristretto_ratio counter
ristretto_ratio{name="ristretto"} 0.5