iris中间件必须为func(ctx iris.context)类型且调用ctx.next(),需手动recordstarttime()并在next()后获取statuscode()和getduration(),推荐使用app.logger()结构化日志并按路由分组启用。

中间件函数签名必须返回 iris.Handler
直接写一个普通函数(比如 func logRequest())是无效的,Iris 中间件必须符合 iris.Handler 类型,也就是 func(ctx iris.Context)。漏掉 ctx iris.Context 参数或返回值不为空,会导致编译失败或运行时 panic。
常见错误:把日志逻辑写成独立工具函数后直接传给 Use(),结果程序启动就报 cannot use ... (type func()) as type iris.Handler。
- 正确写法:
app.Use(func(ctx iris.Context) { /* 日志逻辑 */ ctx.Next() }) - 必须调用
ctx.Next(),否则请求链中断,后续 handler 不执行 - 若需异步记录(如写文件/发 HTTP),建议用 goroutine 包裹日志逻辑,但注意避免捕获
ctx引用导致数据竞争
记录请求时间、状态码和路径要用 ctx.RecordStartTime() 和 ctx.StatusCode()
Iris 的 Context 不像其他框架在结束时自动暴露耗时和状态码,必须手动触发计时起点,并在 Next() 后读取最终状态码 —— 因为 ctx.StatusCode() 在 Next() 前始终返回 0。
典型误区:在 Next() 前读 ctx.StatusCode(),日志里全是 0;或忘了调用 ctx.RecordStartTime(),导致 ctx.GetDuration() 返回零值。
- 务必在中间件开头调用
ctx.RecordStartTime() - 在
ctx.Next()之后获取ctx.StatusCode()和ctx.GetDuration() -
ctx.Path()可直接获取路由路径,但注意它不含查询参数;如需完整 URL,用ctx.Request().RequestURI
生产环境别用 fmt.Printf 写日志,改用 app.Logger().Infof
Iris 自带结构化 logger(基于 zerolog),支持级别控制、JSON 输出、输出到文件等。直接 fmt.Printf 会混入标准输出,无法统一管理,也丢失时间戳、level 等元信息。
更隐蔽的问题:多个 goroutine 并发写 os.Stdout 可能导致日志行错乱(比如两行日志粘连),而 app.Logger() 是线程安全的。
- 启用 JSON 日志:
app.Logger().SetLevel(iris.LogInfo)+app.Logger().Output(os.Stdout)(或重定向到文件) - 记录字段示例:
app.Logger().Infof("method=%s path=%s status=%d duration=%v", ctx.Method(), ctx.Path(), ctx.StatusCode(), ctx.GetDuration()) - 避免在日志中拼接敏感字段(如
ctx.PostValue("password")),防止泄露
按路由分组启用日志中间件,而不是全局 Use
不是所有路由都需要详细访问日志 —— 健康检查 /health、静态资源、WebSocket 升级请求等高频低价值路径,全量记录会快速撑爆磁盘或拖慢响应。
全局 app.Use(logMiddleware) 最容易实现,但也最粗暴。实际项目应优先考虑分组控制。
- 对 API 组启用:
api := app.Party("/api"); api.Use(logMiddleware) - 排除特定路径:
app.Get("/health", healthHandler)(不套中间件) - 若需动态开关(如调试期开启全部日志),可用配置项控制是否调用
Use(),而非在中间件内部加 if 判断
Iris 日志中间件真正难的不是写几行代码,而是决定哪些字段值得记、在哪一级别记、以及怎么不让日志本身成为性能瓶颈 —— 尤其当 ctx.GetBody() 或 ctx.FormFile() 被误读进日志时,内存和延迟问题会立刻浮现。











