关于golang:聊聊golang的zap的NewProduction

34次阅读

共计 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?

正文完
 0