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 序列,导致日志解析失败。