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