sequence

This paper mainly studies the hook of Golang’s Zap

The instance

func hookDemo() {
	count := &atomic.Int64{}
	logger, _ := zap.NewProduction(zap.Hooks(func(entry zapcore.Entry) error {
		fmt.Println("count:", count.Inc(), "msg:", entry.Message)
		return nil
	}))
	defer logger.Sync() // flushes buffer, if any
	sugar := logger.Sugar()
	sugar.Infow("failed to fetch URL",
		// Structured context as loosely typed key-value pairs.
		"url", "https://golang.org",
		"attempt", 3,
		"backoff", time.Second,
	)
	sugar.Info("hello world")
}
Copy the code

The output

{" level ", "info", "ts" : 1608045721.769727, "caller" : "zap/zap_demo. Go: 29", "MSG" : "failed to fetch URL","url":"https://golang.org","attempt":3,"backoff":1} count: 1 msg: Failed to fetch URL {"level":"info","ts":1608045721.769826," Caller ":"zap/zap_demo.go:35"," MSG ":"hello world"} count: 2 msg: hello worldCopy the code

Hooks

[email protected] / options. Go

func Hooks(hooks ...func(zapcore.Entry) error) Option {
	return optionFunc(func(log *Logger) {
		log.core = zapcore.RegisterHooks(log.core, hooks...)
	})
}
Copy the code

The Hooks method wraps the log core using zapcore.registerhooks

zapcore.RegisterHooks

[email protected] / zapcore/hook. Go

func RegisterHooks(core Core, hooks ... func(Entry) error) Core { funcs := append([]func(Entry) error{}, hooks...) return &hooked{ Core: core, funcs: funcs, } }Copy the code

The RegisterHooks method creates hooked, which hooks assign to the funcs property of hooked

hook

[email protected] / zapcore/hook. Go

type hooked struct { Core funcs []func(Entry) error } func (h *hooked) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { // Let the wrapped Core decide whether to log this message or not. This // also gives the downstream a chance to register itself directly with the // CheckedEntry. if downstream := h.Core.Check(ent, ce); downstream ! = nil { return downstream.AddCore(ent, h) } return ce } func (h *hooked) With(fields []Field) Core { return &hooked{ Core: h.Core.With(fields), funcs: h.funcs, } } func (h *hooked) Write(ent Entry, _ []Field) error { // Since our downstream had a chance to register itself directly with the // CheckedMessage, we don't need to call it here. var err error for i := range h.funcs { err = multierr.Append(err, h.funcs[i](ent)) } return err }Copy the code

Hooked is embedded With Core, which overrides the Check, With, and Write methods. The Check method adds a hooked to the downstream; The Write method iterates through hooks, performing the callback

summary

The Hooks method wraps the log core with zapcore.registerhooks; The RegisterHooks method creates hooked, which assigns the funcs attribute to that hooked; Hooked wraps Core, so you need to register yourself when you Check, and then execute your registered hooks when you Write. You can hook things like metrics, but more complex logic is best done by implementing Zapcore.core.

doc

  • zap