Gin 默认不记录请求日志,直接用 log.Println 或 fmt.Println 错误——混入标准输出、无上下文、不可分级、不支持异步;应优先使用 gin.Logger() 中间件,或升级为 zap + 自定义中间件实现结构化、可追踪、高性能日志。

Gin 默认不记录请求日志,直接用 log.Println 或 fmt.Println 打印是错的——它会混在标准输出里、没上下文、无法分级、也不支持异步写入。
为什么不能直接用 log.Printf 打请求日志
你可能试过在 gin.HandlerFunc 里写 log.Printf("req: %s %s", c.Request.Method, c.Request.URL.Path),看起来能跑,但实际埋了几个坑:
- 日志没有请求 ID,多个并发请求的日志会交错,排查时根本分不清哪条属于哪个请求
- 没捕获响应状态码、耗时、客户端 IP,这些关键指标得自己手动取、自己格式化,容易漏或出错
- 如果日志写到文件,
log包默认是同步写,高并发下会卡住整个 HTTP 处理流程 - 无法按 level(debug/info/warn/error)动态开关,测试环境开着 info,上线后想关掉就得改代码
用 gin.Logger() 中间件是最简方案
这是 Gin 官方提供的中间件,开箱即用,适合开发和轻量生产场景。它默认输出到 os.Stdout,格式固定但清晰:
2024/05/12 14:22:33 | 200 | 1.245µs | 127.0.0.1 | GET "/api/users"
使用方式很简单:
立即学习“go语言免费学习笔记(深入)”;
- 直接调用
r.Use(gin.Logger()),放在路由注册前 - 它自动记录方法、路径、状态码、耗时、客户端 IP 和时间戳
- 不依赖第三方包,无额外依赖,适合快速验证或小项目
- 注意:它不记录请求体、响应体、header,也不支持自定义字段(比如 trace ID)
需要结构化日志或集成 ELK?换 zap + 自定义中间件
当你要把日志发到 Kafka、写入 ES、或者要求 JSON 格式、支持字段打点(如 user_id、trace_id),gin.Logger() 就不够用了。推荐用 uber-go/zap 配合自定义中间件:
- 先初始化一个
*zap.Logger(建议用zap.NewProduction()上线,zap.NewDevelopment()开发) - 中间件里用
c.Request.Context()拿到 trace ID(如果用了gin-contrib/pprof或自己注入过) - 在
c.Next()后读取c.Writer.Status()、c.Writer.Size()、c.Keys等获取真实响应信息 - 避免在日志里直接拼接
c.Request.Body——它只能读一次,再读就为空;要记录 body 得提前用c.Request.Body = ioutil.NopCloser(...)替换,且只在调试时开
示例关键行:
logger.Info("http request",
zap.String("method", c.Request.Method),
zap.String("path", c.Request.URL.Path),
zap.Int("status", c.Writer.Status()),
zap.Int("size", c.Writer.Size()),
zap.String("ip", c.ClientIP()),
zap.Duration("latency", time.Since(start)))
线上禁用 console 日志、别让 gin.DefaultWriter 写磁盘
Gin 默认把日志写到 os.Stdout,本地调试没问题,但线上常被重定向到文件。这时候容易踩两个坑:
-
gin.DefaultWriter是全局变量,多个服务共用一个 writer 时会冲突;应显式传入io.Writer实例(比如lumberjack.Logger) - 直接写文件不加轮转,几天就撑爆磁盘;别用
os.OpenFile简单追加,要用gopkg.in/natefinch/lumberjack.v2控制大小和备份数 - 线上建议关闭
gin.Logger(),只保留业务日志;HTTP 访问日志交给 Nginx 或 APISIX 做更稳妥 - 如果必须 Gin 写,确保
zap的WriteSyncer是异步的(用zapcore.NewMultiWriteSyncer+zapcore.Lock)
真正难的不是怎么打日志,是怎么让每条日志都能对应上一次请求、不丢字段、不拖慢接口、还能在出问题时快速捞出来——这些细节藏在中间件的生命周期控制和 writer 的封装里。


















