logrus 已归档不推荐新项目使用,存在原子写入缺陷、hook 并发不安全、字段共享陷阱、颜色污染、缓冲丢日志等问题;生产应禁用 color、强制 stderr 输出、用 JSONFormatter 并调优时间格式。

logrus 不再推荐用于新项目,官方已归档,且存在设计缺陷(如不支持结构化日志的原子写入、hook 并发安全需自行保证);若必须用,务必锁定 v1.9.3 以下版本并禁用 logrus.TextFormatter 的 color 输出(终端不可控时易污染日志流)。
为什么 logrus.SetOutput(os.Stdout) 在 Docker 容器里会丢日志
根本原因是 stdout/stderr 被重定向为管道后,logrus 默认的缓冲行为(尤其搭配 TextFormatter)会触发行缓冲失效,导致部分日志滞留在内存未刷出。更隐蔽的问题是:容器 runtime(如 containerd)对短生命周期进程的日志捕获依赖 flush 行为。
- 强制每条日志后调用
logrus.StandardLogger().Writer().(*os.File).Sync()(仅限 Linux,性能差) - 改用
logrus.SetOutput(os.Stderr)—— 多数容器平台对 stderr 的日志采集更激进 - 彻底规避:用
logrus.SetOutput(&os.File{Fd: uintptr(2)})直接绑定 stderr fd,绕过 Go 的 os.File 缓冲层
logrus.WithFields 的字段覆盖陷阱
logrus 字段不是深拷贝,WithFields 返回的新 logger 共享底层 logrus.Entry 的 data map 指针。若后续修改传入的 map(比如 m := map[string]interface{}{"id": 1}; log.WithFields(m).Info("a"); m["id"] = 2),下一条日志可能输出错误的 id=2。
- 永远用字面量 map:
log.WithFields(logrus.Fields{"id": 1, "user": u.Name}).Info("login") - 避免复用变量传入
WithFields,尤其在 goroutine 中 - 若需动态构造字段,用
log.WithField("key", value).WithField("k2", v2)链式调用(每次新建独立 map)
替换 logrus.TextFormatter 的真正原因
TextFormatter 默认开启 DisableColors 为 false,但它的颜色控制依赖 os.Stdout 是否为 TTY。在 CI/CD 流水线或 systemd 服务中,即使设了 DisableColors: true,某些版本仍会因环境变量 NO_COLOR 未识别而输出 ANSI 序列,导致日志解析失败。
立即学习“go语言免费学习笔记(深入)”;
- 生产环境必须显式设置:
formatter.DisableColors = true且formatter.ForceFormatting = true - 更稳妥的做法是直接换
logrus.JSONFormatter,它不依赖终端能力,字段顺序稳定,兼容 ELK 等日志系统 - 注意
JSONFormatter的TimestampFormat默认是 RFC3339Nano,若下游系统只认秒级时间戳,需手动设为"2006-01-02T15:04:05Z"
logrus 最难 debug 的问题往往不是功能缺失,而是它把日志写到了你没监控到的地方——比如 hook 内部 panic 被吞掉、异步 writer 的 goroutine 泄漏、或者 formatter 对 error 类型的默认字符串化触发了未预期的 Error() 方法调用。上线前务必用 logrus.SetLevel(logrus.DebugLevel) + logrus.SetReportCaller(true) 跑通全链路。










