# Gin集成Prometheus
prometheus
是一款开源的监控和告警系统,它可以帮助你收集和存储各种指标数据,并提供查询和可视化功能。Gin
是一款高性能的 Go 语言 Web 框架,它可以用来构建高性能的 Web 应用程序。 在本教程中,我们将介绍如何在 Gin
集成 Prometheus
来收集和存储该应用程序的指标数据。
# 初始化prometheus
服务
package service
import (
"os"
"gitea.fbbmore.com/goweb/fsdk-go/fsdkutils"
"github.com/prometheus/client_golang/prometheus"
)
// 全局获取主机名称
var HostName, _ = os.Hostname()
var (
// 定义一个容器名称的 Gauge
NexcoContainer = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "nexco_container",
Help: "Gauge of container name.",
},
[]string{"ip"},
)
// 定义一个 HTTP 请求计数器
NexcoHttpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "nexco_http_requests_total",
Help: "Total number of HTTP requests processed, partitioned by status code and method.",
},
[]string{"method", "path", "status"},
)
// 定义一个 HTTP 请求处理时间的直方图
NexcoHttpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "nexco_http_request_duration_seconds",
Help: "Histogram of HTTP request durations in seconds.",
Buckets: prometheus.DefBuckets, // 可以自定义桶
},
[]string{"method", "path", "status"},
)
)
func init() {
// 定义全局标签
podLabel := prometheus.Labels{"container": HostName}
// 包装默认注册器,添加统一的 container 标签
registry := prometheus.WrapRegistererWith(podLabel, prometheus.DefaultRegisterer)
// 设置容器的ip
NexcoContainer.WithLabelValues(fsdkutils.MustIPv4()).Set(1)
// 注册指标
registry.MustRegister(NexcoContainer)
registry.MustRegister(NexcoHttpRequestsTotal)
registry.MustRegister(NexcoHttpRequestDuration)
}
NexcoContainer
是一个GaugeVec
类型的指标,它用于表示容器的名称。我们使用WithLabelValues
方法为该指标添加了一个标签,标签的值为当前主机的 IP 地址。NexcoHttpRequestsTotal
是一个CounterVec
类型的指标,它用于表示 HTTP 请求的总数。我们使用WithLabelValues
方法为该指标添加了三个标签,分别是请求的方法、路径和状态码。NexcoHttpRequestDuration
是一个HistogramVec
类型的指标,它用于表示 HTTP 请求的处理时间。我们使用WithLabelValues
方法为该指标添加了三个标签,分别是请求的方法、路径和状态码。- 在初始化的时候,首先给这些注册器添加了一个全局标签
container
,然后使用WrapRegistererWith
方法包装了默认的注册器,这样在注册指标的时候,就会自动添加这个全局标签。 - 最后将这些指标注册到
prometheus.DefaultRegisterer
中。这样,这些指标就可以被 Prometheus 收集和存储了。
# 上报指标数据
上面的代码中,我们定义了三个指标,但是并没有将它们的数据上报到 Prometheus。接下来,我们需要在应用程序中添加一些代码,将这些指标的数据上报到 Prometheus。
package middleware
import (
"strconv"
"time"
"gitea.fbbmore.com/goweb/nexco/api/internal/service"
"github.com/gin-gonic/gin"
)
func PrometheusMiddleware(svc *service.Service) gin.HandlerFunc {
return func(ctx *gin.Context) {
start := time.Now()
// 处理请求
ctx.Next()
duration := time.Since(start).Seconds()
status := ctx.Writer.Status()
method := ctx.Request.Method
path := ctx.Request.URL.Path
// 更新指标
service.NexcoHttpRequestsTotal.WithLabelValues(method, path, strconv.Itoa(status)).Inc()
service.NexcoHttpRequestDuration.WithLabelValues(method, path, strconv.Itoa(status)).Observe(duration)
}
}
// 全局使用中间件
engine.Use(
middleware.RecoveryMiddleware(svc), // panic recovery
middleware.PrometheusMiddleware(svc), // prometheus监控
middleware.TraceIdMiddleware(svc), // 全局请求ID生成
middleware.CorsMiddleware(svc), // 允许跨域请求
middleware.RequestBodyCacheMiddleware(svc), // 请求body缓存
middleware.RequestLoggerMiddleware(svc), // 请求日志记录
middleware.RateLimitMiddleware(svc), // 限流处理
)
- 在上面的代码中,我们定义了一个
PrometheusMiddleware
中间件,它会在每个请求处理之前和之后更新指标数据。 - 在请求处理之前,我们记录了请求开始的时间。
- 在请求处理之后,我们记录了请求结束的时间,并计算了请求的处理时间。
- 然后,我们使用
WithLabelValues
方法为指标添加了标签,并使用Inc
方法更新了NexcoHttpRequestsTotal
指标的值。这个指标表示 HTTP 请求的总数。 - 使用
Observe
方法更新了NexcoHttpRequestDuration
指标的值。这个指标表示 HTTP 请求的处理时间。 - 最后,我们将这个中间件添加到 Gin 的路由中,这样每个请求都会经过这个中间件,并更新指标数据。
# 暴露指标数据
在应用程序中定义了指标之后,我们需要将这些指标暴露给 Prometheus,以便 Prometheus 可以收集和存储这些指标。在 Go 中,我们可以使用 promhttp
包来暴露指标数据。
package handler
import (
"net/http"
"gitea.fbbmore.com/goweb/nexco/api/internal/service"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func init() {
routes = append(routes, prometheusRoutes...)
}
var prometheusRoutes = []Route{
{
Method: http.MethodGet,
Path: "/metrics",
Handler: PrometheusHandler,
},
}
func PrometheusHandler(svc *service.Service) gin.HandlerFunc {
return gin.WrapH(promhttp.Handler())
}
- 在上面的代码中,我们定义了一个
PrometheusHandler
函数,它返回一个gin.HandlerFunc
,这个函数会使用promhttp.Handler()
函数来创建一个 HTTP 处理器,这个处理器会将指标数据暴露给 Prometheus。 - 然后,我们将这个处理器添加到 Gin 的路由中,这样当用户访问
/metrics
路径时,Prometheus 就可以收集和存储指标数据了。