共计 3409 个字符,预计需要花费 9 分钟才能阅读完成。
序
文次要钻研一下 uber 的 zap 的 NewProduction。
golang 的 log 有 zap、logrus 等,不过 logrus 当初曾经处于保护状态。
实例
SugaredLogger
func main() {logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
url := "https://abc.com"
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
}
SugaredLogger 比一般的结构化 logging 包快 4 -10 倍
输入
{"level":"info","ts":1607095287.638658,"caller":"log-demo/zap_demo.go:14","msg":"failed to fetch URL","url":"https://abc.com","attempt":3,"backoff":1}
Logger
func main() {logger, _ := zap.NewProduction()
defer logger.Sync()
url := "https://abc.com"
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
}
当对性能和类型平安都要求比拟高的场景就应用 Logger,它比 SugaredLogger 速度更快,然而它只反对结构化 logging
输入
{"level":"info","ts":1607095675.5623732,"caller":"log-demo/zap_demo.go:25","msg":"failed to fetch URL","url":"https://abc.com","attempt":3,"backoff":1}
NewProduction
zap@v1.16.0/logger.go
func NewProduction(options ...Option) (*Logger, error) {return NewProductionConfig().Build(options...)
}
NewProduction 外部执行 NewProductionConfig().Build 办法
NewProductionConfig
zap@v1.16.0/config.go
func NewProductionConfig() Config {
return Config{Level: NewAtomicLevelAt(InfoLevel),
Development: false,
Sampling: &SamplingConfig{
Initial: 100,
Thereafter: 100,
},
Encoding: "json",
EncoderConfig: NewProductionEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
NewProductionConfig 办法按默认参数创立了 Config,其中 encoding 为 json,output 为 std
NewProductionEncoderConfig
zap@v1.16.0/config.go
func NewProductionEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
FunctionKey: zapcore.OmitKey,
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.EpochTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
NewProductionEncoderConfig 这里创立了 zapcore.EncoderConfig
Build
zap@v1.16.0/config.go
func (cfg Config) Build(opts ...Option) (*Logger, error) {enc, err := cfg.buildEncoder()
if err != nil {return nil, err}
sink, errSink, err := cfg.openSinks()
if err != nil {return nil, err}
if cfg.Level == (AtomicLevel{}) {return nil, fmt.Errorf("missing Level")
}
log := New(zapcore.NewCore(enc, sink, cfg.Level),
cfg.buildOptions(errSink)...,
)
if len(opts) > 0 {log = log.WithOptions(opts...)
}
return log, nil
}
Build 办法执行 cfg.buildEncoder()、cfg.openSinks()、zapcore.NewCore 及 New 办法
New
zap@v1.16.0/logger.go
func New(core zapcore.Core, options ...Option) *Logger {
if core == nil {return NewNop()
}
log := &Logger{
core: core,
errorOutput: zapcore.Lock(os.Stderr),
addStack: zapcore.FatalLevel + 1,
}
return log.WithOptions(options...)
}
func NewNop() *Logger {
return &Logger{core: zapcore.NewNopCore(),
errorOutput: zapcore.AddSync(ioutil.Discard),
addStack: zapcore.FatalLevel + 1,
}
}
这里对于 core 为 nil 的返回的是 NewNop,否则实例化 Logger;NewNop 返回的 logger 的 core 为 zapcore.NewNopCore()
Logger
zap@v1.16.0/logger.go
type Logger struct {
core zapcore.Core
development bool
name string
errorOutput zapcore.WriteSyncer
addCaller bool
addStack zapcore.LevelEnabler
callerSkip int
onFatal zapcore.CheckWriteAction // default is WriteThenFatal
}
Logger 定义了 core、development、name、errorOutput、addCaller、addStack、callerSkip、onFatal 属性
小结
zap.NewProduction() 通过创立 NewProductionEncoderConfig 再 Build 出 Logger,其中 Logger 的 New 办法次要设置了 core、errorOutput、addStack 属性
doc
- zap
- How to implement level based logging in golang?