sequence

This paper mainly studies uber’s zap’s NewProduction.

Golang’s logs include Zap, Logrus, and others, although Logrus is now in maintenance.

The instance

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,
	)
}
Copy the code

SugaredLogger is 4-10 times faster than a normal structured logging package

The output

{" level ", "info", "ts" : 1607095287.638658, "caller" : "the log - demo/zap_demo. Go: 14", "MSG" : "failed to fetch URL","url":"https://abc.com","attempt":3,"backoff":1}Copy the code

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),
	)
}
Copy the code

Logger is used for scenarios where performance and type-safety requirements are high. It is faster than SugaredLogger, but it only supports structured logging

The output

{" level ", "info", "ts" : 1607095675.5623732, "caller" : "the log - demo/zap_demo. Go: 25", "MSG" : "failed to fetch URL","url":"https://abc.com","attempt":3,"backoff":1}Copy the code

NewProduction

[email protected] / logger. Go

func NewProduction(options ... Option) (*Logger, error) { return NewProductionConfig().Build(options...) }Copy the code

NewProduction executes the NewProductionConfig().build method internally

NewProductionConfig

[email protected] / 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"},
	}
}
Copy the code

The NewProductionConfig method creates Config with the default parameters, where encoding is JSON and output is STD

NewProductionEncoderConfig

[email protected] / 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,
	}
}
Copy the code

NewProductionEncoderConfig created here zapcore EncoderConfig

Build

[email protected] / 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 }Copy the code

Build method executes cfg.buildEncoder(), cfg.openSinks(), zapcore.newcore and New methods

New

[email protected] / 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, } }Copy the code

So here NewNop is returned for core nil, otherwise instantiate Logger; NewNop returns logger core as zapCore.newnopCore ()

Logger

[email protected] / 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
}
Copy the code

Logger defines core, development, name, errorOutput, addCaller, addStack, callerSkip, and onFatal attributes

summary

Zap. NewProduction () by creating NewProductionEncoderConfig again Build a Logger, set up a core, among which the New methods in the Logger errorOutput, addStack attribute

doc

  • zap
  • How to implement level based logging in golang?