|
|
package main
|
|
|
|
|
|
import (
|
|
|
"flag"
|
|
|
"log"
|
|
|
"math/rand"
|
|
|
"net/http"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"github.com/gorilla/mux"
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
|
)
|
|
|
|
|
|
var (
|
|
|
addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
|
|
|
)
|
|
|
|
|
|
var (
|
|
|
requestTimes = prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
|
Name: "request_times",
|
|
|
Help: "请求次数",
|
|
|
}, []string{"method", "url", "host"})
|
|
|
// 多个label,需要与requestTimes.WithLabelValues(strings.ToLower(r.Method), r.URL.String())一一对应,
|
|
|
// 效果为可用promql request_times{method="get",url="/metrics",host="172.20.16.185:8080"}查询
|
|
|
|
|
|
requestTime = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
|
|
Name: "request_time",
|
|
|
Help: "每次请求花费的时间",
|
|
|
}, []string{"method", "url", "host"})
|
|
|
|
|
|
// 需要计算,开销大
|
|
|
requestSummary = prometheus.NewSummaryVec(prometheus.SummaryOpts{
|
|
|
Name: "request_time_summary",
|
|
|
Help: "summary test",
|
|
|
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
|
|
// 0.5,0.9,0.99表示分位数,0.05,0.01,0.001表示可接收的误差,比如0.5分位的值为10,其实这个10可能是(0.45,0.55)这个区间内的某个值,太过精确会导致cpu压力过大
|
|
|
}, []string{"request_time"})
|
|
|
|
|
|
// Histogram只计数,不计算,开销小
|
|
|
// 线性桶
|
|
|
requestHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
|
|
Name: "request_time_histogram",
|
|
|
Help: "histogram LinearBuckets test",
|
|
|
Buckets: prometheus.LinearBuckets(1, 2, 20), // 初始为1,间隔为2,一共20个取值,Buckets会隐式添加 `+Inf` 值作为取值区间的最大值
|
|
|
// request_time_histogram_bucket{instance="172.20.16.185:8080", job="my_metrics", le="1.0", request_time="request_time"}
|
|
|
// request_time_histogram_bucket{instance="172.20.16.185:8080", job="my_metrics", le="3.0", request_time="request_time"}
|
|
|
// ...
|
|
|
// 会生成如上所示的指标,le: 小于等于
|
|
|
// 即,比如第一个数据的值,表示为小于等于1.0的个数,此处即为响应时间小于等于1.0的请求的个数
|
|
|
}, []string{"request_time"})
|
|
|
|
|
|
// 默认桶
|
|
|
requestHistogramDef = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
|
|
Name: "request_time_histogram_def_buckets",
|
|
|
Help: "histogram DefBuckets test",
|
|
|
Buckets: prometheus.DefBuckets,
|
|
|
}, []string{"request_time"})
|
|
|
|
|
|
// 指数桶
|
|
|
requestHistogramExponentialBuckets = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
|
|
Name: "request_time_histogram_exponential_buckets",
|
|
|
Help: "histogram ExponentialBuckets test",
|
|
|
Buckets: prometheus.ExponentialBuckets(1, 2, 20), // 初始值为1,指数为2增长,20个取值
|
|
|
}, []string{"request_time"})
|
|
|
// 不同的桶根据具体情况而定
|
|
|
|
|
|
metricsPath = flag.String("web.telemetry-path", "/metrics",
|
|
|
"Path under which to expose metrics")
|
|
|
)
|
|
|
|
|
|
func init() {
|
|
|
// Add Go module build info.
|
|
|
// 也可prometheus.MustRegister(xx, yy)
|
|
|
prometheus.MustRegister(requestTime)
|
|
|
prometheus.MustRegister(requestTimes)
|
|
|
prometheus.MustRegister(requestSummary)
|
|
|
prometheus.MustRegister(requestHistogram, requestHistogramDef, requestHistogramExponentialBuckets)
|
|
|
}
|
|
|
|
|
|
func main() {
|
|
|
flag.Parse()
|
|
|
r := mux.NewRouter()
|
|
|
r.HandleFunc("/", handlerIndex)
|
|
|
r.Use(metricsMiddleware)
|
|
|
|
|
|
r.Handle("/metrics", promhttp.HandlerFor(
|
|
|
prometheus.DefaultGatherer,
|
|
|
promhttp.HandlerOpts{
|
|
|
// Opt into OpenMetrics to support exemplars.
|
|
|
EnableOpenMetrics: true,
|
|
|
},
|
|
|
))
|
|
|
log.Fatal(http.ListenAndServe(*addr, r))
|
|
|
}
|
|
|
|
|
|
func metricsMiddleware(next http.Handler) http.Handler {
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
start := time.Now().Unix()
|
|
|
next.ServeHTTP(w, r)
|
|
|
end := time.Now().Unix()
|
|
|
requestTime.WithLabelValues(strings.ToLower(r.Method), r.URL.String(), r.Host).Set(float64(end - start))
|
|
|
requestTimes.WithLabelValues(strings.ToLower(r.Method), r.URL.String(), r.Host).Add(1)
|
|
|
requestSummary.WithLabelValues("request_time").Observe(float64(end - start))
|
|
|
requestHistogram.WithLabelValues("request_time").Observe(float64(end - start))
|
|
|
requestHistogramDef.WithLabelValues("request_time").Observe(float64(end - start))
|
|
|
requestHistogramExponentialBuckets.WithLabelValues("request_time").Observe(float64(end - start))
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func handlerIndex(w http.ResponseWriter, r *http.Request) {
|
|
|
x := rand.Intn(3)
|
|
|
time.Sleep(time.Duration(x) * time.Second)
|
|
|
//_, _ = w.Write([]byte("handler response"))
|
|
|
_, _ = w.Write([]byte(`<html>
|
|
|
<head><title>SRE Promethus Exporter</title></head>
|
|
|
<body>
|
|
|
<h1>SRE Promethus Exporter</h1>
|
|
|
<p><a href='` + *metricsPath + `'>Metrics</a></p>
|
|
|
</body>
|
|
|
</html>`))
|
|
|
|
|
|
log.Println("print handler index")
|
|
|
}
|
|
|
|
|
|
// 清除数据,各项数据都会清零
|
|
|
func dataClear() {
|
|
|
requestTime.Reset()
|
|
|
requestTimes.Reset()
|
|
|
requestHistogram.Reset()
|
|
|
requestHistogramExponentialBuckets.Reset()
|
|
|
requestHistogramDef.Reset()
|
|
|
requestSummary.Reset()
|
|
|
}
|