package middleware import ( "strconv" "time" "github.com/gin-gonic/gin" "lokistack/pkg/metrics" ) // Metrics 采集 HTTP 层指标。 // // 关键点:path 标签用 **c.FullPath()(路由模板)**而不是原始 URL。 // 原始 URL 带 ID/UUID,每个值都会新建一条时间序列 → Prometheus 基数爆炸 // (本平台有 117 个 Deployment,光 /deployments/:id 就能炸出上千条)。 func Metrics() gin.HandlerFunc { return func(c *gin.Context) { // 抓取端点与健康检查不计入,否则监控自身的流量会污染 QPS path := c.FullPath() if path == "/api/v1/metrics" || path == "/api/v1/health" { c.Next() return } metrics.IncInFlight() start := time.Now() c.Next() metrics.DecInFlight() label := path if label == "" { // 未匹配到路由(404),统一归到一个标签,避免任意 URL 打爆基数 label = "unmatched" } metrics.ObserveHTTP(c.Request.Method, label, c.Writer.Status(), time.Since(start).Seconds()) } } // statusClass 给日志/看板用的状态分类(保留工具函数) func statusClass(code int) string { switch { case code < 300: return "2xx" case code < 400: return "3xx" case code < 500: return "4xx" default: return "5xx" } } var _ = strconv.Itoa