本文主要研究一下zerolog的Hook
github.com/rs/zerolog@v1.20.0/hook.go
// Hook defines an interface to a log hook. type Hook interface { // Run runs the hook with the event. Run(e *Event, level Level, message string) }
Hook接口定义了Run方法,它接收event、level、message参数
github.com/rs/zerolog@v1.20.0/hook.go
// LevelHook applies a different hook for each level. type LevelHook struct { NoLevelHook, TraceHook, DebugHook, InfoHook, WarnHook, ErrorHook, FatalHook, PanicHook Hook } // Run implements the Hook interface. func (h LevelHook) Run(e *Event, level Level, message string) { switch level { case TraceLevel: if h.TraceHook != nil { h.TraceHook.Run(e, level, message) } case DebugLevel: if h.DebugHook != nil { h.DebugHook.Run(e, level, message) } case InfoLevel: if h.InfoHook != nil { h.InfoHook.Run(e, level, message) } case WarnLevel: if h.WarnHook != nil { h.WarnHook.Run(e, level, message) } case ErrorLevel: if h.ErrorHook != nil { h.ErrorHook.Run(e, level, message) } case FatalLevel: if h.FatalHook != nil { h.FatalHook.Run(e, level, message) } case PanicLevel: if h.PanicHook != nil { h.PanicHook.Run(e, level, message) } case NoLevel: if h.NoLevelHook != nil { h.NoLevelHook.Run(e, level, message) } } } // NewLevelHook returns a new LevelHook. func NewLevelHook() LevelHook { return LevelHook{} }
LevelHook定义了各种level的hook,其Run方法根据指定的level执行指定的hook
github.com/rs/zerolog@v1.20.0/hook.go
// HookFunc is an adaptor to allow the use of an ordinary function // as a Hook. type HookFunc func(e *Event, level Level, message string) // Run implements the Hook interface. func (h HookFunc) Run(e *Event, level Level, message string) { h(e, level, message) }
HookFunc是个func类型,它实现了Hook接口的Run方法
github.com/rs/zerolog@v1.20.0/log.go
type Logger struct { w LevelWriter level Level sampler Sampler context []byte hooks []Hook } // Hook returns a logger with the h Hook. func (l Logger) Hook(h Hook) Logger { l.hooks = append(l.hooks, h) return l }
log.Hook方法用于注册hook
github.com/rs/zerolog@v1.20.0/log.go
func (l *Logger) newEvent(level Level, done func(string)) *Event { enabled := l.should(level) if !enabled { return nil } e := newEvent(l.w, level) e.done = done e.ch = l.hooks if level != NoLevel { e.Str(LevelFieldName, LevelFieldMarshalFunc(level)) } if l.context != nil && len(l.context) > 1 { e.buf = enc.AppendObjectData(e.buf, l.context) } return e }
log.newEvent方法在创建event的时候会把自己的hooks拷贝给event
github.com/rs/zerolog@v1.20.0/event.go
func (e *Event) msg(msg string) { for _, hook := range e.ch { hook.Run(e, e.level, msg) } if msg != "" { e.buf = enc.AppendString(enc.AppendKey(e.buf, MessageFieldName), msg) } if e.done != nil { defer e.done(msg) } if err := e.write(); err != nil { if ErrorHandler != nil { ErrorHandler(err) } else { fmt.Fprintf(os.Stderr, "zerolog: could not write event: %v\n", err) } } }
event的msg方法会遍历event的hooks,然后挨个执行Hook的Run方法
type SeverityHook struct{} func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) { if level != zerolog.NoLevel { e.Str("abc", "form hook") } } func hookDemo() { hooked := log.Hook(SeverityHook{}) hooked.Warn().Msg("hello") }
输出
{"level":"warn","time":"2021-01-07T23:07:13+08:00","abc":"form hook","message":"hello"}
zerolog提供了Hook接口,用于修改event;log.Hook方法用于注册hook;log.newEvent方法在创建event的时候会把自己的hooks拷贝给event;event的msg方法会遍历event的hooks,然后挨个执行Hook的Run方法。