文主要研究一下uber的zap的NewProduction。git
golang的log有 zap、 logrus等,不過logrus如今已經處於維護狀態。
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倍
輸出github
{"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}
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
輸出golang
{"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}
zap@v1.16.0/logger.gojson
func NewProduction(options ...Option) (*Logger, error) { return NewProductionConfig().Build(options...) }
NewProduction內部執行NewProductionConfig().Build方法
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
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
zap@v1.16.0/config.gofetch
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方法
zap@v1.16.0/logger.goui
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()
zap@v1.16.0/logger.gourl
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屬性code