gin.logger()默认不兼容logrus,需手动实现logrusmiddleware中间件,传入*logrus.logger实例,提取请求信息并用withfields记录,注意hook线程安全及初始化顺序。

gin.Logger() 默认中间件不兼容 logrus
直接用 gin.Logger() 会走 Gin 自带的 log 标准库实现,和 logrus 完全无关。哪怕你项目里 import 了 github.com/sirupsen/logrus,也不会自动接管日志输出——这是最常被误以为“已集成”的坑。
替换 gin.Logger() 需手动构造 logrus-aware 中间件
核心是写一个符合 gin.HandlerFunc 签名、内部调用 logrus 实例的函数,并确保它能拿到请求上下文、耗时、状态码等关键字段。不要试图 patch gin.Logger 源码或重命名导入。
- 必须用
logrus.New()或全局*logrus.Logger实例,避免混用logrus.包级函数(它们共享全局状态,不利于测试和隔离) - 从
c.Request提取c.ClientIP()、c.Request.URL.Path、c.Request.Method等字段,传给logrus.WithFields() - 在
defer里记录耗时:用time.Now()打点,响应后计算差值,别依赖c.Writer.Size()(它可能为 -1) - 状态码要从
c.Writer.Status()获取,不是c.Writer.Status字段(后者未导出)
func LogrusMiddleware(logger *logrus.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
latency := time.Since(start)
statusCode := c.Writer.Status()
clientIP := c.ClientIP()
method := c.Request.Method
path := c.Request.URL.Path
fields := logrus.Fields{
"status_code": statusCode,
"latency": latency.String(),
"client_ip": clientIP,
"method": method,
"path": path,
}
if len(c.Errors) > 0 {
fields["errors"] = c.Errors.ByType(gin.ErrorTypePrivate).String()
}
if statusCode >= 400 {
logger.WithFields(fields).Warn("http request")
} else {
logger.WithFields(fields).Info("http request")
}
}
}
注意 Hook 和 Formatter 的线程安全边界
如果你在中间件里用了 logrus.AddHook()(比如推送到 ES),得确认该 Hook 实现本身是并发安全的。很多自定义 Hook 会内部缓存连接或 channel,但没加锁——当高并发请求触发大量日志时,容易 panic 或丢日志。
- 避免在 Hook 的
Fire()方法里做阻塞操作(如 HTTP 同步调用),改用带缓冲的 channel + 单独 goroutine 消费 - 若用
logrus.JSONFormatter,记得设DisableTimestamp: false(默认是 true),否则时间字段为空 - 不要在中间件里反复调用
logrus.SetFormatter()或SetOutput(),这会影响所有 goroutine 共享的全局 logger
与封装层 logger 包共存时的初始化顺序
如果你项目已按「抽象接口 + 实现分离」方式封装了 logger 包(例如暴露 logger.Info()),那么 Gin 中间件必须接收该封装后的实例,而不是裸的 *logrus.Logger。否则就破环了封装目标。
- 中间件函数签名应为
func(logger.Interface) gin.HandlerFunc,其中logger.Interface是你定义的最小接口(含Info()、Warn()等) - 在
main()初始化时,先构建底层logrus实例,再注入到封装层,最后传给中间件——顺序错乱会导致中间件拿到 nil 或未配置好的 logger - 切忌在
init()里初始化 logger 并赋值给全局变量,Gin 路由启动前无法保证其 ready
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











