Logrus是支持多级别且可插拔格式化的结构化日志库,非多级别格式化工具;Info未输出主因是SetLevel设为WarnLevel及以上;开发用DebugLevel、生产用InfoLevel或WarnLevel;TextFormatter适合终端调试,JSONFormatter适配日志平台;通过WithFields预置trace_id等字段;容器中需SetOutput(os.Stdout)并避免os.Exit。

Logrus 本身不是“多级别日志格式化工具”,而是支持多级别(Debug/Info/Warn/Err/Fatal/Panic)且可插拔格式化的结构化日志库;它不自动“格式化级别”,而是靠 SetLevel 控制输出阈值,靠 SetFormatter 控制每条日志的呈现方式。
为什么 logrus.Info("x") 没输出?检查 SetLevel 是否太严格
默认日志级别是 InfoLevel,但很多项目初始化时误设为 WarnLevel 或更高,导致 Info、Debug 被静默丢弃。
- 用
logrus.GetLevel()现场确认当前生效级别 - 开发环境建议设为
logrus.DebugLevel,生产环境再切回logrus.InfoLevel或logrus.WarnLevel - 别依赖全局
logrus.SetLevel后就不管——微服务常有多个 logger 实例(如按模块拆分),每个都要单独SetLevel - 环境变量驱动更可靠:
if os.Getenv("ENV") == "dev" { log.SetLevel(logrus.DebugLevel) }
TextFormatter 和 JSONFormatter 怎么选?看下游消费方
不是“哪个更好”,而是“谁在读日志”。终端调试用 TextFormatter,日志平台采集用 JSONFormatter。
-
TextFormatter:开箱带颜色、调用文件行号、时间戳,默认启用FullTimestamp和DisableSorting更易读;但DisableColors: true必须显式设,否则 CI/CD 环境可能乱码 -
JSONFormatter:字段固定("level"、"msg"、"time"),无颜色无换行,适合 Logstash/Elasticsearch/K8s 日志采集器;但调试时一行 JSON 不易扫读,别在本地开发用它 - 别混用:同一个 logger 实例不能同时设两种 formatter,切换需重新
SetFormatter
如何让每条日志自动带上 trace_id、service_name?用 WithFields + 全局 entry
手动在每个 log.WithFields(...).Info() 里传 trace_id 既啰嗦又易漏。正确做法是预置一个带默认字段的 *logrus.Entry。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
立即学习“go语言免费学习笔记(深入)”;
- 不要直接改全局
logrus.StandardLogger()的Entry——它不支持默认字段 - 创建模块级 logger:
svcLogger := logrus.WithFields(logrus.Fields{"service": "auth", "env": os.Getenv("ENV")}) - HTTP 中间件注入 trace_id:
reqCtx := context.WithValue(r.Context(), "trace_id", uuid.New().String()),再用中间件把该值塞进logrus.Entry并透传 - 注意:嵌套调用时避免字段覆盖,
WithFields是浅拷贝,重复 key 会覆盖上层值
微服务部署后日志突然变少或格式错乱?检查 SetOutput 和缓冲区刷新
本地跑得好,K8s 里日志断续或缺字段,大概率是输出目标没配对,或进程退出前缓冲未刷出。
- 容器环境必须设
logrus.SetOutput(os.Stdout),否则默认写os.Stderr可能被截断或丢弃 - 若写文件,要用
lumberjack.Logger做轮转,且确保Write是同步的;异步写法(如 goroutine 包裹)需自己管理 flush - logrus 没有内置
Sync()方法,若用os.Stdout可忽略;但写文件时,进程退出前应defer file.Close(),或封装带Flush()的 writer - 关键点:别用
os.Exit(0)结束服务——它绕过 defer;改用return让 defer 生效
最常被忽略的是:logrus 默认不保证字段顺序(TextFormatter 下尤其明显),若你依赖日志行中某个字段总在固定位置做 grep 或正则提取,得加 DisableSorting: true 并接受字段顺序由 map 迭代决定(Go 1.12+ 是伪随机,不可控)。

















