go_study/fabric-main/vendor/github.com/sykesm/zap-logfmt/encoder.go

528 lines
13 KiB
Go

// Package zaplogfmt provides a zap encoder that formats log entries in
// "logfmt" format.
package zaplogfmt
import (
"bytes"
"encoding"
"encoding/base64"
"encoding/json"
"fmt"
"math"
"reflect"
"strings"
"sync"
"time"
"unicode/utf8"
"go.uber.org/zap/buffer"
"go.uber.org/zap/zapcore"
)
var (
logfmtPool = sync.Pool{
New: func() interface{} { return &logfmtEncoder{} },
}
bufferpool = buffer.NewPool()
)
func getEncoder() *logfmtEncoder {
return logfmtPool.Get().(*logfmtEncoder)
}
func putEncoder(enc *logfmtEncoder) {
enc.EncoderConfig = nil
enc.buf = nil
enc.namespaces = nil
enc.arrayLiteral = false
logfmtPool.Put(enc)
}
type logfmtEncoder struct {
*zapcore.EncoderConfig
buf *buffer.Buffer
namespaces []string
arrayLiteral bool
}
// NewEncoder creates an encoder writes logfmt formatted log entries.
func NewEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder {
return &logfmtEncoder{
EncoderConfig: &cfg,
buf: bufferpool.Get(),
}
}
func (enc *logfmtEncoder) AddArray(key string, arr zapcore.ArrayMarshaler) error {
enc.addKey(key)
return enc.AppendArray(arr)
}
func (enc *logfmtEncoder) AddBinary(key string, value []byte) {
enc.AddString(key, base64.StdEncoding.EncodeToString(value))
}
func (enc *logfmtEncoder) AddBool(key string, value bool) {
enc.addKey(key)
enc.AppendBool(value)
}
func (enc *logfmtEncoder) AddByteString(key string, value []byte) {
enc.addKey(key)
enc.AppendByteString(value)
}
func (enc *logfmtEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) }
func (enc *logfmtEncoder) AddComplex128(key string, value complex128) {
enc.addKey(key)
enc.AppendComplex128(value)
}
func (enc *logfmtEncoder) AddDuration(key string, value time.Duration) {
enc.addKey(key)
enc.AppendDuration(value)
}
func (enc *logfmtEncoder) AddFloat32(key string, value float32) {
enc.addKey(key)
enc.AppendFloat32(value)
}
func (enc *logfmtEncoder) AddFloat64(key string, value float64) {
enc.addKey(key)
enc.AppendFloat64(value)
}
func (enc *logfmtEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) }
func (enc *logfmtEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) }
func (enc *logfmtEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) }
func (enc *logfmtEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) }
func (enc *logfmtEncoder) AddInt64(key string, value int64) {
enc.addKey(key)
enc.AppendInt64(value)
}
func (enc *logfmtEncoder) AddObject(key string, obj zapcore.ObjectMarshaler) error {
enc.addKey(key)
return enc.AppendObject(obj)
}
func (enc *logfmtEncoder) AddReflected(key string, value interface{}) error {
enc.addKey(key)
return enc.AppendReflected(value)
}
func (enc *logfmtEncoder) AddString(key, value string) {
enc.addKey(key)
enc.AppendString(value)
}
func (enc *logfmtEncoder) AddTime(key string, value time.Time) {
enc.addKey(key)
enc.AppendTime(value)
}
func (enc *logfmtEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) }
func (enc *logfmtEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) }
func (enc *logfmtEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) }
func (enc *logfmtEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) }
func (enc *logfmtEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) }
func (enc *logfmtEncoder) AddUint64(key string, value uint64) {
enc.addKey(key)
enc.AppendUint64(value)
}
func (enc *logfmtEncoder) AppendArray(arr zapcore.ArrayMarshaler) error {
marshaler := enc.clone()
marshaler.namespaces = nil
marshaler.arrayLiteral = true
marshaler.buf.AppendByte('[')
err := arr.MarshalLogArray(marshaler)
if err == nil {
marshaler.buf.AppendByte(']')
enc.AppendByteString(marshaler.buf.Bytes())
} else {
enc.AppendByteString(nil)
}
marshaler.buf.Free()
putEncoder(marshaler)
return err
}
func (enc *logfmtEncoder) AppendBool(value bool) {
if value {
enc.AppendString("true")
} else {
enc.AppendString("false")
}
}
func (enc *logfmtEncoder) AppendByteString(value []byte) {
enc.addSeparator()
needsQuotes := bytes.IndexFunc(value, needsQuotedValueRune) != -1
if needsQuotes {
enc.buf.AppendByte('"')
}
enc.safeAddByteString(value)
if needsQuotes {
enc.buf.AppendByte('"')
}
}
func (enc *logfmtEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) }
func (enc *logfmtEncoder) AppendComplex128(value complex128) {
enc.addSeparator()
// Cast to a platform-independent, fixed-size type.
r, i := float64(real(value)), float64(imag(value))
enc.buf.AppendFloat(r, 64)
enc.buf.AppendByte('+')
enc.buf.AppendFloat(i, 64)
enc.buf.AppendByte('i')
}
func (enc *logfmtEncoder) AppendDuration(value time.Duration) {
cur := enc.buf.Len()
if enc.EncodeDuration != nil {
enc.EncodeDuration(value, enc)
}
if cur == enc.buf.Len() {
enc.AppendInt64(int64(value))
}
}
func (enc *logfmtEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) }
func (enc *logfmtEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) }
func (enc *logfmtEncoder) appendFloat(val float64, bitSize int) {
enc.addSeparator()
switch {
case math.IsNaN(val):
enc.buf.AppendString(`NaN`)
case math.IsInf(val, 1):
enc.buf.AppendString(`+Inf`)
case math.IsInf(val, -1):
enc.buf.AppendString(`-Inf`)
default:
enc.buf.AppendFloat(val, bitSize)
}
}
func (enc *logfmtEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) }
func (enc *logfmtEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) }
func (enc *logfmtEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) }
func (enc *logfmtEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) }
func (enc *logfmtEncoder) AppendInt64(value int64) {
enc.addSeparator()
enc.buf.AppendInt(value)
}
func (enc *logfmtEncoder) AppendObject(obj zapcore.ObjectMarshaler) error {
marshaler := enc.clone()
marshaler.namespaces = nil
err := obj.MarshalLogObject(marshaler)
if err == nil {
enc.AppendByteString(marshaler.buf.Bytes())
} else {
enc.AppendByteString(nil)
}
marshaler.buf.Free()
putEncoder(marshaler)
return err
}
func (enc *logfmtEncoder) AppendReflected(value interface{}) error {
switch v := value.(type) {
case nil:
enc.AppendString("null")
case error:
enc.AppendString(v.Error())
case []byte:
enc.AppendByteString(v)
case fmt.Stringer:
enc.AppendString(v.String())
case encoding.TextMarshaler:
b, err := v.MarshalText()
if err != nil {
return err
}
enc.AppendString(string(b))
case json.Marshaler:
b, err := v.MarshalJSON()
if err != nil {
return err
}
enc.AppendString(string(b))
default:
rvalue := reflect.ValueOf(value)
switch rvalue.Kind() {
case reflect.Bool:
enc.AppendBool(rvalue.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
enc.AppendInt64(rvalue.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
enc.AppendUint64(rvalue.Uint())
case reflect.Float32:
enc.appendFloat(rvalue.Float(), 32)
case reflect.Float64:
enc.AppendFloat64(rvalue.Float())
case reflect.String:
enc.AppendString(rvalue.String())
case reflect.Complex64, reflect.Complex128:
enc.AppendComplex128(rvalue.Complex())
case reflect.Chan, reflect.Func:
enc.AppendString(fmt.Sprintf("%T(%p)", value, value))
case reflect.Map, reflect.Struct:
enc.AppendString(fmt.Sprint(value))
case reflect.Array, reflect.Slice:
enc.AppendArray(zapcore.ArrayMarshalerFunc(func(ae zapcore.ArrayEncoder) error {
for i := 0; i < rvalue.Len(); i++ {
ae.AppendReflected(rvalue.Index(i).Interface())
}
return nil
}))
case reflect.Interface, reflect.Ptr:
return enc.AppendReflected(rvalue.Elem().Interface())
}
}
return nil
}
func (enc *logfmtEncoder) AppendString(value string) {
enc.addSeparator()
needsQuotes := strings.IndexFunc(value, needsQuotedValueRune) != -1
if needsQuotes {
enc.buf.AppendByte('"')
}
enc.safeAddString(value)
if needsQuotes {
enc.buf.AppendByte('"')
}
}
func (enc *logfmtEncoder) AppendTime(value time.Time) {
cur := enc.buf.Len()
if enc.EncodeTime != nil {
enc.EncodeTime(value, enc)
}
if cur == enc.buf.Len() {
enc.AppendInt64(value.UnixNano())
}
}
func (enc *logfmtEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) }
func (enc *logfmtEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) }
func (enc *logfmtEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) }
func (enc *logfmtEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) }
func (enc *logfmtEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) }
func (enc *logfmtEncoder) AppendUint64(value uint64) {
enc.addSeparator()
enc.buf.AppendUint(value)
}
func (enc *logfmtEncoder) Clone() zapcore.Encoder {
clone := enc.clone()
clone.buf.Write(enc.buf.Bytes())
return clone
}
func (enc *logfmtEncoder) clone() *logfmtEncoder {
clone := getEncoder()
clone.EncoderConfig = enc.EncoderConfig
clone.buf = bufferpool.Get()
clone.namespaces = enc.namespaces
return clone
}
func (enc *logfmtEncoder) OpenNamespace(key string) {
key = strings.Map(keyRuneFilter, key)
enc.namespaces = append(enc.namespaces, key)
}
func (enc *logfmtEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
final := enc.clone()
if final.TimeKey != "" {
final.AddTime(final.TimeKey, ent.Time)
}
if final.LevelKey != "" {
final.addKey(final.LevelKey)
cur := final.buf.Len()
if final.EncodeLevel != nil {
final.EncodeLevel(ent.Level, final)
}
if cur == final.buf.Len() {
// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
// output valid.
final.AppendString(ent.Level.String())
}
}
if ent.LoggerName != "" && final.NameKey != "" {
final.addKey(final.NameKey)
cur := final.buf.Len()
if final.EncodeName != nil {
final.EncodeName(ent.LoggerName, final)
}
if cur == final.buf.Len() {
// User-supplied EncodeName was a no-op. Fall back to strings to
// keep output valid.
final.AppendString(ent.LoggerName)
}
}
if ent.Caller.Defined && final.CallerKey != "" {
final.addKey(final.CallerKey)
cur := final.buf.Len()
if final.EncodeCaller != nil {
final.EncodeCaller(ent.Caller, final)
}
if cur == final.buf.Len() {
// User-supplied EncodeCaller was a no-op. Fall back to strings to
// keep output valid.
final.AppendString(ent.Caller.String())
}
}
if final.MessageKey != "" {
final.addKey(enc.MessageKey)
final.AppendString(ent.Message)
}
if enc.buf.Len() > 0 {
if final.buf.Len() > 0 {
final.buf.AppendByte(' ')
}
final.buf.Write(enc.buf.Bytes())
}
addFields(final, fields)
if ent.Stack != "" && final.StacktraceKey != "" {
final.AddString(final.StacktraceKey, ent.Stack)
}
if final.LineEnding != "" {
final.buf.AppendString(final.LineEnding)
} else {
final.buf.AppendString(zapcore.DefaultLineEnding)
}
ret := final.buf
putEncoder(final)
return ret, nil
}
func (enc *logfmtEncoder) addSeparator() {
if !enc.arrayLiteral {
return
}
last := enc.buf.Len() - 1
if last >= 0 && enc.buf.Bytes()[last] != '[' {
enc.buf.AppendByte(',')
}
}
func (enc *logfmtEncoder) addKey(key string) {
key = strings.Map(keyRuneFilter, key)
if enc.buf.Len() > 0 {
enc.buf.AppendByte(' ')
}
for _, ns := range enc.namespaces {
enc.safeAddString(ns)
enc.buf.AppendByte('.')
}
enc.safeAddString(key)
enc.buf.AppendByte('=')
}
// safeAddString JSON-escapes a string and appends it to the internal buffer.
// Unlike the standard library's encoder, it doesn't attempt to protect the
// user from browser vulnerabilities or JSONP-related problems.
func (enc *logfmtEncoder) safeAddString(s string) {
for i := 0; i < len(s); {
if enc.tryAddRuneSelf(s[i]) {
i++
continue
}
r, size := utf8.DecodeRuneInString(s[i:])
if enc.tryAddRuneError(r, size) {
i++
continue
}
enc.buf.AppendString(s[i : i+size])
i += size
}
}
// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
func (enc *logfmtEncoder) safeAddByteString(s []byte) {
for i := 0; i < len(s); {
if enc.tryAddRuneSelf(s[i]) {
i++
continue
}
r, size := utf8.DecodeRune(s[i:])
if enc.tryAddRuneError(r, size) {
i++
continue
}
enc.buf.Write(s[i : i+size])
i += size
}
}
// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte.
func (enc *logfmtEncoder) tryAddRuneSelf(b byte) bool {
if b >= utf8.RuneSelf {
return false
}
if 0x20 <= b && b != '\\' && b != '"' {
enc.buf.AppendByte(b)
return true
}
switch b {
case '\\', '"':
enc.buf.AppendByte('\\')
enc.buf.AppendByte(b)
case '\n':
enc.buf.AppendByte('\\')
enc.buf.AppendByte('n')
case '\r':
enc.buf.AppendByte('\\')
enc.buf.AppendByte('r')
case '\t':
enc.buf.AppendByte('\\')
enc.buf.AppendByte('t')
default:
// Encode bytes < 0x20, except for the escape sequences above.
const _hex = "0123456789abcdef"
enc.buf.AppendString(`\u00`)
enc.buf.AppendByte(_hex[b>>4])
enc.buf.AppendByte(_hex[b&0xF])
}
return true
}
func (enc *logfmtEncoder) tryAddRuneError(r rune, size int) bool {
if r == utf8.RuneError && size == 1 {
enc.buf.AppendString(`\ufffd`)
return true
}
return false
}
func needsQuotedValueRune(r rune) bool {
return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
}
func keyRuneFilter(r rune) rune {
if needsQuotedValueRune(r) {
return -1
}
return r
}
func addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) {
for i := range fields {
fields[i].AddTo(enc)
}
}