当前位置:网站首页>聊聊golang的zap的NewExample

聊聊golang的zap的NewExample

2020-12-07 23:31:59 go4it

本文主要研究一下golang的zap的NewExample

NewExample

zap@v1.16.0/logger.go

func NewExample(options ...Option) *Logger {
	encoderCfg := zapcore.EncoderConfig{
		MessageKey:     "msg",
		LevelKey:       "level",
		NameKey:        "logger",
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
	}
	core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel)
	return New(core).WithOptions(options...)
}

NewExample使用通过core来创建Logger,其中core使用的Encoder为JSONEncoder,WriteSyncer使用的是os.Stdout,LevelEnabler使用的是DebugLevel;使用的JSONEncoder的zapcore.EncoderConfig其EncodeLevel为zapcore.LowercaseLevelEncoder,其TimeEncoder为zapcore.ISO8601TimeEncoder,,其DurationEncoder为zapcore.StringDurationEncoder

encoder

zap@v1.16.0/zapcore/encoder.go

func LowercaseLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
	enc.AppendString(l.String())
}

func ISO8601TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
	encodeTimeLayout(t, "2006-01-02T15:04:05.000Z0700", enc)
}

func StringDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
	enc.AppendString(d.String())
}

LowercaseLevelEncoder使用小写打印log level;ISO8601TimeEncoder使用2006-01-02T15:04:05.000Z0700格式打印时间;StringDurationEncoder使用Duration内置的String()打印time.Duration

NewJSONEncoder

zap@v1.16.0/zapcore/json_encoder.go

func NewJSONEncoder(cfg EncoderConfig) Encoder {
	return newJSONEncoder(cfg, false)
}

func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder {
	return &jsonEncoder{
		EncoderConfig: &cfg,
		buf:           bufferpool.Get(),
		spaced:        spaced,
	}
}

func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
	final := enc.clone()
	final.buf.AppendByte('{')

	if final.LevelKey != "" {
		final.addKey(final.LevelKey)
		cur := final.buf.Len()
		final.EncodeLevel(ent.Level, final)
		if cur == final.buf.Len() {
			// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
			// output JSON valid.
			final.AppendString(ent.Level.String())
		}
	}
	if final.TimeKey != "" {
		final.AddTime(final.TimeKey, ent.Time)
	}
	if ent.LoggerName != "" && final.NameKey != "" {
		final.addKey(final.NameKey)
		cur := final.buf.Len()
		nameEncoder := final.EncodeName

		// if no name encoder provided, fall back to FullNameEncoder for backwards
		// compatibility
		if nameEncoder == nil {
			nameEncoder = FullNameEncoder
		}

		nameEncoder(ent.LoggerName, final)
		if cur == final.buf.Len() {
			// User-supplied EncodeName was a no-op. Fall back to strings to
			// keep output JSON valid.
			final.AppendString(ent.LoggerName)
		}
	}
	if ent.Caller.Defined {
		if final.CallerKey != "" {
			final.addKey(final.CallerKey)
			cur := final.buf.Len()
			final.EncodeCaller(ent.Caller, final)
			if cur == final.buf.Len() {
				// User-supplied EncodeCaller was a no-op. Fall back to strings to
				// keep output JSON valid.
				final.AppendString(ent.Caller.String())
			}
		}
		if final.FunctionKey != "" {
			final.addKey(final.FunctionKey)
			final.AppendString(ent.Caller.Function)
		}
	}
	if final.MessageKey != "" {
		final.addKey(enc.MessageKey)
		final.AppendString(ent.Message)
	}
	if enc.buf.Len() > 0 {
		final.addElementSeparator()
		final.buf.Write(enc.buf.Bytes())
	}
	addFields(final, fields)
	final.closeOpenNamespaces()
	if ent.Stack != "" && final.StacktraceKey != "" {
		final.AddString(final.StacktraceKey, ent.Stack)
	}
	final.buf.AppendByte('}')
	if final.LineEnding != "" {
		final.buf.AppendString(final.LineEnding)
	} else {
		final.buf.AppendString(DefaultLineEnding)
	}

	ret := final.buf
	putJSONEncoder(final)
	return ret, nil
}

NewJSONEncoder创建的是jsonEncoder;其EncodeEntry方法一次打印LevelKey、TimeKey、LoggerName、Caller,最后才是业务的message本身,然后结束json打印,对于有stacktrace还会以非json的形式(普通堆栈形式)打印stacktrace

实例

func exampleDemo() {
	logger := zap.NewExample()
	defer logger.Sync() // flushes buffer, if any
	sugar := logger.Sugar()
	sugar.Info("this will be logged")
	sugar.Info("time=", time.Now())
	sugar.Panic("test panic")
}

输出

{"level":"info","msg":"this will be logged"}
{"level":"info","msg":"time=2020-12-07 23:14:48.50402 +0800 CST m=+0.000602110"}
{"level":"panic","msg":"test panic"}
panic: test panic

goroutine 1 [running]:
go.uber.org/zap/zapcore.(*CheckedEntry).Write(0xc0001680c0, 0x0, 0x0, 0x0)
        /go/pkg/mod/go.uber.org/zap@v1.16.0/zapcore/entry.go:234 +0x585
go.uber.org/zap.(*SugaredLogger).log(0xc000179e98, 0xc000054e04, 0x0, 0x0, 0xc000179ea0, 0x1, 0x1, 0x0, 0x0, 0x0)
        /go/pkg/mod/go.uber.org/zap@v1.16.0/sugar.go:234 +0xf6
go.uber.org/zap.(*SugaredLogger).Panic(...)
        /go/pkg/mod/go.uber.org/zap@v1.16.0/sugar.go:123
main.exampleDemo()
        /zap_demo.go:19 +0x277
main.main()
        /zap_demo.go:10 +0x25
exit status 2

小结

NewExample使用通过core来创建Logger,其中core使用的Encoder为JSONEncoder,WriteSyncer使用的是os.Stdout,LevelEnabler使用的是DebugLevel;NewJSONEncoder创建的是jsonEncoder;其EncodeEntry方法一次打印LevelKey、TimeKey、LoggerName、Caller,最后才是业务的message本身,然后结束json打印,对于有stacktrace还会以非json的形式(普通堆栈形式)打印stacktrace

doc

版权声明
本文为[go4it]所创,转载请带上原文链接,感谢
https://my.oschina.net/go4it/blog/4780141