Beego中间件可记录请求耗时但需手动集成Prometheus或ELK实现监控;须在ctx.Next()前后打点、用time.Now()计算,注册为全局BeforRouter过滤器并注意静态文件和状态码获取时机。

Beego 的中间件(过滤器)能直接记录请求耗时,但原生不带指标上报能力;要真正做性能监控,得自己集成 Prometheus 或写日志后由 ELK 处理。
用 ctx.Next() 拦截并计算耗时
Beego 的过滤器本质是函数,在 ctx.Next() 前后打点即可拿到完整处理时间。注意:必须在 ctx.Next() 之后读取响应状态和耗时,否则控制器还没执行完。
-
ctx.Next()不是“继续执行”,而是触发后续过滤器链 + 控制器逻辑的入口点 - 耗时应基于
time.Now(),别用time.Since()在ctx.Next()前调用,否则结果不准 - 不要在过滤器里直接
panic或return,否则ctx.Next()后的代码不会执行,耗时统计就断了
示例:
func LogDurationFilter(ctx *context.Context) {
start := time.Now()
ctx.Next() // 必须放这里
duration := time.Since(start)
log.Printf("[DURATION] %s %s %v", ctx.Request.Method, ctx.Request.URL.Path, duration)
}
注册过滤器时注意作用域和顺序
Beego 过滤器分全局、控制器级、方法级,注册位置决定它是否生效。性能监控类过滤器通常注册为全局,但要注意顺序——比如日志过滤器如果放在认证过滤器后面,就可能漏掉 401 请求的耗时。
- 全局过滤器用
web.InsertFilter("/*", web.BeforRouter, LogDurationFilter) - 匹配路径用
"/*"而不是"/",否则静态文件或 API 前缀(如/api/v1/xxx)可能被忽略 - 如果同时用了 CORS、Auth、Log 三类过滤器,
LogDurationFilter应放在最外层(即BeforRouter),才能覆盖所有路径
把耗时数据导出到 Prometheus
Beego 自身没有 metrics 模块,需手动用 prometheus/client_golang 注册指标。关键点是:指标对象(如 promhttp.Handler())不能和 Beego 的路由冲突,要单独开一个监控端口或复用 admin 端口。
- 定义
prometheus.HistogramVec记录耗时,标签建议包含method、path、status - 在过滤器里调用
histogram.WithLabelValues(...).Observe(duration.Seconds()) - 暴露指标接口:启动时加一行
http.Handle("/metrics", promhttp.Handler()),但别挂到 Beego 路由下,否则会被过滤器拦截导致重复计时 - 若已开启
beego.EnableAdmin = true,可把/metrics注册到 admin server 上(监听AdminHttpAddr:AdminHttpPort),避免端口冲突
容易被忽略的细节
耗时统计看似简单,但在真实服务中常因几个细节失效:
- 静态文件(如
/static/xxx.js)默认不走控制器,但会进BeforRouter过滤器——如果你没在过滤器里判断ctx.Input.IsStatic(),就会把大量小文件耗时混进 P95 统计 - Beego 的
ctx.ResponseWriter.Status在ctx.Next()后才可用,但某些错误(如 panic)会导致状态码仍是 0,需配合recover()捕获 - 如果启用了 Gzip 中间件,响应体大小和耗时需在压缩后读取,否则
ctx.ResponseWriter.Size()返回的是未压缩字节数











