// Package observability provides tracer, metrics, and structured logging // initialization for the api-gateway. package observability import ( "strconv" "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) // 业务指标(W5 裁决:7 个业务 metrics) var ( httpRequestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "api_gateway_http_requests_total", Help: "Total number of HTTP requests processed by the gateway.", }, []string{"method", "endpoint", "status"}) httpRequestDurationSeconds = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "api_gateway_http_request_duration_seconds", Help: "HTTP request processing duration in seconds.", Buckets: prometheus.DefBuckets, }, []string{"method", "endpoint"}) circuitBreakerState = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "api_gateway_circuit_breaker_state", Help: "Circuit breaker state by service: 1=active state, 0=inactive.", }, []string{"service", "state"}) rateLimitedTotal = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "api_gateway_rate_limited_total", Help: "Total number of rate-limited requests.", }, []string{"ip"}) proxyUpstreamDurationSeconds = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "api_gateway_proxy_upstream_duration_seconds", Help: "Upstream proxy response duration in seconds.", Buckets: prometheus.DefBuckets, }, []string{"upstream"}) jwksRefreshTotal = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "api_gateway_jwks_refresh_total", Help: "Total number of JWKS cache refresh attempts.", }, []string{"result"}) authFailuresTotal = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "api_gateway_auth_failures_total", Help: "Total number of authentication failures.", }, []string{"reason"}) ) // Metrics 返回 HTTP 请求统计中间件(W5 裁决)。 // 记录请求总数(method/endpoint/status)与请求延迟(method/endpoint)。 // endpoint 使用 gin 路由模式(c.FullPath())避免高基数。 func Metrics() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() c.Next() duration := time.Since(start).Seconds() status := strconv.Itoa(c.Writer.Status()) endpoint := c.FullPath() if endpoint == "" { endpoint = "unknown" } httpRequestsTotal.WithLabelValues(c.Request.Method, endpoint, status).Inc() httpRequestDurationSeconds.WithLabelValues(c.Request.Method, endpoint).Observe(duration) } } // IncAuthFailure 递增鉴权失败计数器。 func IncAuthFailure(reason string) { authFailuresTotal.WithLabelValues(reason).Inc() } // IncRateLimited 递增限流计数器。 func IncRateLimited(ip string) { rateLimitedTotal.WithLabelValues(ip).Inc() } // IncJWKSRefresh 递增 JWKS 刷新计数器(result: success/failure)。 func IncJWKSRefresh(result string) { jwksRefreshTotal.WithLabelValues(result).Inc() } // SetCircuitBreakerState 更新熔断器状态 gauge。 func SetCircuitBreakerState(service, state string, value float64) { circuitBreakerState.WithLabelValues(service, state).Set(value) } // ObserveProxyUpstreamDuration 记录上游代理响应延迟。 func ObserveProxyUpstreamDuration(upstream string, duration time.Duration) { proxyUpstreamDurationSeconds.WithLabelValues(upstream).Observe(duration.Seconds()) }