5

聊聊zerolog的Hook

 3 years ago
source link: https://studygolang.com/articles/32510
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文主要研究一下zerolog的Hook

Hook

github.com/rs/[email protected]/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参数

LevelHook

github.com/rs/[email protected]/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

HookFunc

github.com/rs/[email protected]/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方法

log.Hook

github.com/rs/[email protected]/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

log.newEvent

github.com/rs/[email protected]/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

msg

github.com/rs/[email protected]/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方法。

doc

有疑问加站长微信联系(非本文作者)

eUjI7rn.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK