文次要钻研一下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?