
本文介绍如何在 Go 中使用 logrus 等日志库实现按级别分流输出:INFO 及以上仅输出到 stdout,DEBUG 及以上同时写入带时间戳的文件,解决单 logger 无法差异化路由日志的痛点。
本文介绍如何在 go 中使用 logrus 等日志库实现**按级别分流输出**:info 及以上仅输出到 stdout,debug 及以上同时写入带时间戳的文件,解决单 logger 无法差异化路由日志的痛点。
在 Go 日志实践中,io.MultiWriter 虽能将日志镜像复制到多个 Writer(如文件 + stdout),但它不支持按日志级别分流——即无法让 Debug() 写入文件而 Info() 仅打印到终端。因此,仅用 log.SetOutput(io.MultiWriter(...)) 无法满足题目中「stdout 仅 INFO+、文件记录 DEBUG+」的核心需求。
要真正实现级别感知的多目标输出,推荐使用成熟的结构化日志库 —— Logrus(或其现代替代品 Zap),通过自定义 Hook 实现精准路由:
✅ 推荐方案:Logrus + 自定义 Hook(支持级别分流)
package main
import (
"io"
"log"
"os"
"time"
"github.com/sirupsen/logrus"
)
// LevelFileHook 将指定级别及以上的日志写入文件
type LevelFileHook struct {
writer io.Writer
levels []logrus.Level
}
func (h *LevelFileHook) Fire(entry *logrus.Entry) error {
if !contains(h.levels, entry.Level) {
return nil
}
line, err := entry.String()
if err != nil {
return err
}
_, err = h.writer.Write([]byte(line))
return err
}
func (h *LevelFileHook) Levels() []logrus.Level {
return h.levels
}
func contains(levels []logrus.Level, level logrus.Level) bool {
for _, l := range levels {
if l == level {
return true
}
}
return false
}
func main() {
// 创建带时间戳的文件 Writer
file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 初始化 Logrus
logger := logrus.New()
logger.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: time.RFC3339,
})
// Hook 1:仅 DEBUG 及以上写入文件
logger.AddHook(&LevelFileHook{
writer: file,
levels: []logrus.Level{
logrus.DebugLevel,
logrus.InfoLevel,
logrus.WarnLevel,
logrus.ErrorLevel,
logrus.FatalLevel,
logrus.PanicLevel,
},
})
// Hook 2:仅 INFO 及以上输出到 stdout(可进一步过滤为 INFO+)
logger.AddHook(&LevelFileHook{
writer: os.Stdout,
levels: []logrus.Level{
logrus.InfoLevel,
logrus.WarnLevel,
logrus.ErrorLevel,
logrus.FatalLevel,
logrus.PanicLevel,
},
})
// 使用示例
logger.Debug("Entering some func") // → 仅写入 app.log
logger.Info("Result was: Successful") // → 同时输出到 stdout 和 app.log
}
⚠️ 注意事项
- io.MultiWriter 仅适用于全量镜像(所有日志发往所有目标),不区分级别,故不满足本题要求;
- Logrus 的 AddHook 机制允许每个 Hook 独立声明生效级别,是实现「分级路由」的标准方式;
- 生产环境建议使用 zap(性能更高)或 zerolog,它们同样支持基于 Level 的 Writer 分流;
- 文件写入需注意并发安全(Logrus Hook 默认线程安全),但 os.File 本身支持并发写,无需额外加锁。
✅ 总结
Go 原生 log 包功能有限,无法原生支持分级多输出;Logrus 通过 Hook 扩展机制提供了优雅、可组合的解决方案。只需为不同输出目标注册对应级别的 Hook,即可精准控制每条日志的流向,兼顾可读性、可维护性与生产可用性。











