如何使用uber-go/zap根据日志级别分别输出到stdout和stderr?
解决zap日志按级别输出到不同流的问题
问题原因
zap.Config的ErrorOutputPaths参数仅用于输出zap库自身的内部错误,并非用来存放业务代码打印的Error/Fatal级业务日志,所以你之前的配置会让所有业务日志都输出到OutputPaths配置的路径中,无法实现分级输出。
正确实现方案
直接通过zapcore.Core自定义多核心组合实现,代码示例如下:
package main import ( "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) func main() { // 1. 定义编码器配置,和你原配置规则保持一致 encoderConfig := zapcore.EncoderConfig{ MessageKey: "message", LevelKey: "level", EncodeLevel: zapcore.CapitalLevelEncoder, TimeKey: "time", EncodeTime: zapcore.ISO8601TimeEncoder, CallerKey: "caller", EncodeCaller: zapcore.ShortCallerEncoder, EncodeDuration: zapcore.MillisDurationEncoder, } encoder := zapcore.NewJSONEncoder(encoderConfig) // 2. 定义两个输出流 stdout := zapcore.AddSync(os.Stdout) stderr := zapcore.AddSync(os.Stderr) // 3. 分别定义两个Core的级别过滤规则 // stdout仅输出Info级别日志,如有需要可自行调整判断条件包含Debug、Warn等其他级别 stdoutLevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool { return l == zapcore.InfoLevel }) // stderr输出Error及以上级别日志(含Error、Fatal、Panic) stderrLevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool { return l >= zapcore.ErrorLevel }) // 4. 组合两个Core core := zapcore.NewTee( zapcore.NewCore(encoder, stdout, stdoutLevel), zapcore.NewCore(encoder, stderr, stderrLevel), ) // 5. 构建Logger,添加调用者信息等配置 logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) defer logger.Sync() // 测试示例 logger.Info("这是Info日志,会输出到stdout") logger.Error("这是Error日志,会输出到stderr") logger.Fatal("这是Fatal日志,会输出到stderr") }
扩展说明
- 如果需要调整不同级别对应的输出流,只需要修改两个
LevelEnablerFunc的判断逻辑即可,比如要把Warn级别也输出到stdout,只需要把stdout的判断条件改为return l <= zapcore.WarnLevel即可。 - 如果需要使用预设的生产/开发配置,可以先调用
zap.NewProductionConfig()或zap.NewDevelopmentConfig()获取预设的EncoderConfig,再复用上面的核心组合逻辑即可。
内容的提问来源于stack exchange,提问作者Yury Zakharov
相关产品推荐
相关产品推荐

