必须显式配置信任代理段(如10.0.0.0/8)并调用settrustedproxies,否则c.clientip()返回内网ip而非真实客户端ip;路径需标准化(如归一化/user/:id),避免指标爆炸。

如何在Gin中间件里获取真实请求IP和路径
直接用 c.ClientIP() 会出错——它默认信任 X-Forwarded-For,但没配信任代理时,返回的是负载均衡器或Nginx的内网IP,不是用户真实IP。
必须显式配置信任的代理段,否则统计的“IP分布”全是 10.x.x.x 或 172.x.x.x,完全失真。
- 启动前调用
gin.SetMode(gin.ReleaseMode)避免调试信息干扰日志 - 在
gin.Default()之后立即设置:router.TrustedProxies = []string{"127.0.0.1", "10.0.0.0/8", "172.16.0.0/12"}(按实际反向代理网段调整) - 路径统计别只取
c.Request.URL.Path,要 normalize:去掉查询参数、统一末尾斜杠(如/api/user和/api/user/视为同一接口)
用原子操作+map做轻量级内存计数器是否可靠
单机部署时可以,但要注意 map 并发写 panic 和 key 竞争问题。Go 的 map 本身不支持并发读写,哪怕只增不删也不行。
正确做法是组合 sync.Map + atomic,但 sync.Map 的 LoadOrStore 返回值类型是 interface{},对计数器来说很别扭;更稳妥的是用 sync.RWMutex 包裹普通 map,读多写少场景下性能损耗可忽略。
- key 建议用
net.JoinHostPort(c.ClientIP(), c.Request.Method)拼接,避免纯 IP 统计掩盖方法差异 - 不要用
time.Now().Unix()作时间分桶键——精度太粗;改用time.Now().Truncate(time.Minute)实现分钟级聚合 - 每分钟自动清理过期桶(比如只保留最近 60 分钟),否则内存持续增长
如何把 Gin 请求统计对接 Prometheus
别自己造指标暴露端点。直接用官方维护的 promhttp + promauto,配合 prometheus.CounterVec 按 path、method、status 分维度打点,比手写 HTTP handler 稳定得多。
Gin 中间件里调用 counterVec.WithLabelValues(c.Request.URL.Path, c.Request.Method, strconv.Itoa(c.Writer.Status())).Inc() 即可,注意 status 要在 c.Next() 之后读,否则拿不到真实响应码。
- 暴露指标端点用
http.Handle("/metrics", promhttp.Handler()),别挂在 Gin 路由下——Gin 的 handler 无法兼容http.Handler接口的 ResponseWriter - 如果服务跑在 Kubernetes 里,确保 Service 的
targetPort映射到指标端口(如 9090),否则 Prometheus 抓不到数据 - 避免在
WithLabelValues里传动态路径(如/user/123),会导致指标 cardinality 爆炸;先用正则归一化成/user/:id
为什么日志埋点统计和 Prometheus 结果对不上
根本原因是日志写入有延迟、丢行、缓冲,而 Prometheus 是 pull 模型,抓取瞬间的内存指标快照。两者不是同一数据源,强行对齐反而误导排查。
真正该做的是分层验证:用 Prometheus 看趋势和异常突刺,用日志查具体某次请求的完整上下文(如耗时、错误堆栈)。如果发现某分钟 Prometheus 计数比 Nginx access log 少 20%,大概率是中间某层(如 ALB、WAF)拦截了请求,根本没到 Gin。
- 检查
c.Writer.Status()是否总为 0 —— 是的话说明中间件 panic 了,响应没写出,Prometheus 没法捕获 - 确认
log.Println类日志没被 stdout 缓冲区截断(加log.SetFlags(0)和log.SetOutput(os.Stderr)提高可靠性) - 流量统计类逻辑尽量靠近入口,在
c.Next()前就完成 IP/path 提取,避免后续中间件修改c.Request导致数据错乱
真实环境里,IP 识别、指标维度、数据源一致性这三点,任何一个没对齐,统计结果就失去参考价值。别指望写完中间件就自动得到准确数字。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











