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