You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 18:13:17