必须在main()开头同步初始化otel.meterprovider,否则所有指标调用静默丢弃;echo不自带/metrics端点,需手动注册promhttp.handler()或otlp exporter,且meterprovider须早于echo.new()初始化。

必须在 main() 开头同步初始化 otel.MeterProvider,否则所有 meter.Int64Counter().Add() 调用都写入 noop 实现,Prometheus 拉不到指标、OTLP exporter 无数据上报——这不是报错问题,是彻底静默丢弃。
为什么 Echo 启动后 metrics 端点返回空或 404
Echo 自身不提供 metrics endpoint,必须手动注册 promhttp.Handler() 或启用 OTLP exporter;且 otel.MeterProvider 必须早于 echo.New() 初始化,否则 echootel.Middleware 内部的指标采集器(如请求计数、延迟直方图)会 fallback 到 noop。
-
echo.Use(echootel.Middleware())依赖全局otel.Meter(),而otel.Meter()又依赖已设置的MeterProvider - 若用 Prometheus,需显式
e.GET("/metrics", echo.WrapHandler(promhttp.Handler())),不能只靠中间件 - 若用 OTLP,
otlpmetricgrpc.NewClient()的 endpoint 必须可连通(如"otel-collector:4317",不是"http://...")
如何让 echootel.Middleware 正确上报 HTTP 指标
echootel.Middleware 默认只采集基础指标(http.server.request.duration, http.server.active_requests),但需满足三个硬性条件才能生效:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 必须在
echo.Use()前完成otel.SetMeterProvider(),且传入的resource包含service.name(否则指标 label 缺失service_name) - 中间件必须注册在所有路由之前,否则
c.FullPath()解析失败,http.routelabel 为空,导致 Prometheus 查询时无法按路径聚合 - 不要同时注册
echohttp.Middleware和echootel.Middleware——后者已包含前者语义,重复注册会导致 counter 重复累加
自定义指标必须绑定到同一 MeterProvider
你在 handler 里调用 meter := otel.Meter("myapp") 创建的 meter,和 echootel.Middleware 内部用的 meter 是同一个实例,前提是 otel.SetMeterProvider() 已执行。否则你看到的永远是 NoopMeter。
- 自定义 Counter 示例:
reqCounter := meter.Int64Counter("http.custom.requests", metric.WithDescription("Total custom requests")) - 调用时必须传 context:
reqCounter.Add(ctx, 1, attribute.String("endpoint", "/api/v1/users")),否则 label 不生效 - 避免在 goroutine 里直接用
context.Background()调用 Add()——这会让指标脱离 trace 上下文,且可能丢失 service 标签
采样率与指标导出器配置强相关
指标不像 trace 那样有采样器概念,但导出器的 batch 间隔、超时、重试策略直接影响上报稳定性:
- OTLP exporter 推荐设
otlpmetricgrpc.WithTimeout(5 * time.Second),默认 10s 容易卡住 HTTP 请求 - Prometheus exporter 不需要额外配置,但需确保
promhttp.Handler()注册在非 root 路径(如/metrics),且不被其他中间件拦截 - 别把
metric.WithInstrumentationVersion("v1.0.0")写死——版本变更会导致 Prometheus 中出现新旧 series 并存,查询混乱
最易被忽略的是:Echo 的 c.Request.Context() 默认不携带任何 metric scope,echootel.Middleware 只负责创建 span 和注入 trace context,不会自动为指标创建 scope。如果你要基于 trace ID 打点指标(比如“这个 trace 下第几次重试”),得手动从 span 中提取 trace ID 并作为 attribute 传入 Add()。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










