1 概述
我们经常用Prometheus来采集一些业务数据,通常的做法是在项目里定义相关的label-value结构体,写入数据,然后Prometheus从 /metrics 接口中获取数据,写入时序数据库,然后生成各种图标或进行告警。
2 简单实现
package main
import (
"flag"
"log"
"net/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var addr = flag.String("listen-address", ":8090", "The address to listen on for HTTP requests.")
func main() {
flag.Parse()
http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe(*addr, nil))
}
启动服务后,调用 metrics接口
curl localhost:8090/metrics
#返回:
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
.
.
.
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 8
.
.
.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 0
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0
可以看到,所使用的库有一些默认指标。我们接下来增加自己想要的业务指标。
3 新增指标
package main
import (
"flag"
"fmt"
"log"
"math/rand"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var addr = flag.String("listen-address", ":8090", "The address to listen on for HTTP requests.")
var (
// CityTemperatureGauge Gauge 是一种既可增加也可减少还可设置为指定值的类型,底层为float64。
// 适用指标:并发请求数量、内存使用量、温度等数据。
CityTemperatureGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "city_temperature",
Help: "city temperature",
},
[]string{"city", "temperature"},
)
)
func main() {
flag.Parse()
// 注册新的collector
prometheus.MustRegister(CityTemperatureGauge)
// 往metrics里面写数据
AppendDataToMetrics()
http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe(*addr, nil))
}
// 往metrics里面写数据
func AppendDataToMetrics() {
cityList := []string{"北京", "上海", "广州"}
rand.Seed(time.Now().UnixNano())
for _, city := range cityList {
randomFloat := rand.Float64()*(35-25) + 25
randomFloat = float64(int(randomFloat*10)) / 10
CityTemperatureGauge.WithLabelValues(city, fmt.Sprintf("%.1f", randomFloat)).Set(1)
}
}
启动后,请求 metrics 接口:
# HELP city_temperature city temperature.
# TYPE city_temperature gauge
city_temperature{city="上海",temperature="27.2"} 1
city_temperature{city="北京",temperature="34.6"} 1
city_temperature{city="广州",temperature="31.5"} 1
... 其他默认数据忽略...
这样我们就简单实现了一个业务指标。
4 改写路由
由于metrics接口会返回全量的数据,有时候我们其实不需要那些系统的默认数据,此时可以通过改写路由的方式,来只获取我们所需的那部分数据。
func main() {
flag.Parse()
// new一个注册器
reg := prometheus.NewRegistry()
reg.MustRegister(CityTemperatureGauge)
AppendDataToMetrics()
http.Handle("/metrics", promhttp.Handler())
// 用新路由获取到新注册器的数据
http.Handle("/metrics/cityTemp", promhttp.HandlerFor(
reg,
promhttp.HandlerOpts{
// Opt into OpenMetrics to support exemplars.
EnableOpenMetrics: true,
},
))
log.Fatal(http.ListenAndServe(*addr, nil))
}
请求
curl localhost:8090/metrics # 只返回默认数据
curl localhost:8090/metrics/cityTemp # 只返回 city_temperature 数据