聊聊zerolog的send

995 阅读2分钟

本文主要研究一下zerolog的send

实例

func sendDemo() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

	log.Info().
		Str("Name", "Tom").
		Send()

	log.Info().
		Str("Name", "Tom").
		Msg("hello world")
}

使用Send或者Msg来发送log

输出

{"level":"info","Name":"Tom","time":1609509525}
{"level":"info","Name":"Tom","time":1609509525,"message":"hello world"}

Send

github.com/rs/zerolog@v1.20.0/event.go

// Send is equivalent to calling Msg("").
//
// NOTICE: once this method is called, the *Event should be disposed.
func (e *Event) Send() {
	if e == nil {
		return
	}
	e.msg("")
}

Send方法相当于Msg("")

msg

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)
		}
	}
}

msg方法先执行hook,之后对于有msg的添加message字段,如果done不为nil则defer注册回调,之后执行e.write()

write

github.com/rs/zerolog@v1.20.0/event.go

func (e *Event) write() (err error) {
	if e == nil {
		return nil
	}
	if e.level != Disabled {
		e.buf = enc.AppendEndMarker(e.buf)
		e.buf = enc.AppendLineBreak(e.buf)
		if e.w != nil {
			_, err = e.w.WriteLevel(e.level, e.buf)
		}
	}
	putEvent(e)
	return
}

write在level不为Disabled的时候会追加endMarker及lineBreaker;对于e.w不为nil时,执行e.w.WriteLevel(e.level, e.buf)进行输出;之后执行putEvent归还event

putEvent

github.com/rs/zerolog@v1.20.0/event.go

func putEvent(e *Event) {
	// Proper usage of a sync.Pool requires each entry to have approximately
	// the same memory cost. To obtain this property when the stored type
	// contains a variably-sized buffer, we add a hard limit on the maximum buffer
	// to place back in the pool.
	//
	// See https://golang.org/issue/23199
	const maxSize = 1 << 16 // 64KiB
	if cap(e.buf) > maxSize {
		return
	}
	eventPool.Put(e)
}

putEvent方法先判断e.buf的大小是否超过maxSize,超过则直接返回,否则执行eventPool.Put(e)将event归还到eventPool中

Info

github.com/rs/zerolog@v1.20.0/log.go

// Info starts a new message with info level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Info() *Event {
	return l.newEvent(InfoLevel, nil)
}

Info方法执行的l.newEvent(InfoLevel, nil)

newEvent

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
}

func newEvent(w LevelWriter, level Level) *Event {
	e := eventPool.Get().(*Event)
	e.buf = e.buf[:0]
	e.ch = nil
	e.buf = enc.AppendBeginMarker(e.buf)
	e.w = w
	e.level = level
	e.stack = false
	return e
}

newEvent方法从eventPool获取Event,然后设置done、hooks等属性

小结

zerolog的Send方法相当于Msg("");newEvent方法从eventPool获取Event,然后设置done、hooks等属性;write在level不为Disabled的时候会追加endMarker及lineBreaker;对于e.w不为nil时,执行e.w.WriteLevel(e.level, e.buf)进行输出;之后执行putEvent归还event;

doc