如何基于OpenTelemetry标准提取Gin(Golang)指标?
基于OpenTelemetry实现Gin框架指标采集
因为opentelemetry-go-contrib目前还没提供Gin的官方指标采集中间件,你可以通过自定义Gin中间件结合OpenTelemetry的Metric API来实现,下面是具体步骤和代码示例:
1. 初始化OpenTelemetry Meter
首先导入必要的包并全局初始化Meter(OpenTelemetry中用于创建指标的核心组件):
import ( "time" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.20.0" "github.com/gin-gonic/gin" ) // 全局Meter,指定名称用于区分指标来源 var meter = otel.Meter("gin-application-metrics")
2. 编写Gin指标采集中间件
在中间件中捕获请求的完整生命周期,记录核心指标:请求总数、请求耗时、错误请求数,并携带HTTP方法、路由、状态码等维度属性:
func OtelGinMetrics() gin.HandlerFunc { // 预定义三个核心指标 reqCount, _ := meter.Int64Counter( "http.requests.total", metric.WithDescription("Total number of processed HTTP requests"), ) reqDuration, _ := meter.Float64Histogram( "http.request.duration", metric.WithDescription("Duration of HTTP requests in seconds"), metric.WithUnit("s"), ) reqErrors, _ := meter.Int64Counter( "http.request.errors.total", metric.WithDescription("Total number of HTTP requests with status code >= 400"), ) return func(c *gin.Context) { start := time.Now() // 执行后续路由逻辑 c.Next() // 组装请求属性(使用OpenTelemetry标准语义属性,保证兼容性) attrs := []attribute.KeyValue{ semconv.HTTPMethodKey.String(c.Request.Method), semconv.HTTPRouteKey.String(c.FullPath()), semconv.HTTPStatusCodeKey.Int(c.Writer.Status()), } // 更新请求总数指标 reqCount.Add(c.Request.Context(), 1, metric.WithAttributes(attrs...)) // 记录请求耗时 duration := time.Since(start).Seconds() reqDuration.Record(c.Request.Context(), duration, metric.WithAttributes(attrs...)) // 记录错误请求(状态码>=400) if c.Writer.Status() >= 400 { reqErrors.Add(c.Request.Context(), 1, metric.WithAttributes(attrs...)) } } }
3. 注册中间件到Gin路由
将自定义中间件注册到Gin引擎中,注意要放在路由定义前,确保捕获所有请求:
func main() { // 初始化指标导出器(见下一步) initMetricExporter() r := gin.Default() // 注册OpenTelemetry指标中间件 r.Use(OtelGinMetrics()) // 示例路由 r.GET("/api/health", func(c *gin.Context) { c.JSON(200, gin.H{"status": "ok"}) }) r.POST("/api/submit", func(c *gin.Context) { c.JSON(400, gin.H{"error": "invalid params"}) }) _ = r.Run(":8080") }
4. 配置指标导出(以Prometheus为例)
要让采集到的指标能被监控系统获取,需要配置导出器,以下是Prometheus导出的示例:
import ( "net/http" "go.opentelemetry.io/otel/exporters/prometheus" "go.opentelemetry.io/otel/sdk/metric" ) func initMetricExporter() { // 创建Prometheus导出器 exporter, err := prometheus.New() if err != nil { panic(err) } // 设置全局Meter提供者 provider := metric.NewMeterProvider(metric.WithReader(exporter)) otel.SetMeterProvider(provider) // 暴露/metrics端点,供Prometheus采集 go func() { _ = http.ListenAndServe(":9090", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { exporter.ServeHTTP(w, r) })) }() }
关键注意事项
- 优先使用OpenTelemetry标准语义属性(如
semconv.HTTPMethodKey),确保指标与其他系统兼容,便于统一分析。 - 全局Meter只需初始化一次,避免重复创建导致指标混乱。
- 中间件尽量放在Gin的中间件链最前端,保证能捕获所有请求的完整生命周期。
内容的提问来源于stack exchange,提问作者Yash
相关产品推荐
相关产品推荐

