英文:
How to log to stdout or stderr based on log level using uber-go/zap?
问题
我正在尝试使用这个包github.com/uber-go/zap
来设置日志记录。
我需要将以下内容写入日志:
- 将信息日志写入标准输出(stdout)
- 将错误和致命错误日志写入标准错误(stderr)
我尝试通过设置和构建zap.Config
来实现:
cfg = &zap.Config{
Encoding: "json",
Level: zap.NewAtomicLevelAt(zapcore.DebugLevel),
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
EncoderConfig: zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
EncodeLevel: zapcore.CapitalLevelEncoder,
TimeKey: "time",
EncodeTime: zapcore.ISO8601TimeEncoder,
CallerKey: "caller",
EncodeCaller: zapcore.ShortCallerEncoder,
EncodeDuration: zapcore.MillisDurationEncoder,
},
}
我还尝试了这种方式:
cfg = zap.NewProductionConfig()
cfg.OutputPaths = []string{"stdout"}
logger, err = cfg.Build(zap.AddCaller(), zap.AddCallerSkip(1))
但是所有的日志都被写入了stdout 或者 stderr。我该如何分开写入日志呢?
英文:
I am trying to set up logging using this package github.com/uber-go/zap
.
I need to write:
- Info logs to stdout
- Error and Fatal logs to stderr
I tried to do this by setting up and building zap.Config
like this:
cfg = &zap.Config{
Encoding: "json",
Level: zap.NewAtomicLevelAt(zapcore.DebugLevel),
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
EncoderConfig: zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
EncodeLevel: zapcore.CapitalLevelEncoder,
TimeKey: "time",
EncodeTime: zapcore.ISO8601TimeEncoder,
CallerKey: "caller",
EncodeCaller: zapcore.ShortCallerEncoder,
EncodeDuration: zapcore.MillisDurationEncoder,
},
}
Also I tried this way:
cfg = zap.NewProductionConfig()
cfg.OutputPaths = []string{"stdout"}
logger, err = cfg.Build(zap.AddCaller(), zap.AddCallerSkip(1))
But all logs are written to either stdout or stderr. How can I separate it?
答案1
得分: 6
使用zapcore.NewTee
和两个核心:
- 一个将
zapcore.InfoLevel
锁定到stdout - 一个将
zapcore.ErrorLevel
和zapcore.FatalLevel
锁定到stderr
这是一个演示用法的最小程序:
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
func main() {
// info level enabler
infoLevel := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level == zapcore.InfoLevel
})
// error and fatal level enabler
errorFatalLevel := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level == zapcore.ErrorLevel || level == zapcore.FatalLevel
})
// write syncers
stdoutSyncer := zapcore.Lock(os.Stdout)
stderrSyncer := zapcore.Lock(os.Stderr)
// tee core
core := zapcore.NewTee(
zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
stdoutSyncer,
infoLevel,
),
zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
stderrSyncer,
errorFatalLevel,
),
)
// finally construct the logger with the tee core
logger := zap.New(core)
logger.Info("info log")
logger.Error("error log")
}
请注意,上面的程序记录了两条消息,一条是info级别的,一条是error级别的。要查看它们是否正确地打印到了相应的设备上,请运行程序并将stdout或stderr重定向到/dev/null
,这样只会在控制台上打印另一条消息:
$ go build main.go
$ ./main 2>/dev/null # 仅显示stdout
{"level":"info","ts":1626900981.520349,"msg":"info log"}
$ ./main 1>/dev/null # 仅显示stderr
{"level":"error","ts":1626901025.056065,"msg":"error log"}
英文:
Use zapcore.NewTee
with two cores:
- one that locks
zapcore.InfoLevel
to stdout - one that locks
zapcore.ErrorLevel
andzapcore.FatalLevel
to stderr
This is a minimal program to demonstrate the usage:
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
func main() {
// info level enabler
infoLevel := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level == zapcore.InfoLevel
})
// error and fatal level enabler
errorFatalLevel := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level == zapcore.ErrorLevel || level == zapcore.FatalLevel
})
// write syncers
stdoutSyncer := zapcore.Lock(os.Stdout)
stderrSyncer := zapcore.Lock(os.Stderr)
// tee core
core := zapcore.NewTee(
zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
stdoutSyncer,
infoLevel,
),
zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
stderrSyncer,
errorFatalLevel,
),
)
// finally construct the logger with the tee core
logger := zap.New(core)
logger.Info("info log")
logger.Error("error log")
}
Note that the program above logs two messages, one at info level and one at error level. To see that it prints both to the correct device, run it and redirect stdout or stderr to /dev/null
— thus printing to the console only the other one:
$ go build main.go
$ ./main 2>/dev/null # shows only stdout
{"level":"info","ts":1626900981.520349,"msg":"info log"}
$ ./main 1>/dev/null # shows only stderr
{"level":"error","ts":1626901025.056065,"msg":"error log"}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论