业务指标上报metrics到prometheus,已经是基操了
实现方式有两种:
- 推送到pushgateway,由prometheus 过来pull pushgateway,进而展示在如grafana
- 启动metrics接口;注入Gin中间件,由prometheus 过来pull metrics指标,进而展示在如grafana
将metrics监控指标推送至 pushgateway
package prometheus
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/push"
)
var (
HttpReqDurationHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: "p_saplat_http_request_duration_seconds",
Help: "Histogram of response latency (seconds) of http responses.",
Buckets: prometheus.LinearBuckets(0.1, 0.1, 10),
}, []string{"route1", "method1", "status_code1"})
TotalRequestsCounter = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p_saplat_http_requests_total",
Help: "Total number of HTTP requests",
}, []string{"route2", "method2", "status_code2"})
)
type PrometheusPusher struct {
pusher *push.Pusher
}
func NewPrometheusPusher(pushGatewayURL, jobName string, labels map[string]string) *PrometheusPusher {
pusher := push.New(pushGatewayURL, jobName)
for key, value := range labels {
pusher = pusher.Grouping(key, value)
}
return &PrometheusPusher{pusher: pusher}
}
func (p *PrometheusPusher) Push() error {
return p.pusher.Push()
}
func (p *PrometheusPusher) AddCollector(collector prometheus.Collector) {
p.pusher.Collector(collector)
}
中间件
package middleware
import (
"fmt"
"strconv"
"time"
"github.com/gin-gonic/gin"
// "github.com/prometheus/client_golang/prometheus/push"
"x.com/saplat/conf"
"x.com/saplat/service/prometheus"
)
func PrometheusPushGatewayMiddleware(pushGatewayURL string) gin.HandlerFunc {
// 静态配置推送标签,可以根据需要在这里添加标签。
promPusher := prometheus.NewPrometheusPusher(pushGatewayURL, "gin_service", map[string]string{
// 如果有全局的标签可以在这里添加
// "label1": "value1",
})
// 如果collector是动态创建的,则可以在接下来注册收集器
// 但在大多数时候我们的collector是预注册的全局变量。
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start)
path := c.Request.URL.Path
method := c.Request.Method
status := strconv.Itoa(c.Writer.Status())
// 注册收集器
promPusher.AddCollector(prometheus.HttpReqDurationHistogram)
promPusher.AddCollector(prometheus.TotalRequestsCounter)
// 更新指标
prometheus.HttpReqDurationHistogram.WithLabelValues(path, method, status).Observe(duration.Seconds())
prometheus.TotalRequestsCounter.WithLabelValues(path, method, status).Inc()
// 推送数据
if err := promPusher.Push(); err != nil {
// 处理这里的错误
fmt.Printf("Could not push metrics to Pushgateway: %v", err)
} else {
fmt.Println("Pushed metrics to Pushgateway")
}
}
}
调用
// Prometheus Push
r.Use(middleware.PrometheusPushGatewayMiddleware(conf.PushGatewayURL))
在pushteway 确认上报情况
推送metrics监控指标至prometheus
package prometheus
import (
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"x.com/saplat/conf"
)
var AppID = conf.AppID
// 请求计数
var TotalRequests = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: fmt.Sprintf("%v_http_requests_total", AppID),
Help: fmt.Sprintf("%v Total number of HTTP requests", AppID),
},
[]string{"method", "endpoint", "status_code","AppID"},
)
// 请求响应时间
var RequestDuration = promauto.NewSummaryVec(
prometheus.SummaryOpts{
Name: fmt.Sprintf("%v_http_request_duration_seconds", AppID),
Help: fmt.Sprintf("%v Summary of the response latency (seconds) of HTTP requests", AppID),
Objectives: map[float64]float64{0.95: 0.01, 0.99: 0.01}, // Objectives定义了我们需要的分位数
},
[]string{"method", "endpoint","AppID"},
)
var TotalRequestsByStatus = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: fmt.Sprintf("%v_http_requests_total_by_status", AppID),
Help: fmt.Sprintf("%v Total number of HTTP requests by status code", AppID),
},
[]string{"status_code","AppID"},
)
中间件
package middleware
import (
"fmt"
"strconv"
"time"
"github.com/gin-gonic/gin"
// "github.com/prometheus/client_golang/prometheus/push"
"x.com/saplat/conf"
"x.com/saplat/service/prometheus"
)
func PrometheusMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
method := c.Request.Method
status := strconv.Itoa(c.Writer.Status())
// 请求开始之前的时间
start := time.Now()
c.Next() // 处理请求
// 请求处理完成后统计响应时间
duration := time.Since(start)
statusCode := strconv.Itoa(c.Writer.Status())
// 收集指标信息
prometheus.TotalRequests.WithLabelValues(method, path, status,conf.AppID).Inc() // 增加请求计数
prometheus.RequestDuration.WithLabelValues(method, path,conf.AppID).Observe(duration.Seconds()) // 统计请求响应时间
prometheus.TotalRequestsByStatus.WithLabelValues(statusCode,conf.AppID).Inc() // 增加对应状态码的计数
}
}
调用
注意,如果多个Gin中间件,需要将r.Use 前置
r.GET("/metrics", gin.WrapH(promhttp.Handler()))
r.Use(middleware.PrometheusMiddleware())