使用uber-go/zap库如何根据日志级别将日志记录到stdout或stderr?

huangapple go评论79阅读模式
英文:

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.ErrorLevelzapcore.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 and zapcore.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"}

huangapple
  • 本文由 发表于 2021年7月21日 23:49:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/68472667.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定