github.com/jxskiss/gopkg@v0.17.3/zlog/logfmt_encoder.go (about)

     1  package zlog
     2  
     3  // This file is forked from https://github.com/jsternberg/zap-logfmt.
     4  // It's originally published by Jonathan A. Sternberg with MIT license.
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/base64"
     9  	"errors"
    10  	"fmt"
    11  	"math"
    12  	"reflect"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  	"unicode/utf8"
    17  
    18  	"go.uber.org/zap"
    19  	"go.uber.org/zap/buffer"
    20  	"go.uber.org/zap/zapcore"
    21  )
    22  
    23  const (
    24  	// For JSON-escaping; see logfmtEncoder.safeAddString below.
    25  	_hex = "0123456789abcdef"
    26  )
    27  
    28  var (
    29  	_logfmtPool = sync.Pool{New: func() interface{} {
    30  		return &logfmtEncoder{}
    31  	}}
    32  
    33  	bufferpool = buffer.NewPool()
    34  )
    35  
    36  var ErrUnsupportedValueType = errors.New("unsupported value type")
    37  
    38  func getEncoder() *logfmtEncoder {
    39  	return _logfmtPool.Get().(*logfmtEncoder)
    40  }
    41  
    42  func putEncoder(enc *logfmtEncoder) {
    43  	enc.EncoderConfig = nil
    44  	enc.buf = nil
    45  	_logfmtPool.Put(enc)
    46  }
    47  
    48  type logfmtEncoder struct {
    49  	*zapcore.EncoderConfig
    50  	buf        *buffer.Buffer
    51  	namespaces []string
    52  }
    53  
    54  func NewLogfmtEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder {
    55  	return &logfmtEncoder{
    56  		EncoderConfig: &cfg,
    57  		buf:           bufferpool.Get(),
    58  	}
    59  }
    60  
    61  func (enc *logfmtEncoder) AddArray(key string, arr zapcore.ArrayMarshaler) error {
    62  	enc.addKey(key)
    63  	return enc.AppendArray(arr)
    64  }
    65  
    66  func (enc *logfmtEncoder) AddObject(key string, obj zapcore.ObjectMarshaler) error {
    67  	return ErrUnsupportedValueType
    68  }
    69  
    70  func (enc *logfmtEncoder) AddBinary(key string, value []byte) {
    71  	enc.AddString(key, base64.StdEncoding.EncodeToString(value))
    72  }
    73  
    74  func (enc *logfmtEncoder) AddByteString(key string, value []byte) {
    75  	enc.addKey(key)
    76  	enc.AppendByteString(value)
    77  }
    78  
    79  func (enc *logfmtEncoder) AddBool(key string, value bool) {
    80  	enc.addKey(key)
    81  	enc.AppendBool(value)
    82  }
    83  
    84  func (enc *logfmtEncoder) AddComplex128(key string, value complex128) {
    85  	enc.addKey(key)
    86  	enc.AppendComplex128(value)
    87  }
    88  
    89  func (enc *logfmtEncoder) AddDuration(key string, value time.Duration) {
    90  	enc.addKey(key)
    91  	enc.AppendDuration(value)
    92  }
    93  
    94  func (enc *logfmtEncoder) AddFloat64(key string, value float64) {
    95  	enc.addKey(key)
    96  	enc.AppendFloat64(value)
    97  }
    98  
    99  func (enc *logfmtEncoder) AddInt64(key string, value int64) {
   100  	enc.addKey(key)
   101  	enc.AppendInt64(value)
   102  }
   103  
   104  func (enc *logfmtEncoder) AddReflected(key string, value interface{}) error {
   105  	rvalue := reflect.ValueOf(value)
   106  	switch rvalue.Kind() {
   107  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Struct:
   108  		return ErrUnsupportedValueType
   109  	case reflect.Array, reflect.Slice, reflect.Ptr:
   110  		if rvalue.IsNil() {
   111  			enc.AddByteString(key, nil)
   112  			return nil
   113  		}
   114  		return enc.AddReflected(key, rvalue.Elem().Interface())
   115  	}
   116  	enc.AddString(key, fmt.Sprint(value))
   117  	return nil
   118  }
   119  
   120  func (enc *logfmtEncoder) OpenNamespace(key string) {
   121  	enc.namespaces = append(enc.namespaces, key)
   122  }
   123  
   124  func (enc *logfmtEncoder) AddString(key, value string) {
   125  	enc.addKey(key)
   126  	enc.AppendString(value)
   127  }
   128  
   129  func (enc *logfmtEncoder) AddTime(key string, value time.Time) {
   130  	enc.addKeyWithoutNamespace(key)
   131  	enc.AppendTime(value)
   132  }
   133  
   134  func (enc *logfmtEncoder) AddUint64(key string, value uint64) {
   135  	enc.addKey(key)
   136  	enc.AppendUint64(value)
   137  }
   138  
   139  func (enc *logfmtEncoder) AppendArray(arr zapcore.ArrayMarshaler) error {
   140  	marshaler := literalEncoder{
   141  		EncoderConfig: enc.EncoderConfig,
   142  		buf:           bufferpool.Get(),
   143  	}
   144  
   145  	err := arr.MarshalLogArray(&marshaler)
   146  	if err == nil {
   147  		enc.AppendByteString(marshaler.buf.Bytes())
   148  	} else {
   149  		enc.AppendByteString(nil)
   150  	}
   151  	marshaler.buf.Free()
   152  	return err
   153  }
   154  
   155  func (enc *logfmtEncoder) AppendObject(obj zapcore.ObjectMarshaler) error {
   156  	return ErrUnsupportedValueType
   157  }
   158  
   159  func (enc *logfmtEncoder) AppendBool(value bool) {
   160  	if value {
   161  		enc.AppendString("true")
   162  	} else {
   163  		enc.AppendString("false")
   164  	}
   165  }
   166  
   167  func (enc *logfmtEncoder) AppendByteString(value []byte) {
   168  	needsQuotes := bytes.IndexFunc(value, needsQuotedValueRune) != -1
   169  	if needsQuotes {
   170  		enc.buf.AppendByte('"')
   171  	}
   172  	enc.safeAddByteString(value)
   173  	if needsQuotes {
   174  		enc.buf.AppendByte('"')
   175  	}
   176  }
   177  
   178  func (enc *logfmtEncoder) AppendComplex128(value complex128) {
   179  	// Cast to a platform-independent, fixed-size type.
   180  	r, i := float64(real(value)), float64(imag(value))
   181  	enc.buf.AppendFloat(r, 64)
   182  	enc.buf.AppendByte('+')
   183  	enc.buf.AppendFloat(i, 64)
   184  	enc.buf.AppendByte('i')
   185  }
   186  
   187  func (enc *logfmtEncoder) AppendDuration(value time.Duration) {
   188  	cur := enc.buf.Len()
   189  	enc.EncodeDuration(value, enc)
   190  	if cur == enc.buf.Len() {
   191  		// User-supplied EncodeDuration is a no-op. Fall back to nanoseconds.
   192  		enc.AppendInt64(int64(value))
   193  	}
   194  }
   195  
   196  func (enc *logfmtEncoder) AppendInt64(value int64) {
   197  	enc.buf.AppendInt(value)
   198  }
   199  
   200  func (enc *logfmtEncoder) AppendReflected(value interface{}) error {
   201  	rvalue := reflect.ValueOf(value)
   202  	switch rvalue.Kind() {
   203  	case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
   204  		return ErrUnsupportedValueType
   205  	case reflect.Ptr:
   206  		if rvalue.IsNil() {
   207  			enc.AppendByteString(nil)
   208  			return nil
   209  		}
   210  		return enc.AppendReflected(rvalue.Elem().Interface())
   211  	}
   212  	enc.AppendString(fmt.Sprint(value))
   213  	return nil
   214  }
   215  
   216  func (enc *logfmtEncoder) AppendString(value string) {
   217  	needsQuotes := strings.IndexFunc(value, needsQuotedValueRune) != -1
   218  	if needsQuotes {
   219  		enc.buf.AppendByte('"')
   220  	}
   221  	enc.safeAddString(value)
   222  	if needsQuotes {
   223  		enc.buf.AppendByte('"')
   224  	}
   225  }
   226  
   227  func (enc *logfmtEncoder) AppendTime(value time.Time) {
   228  	cur := enc.buf.Len()
   229  	enc.EncodeTime(value, enc)
   230  	if cur == enc.buf.Len() {
   231  		enc.AppendInt64(value.UnixNano())
   232  	}
   233  }
   234  
   235  func (enc *logfmtEncoder) AppendUint64(value uint64) {
   236  	enc.buf.AppendUint(value)
   237  }
   238  
   239  func (enc *logfmtEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) }
   240  func (enc *logfmtEncoder) AddFloat32(k string, v float32)     { enc.AddFloat64(k, float64(v)) }
   241  func (enc *logfmtEncoder) AddInt(k string, v int)             { enc.AddInt64(k, int64(v)) }
   242  func (enc *logfmtEncoder) AddInt32(k string, v int32)         { enc.AddInt64(k, int64(v)) }
   243  func (enc *logfmtEncoder) AddInt16(k string, v int16)         { enc.AddInt64(k, int64(v)) }
   244  func (enc *logfmtEncoder) AddInt8(k string, v int8)           { enc.AddInt64(k, int64(v)) }
   245  func (enc *logfmtEncoder) AddUint(k string, v uint)           { enc.AddUint64(k, uint64(v)) }
   246  func (enc *logfmtEncoder) AddUint32(k string, v uint32)       { enc.AddUint64(k, uint64(v)) }
   247  func (enc *logfmtEncoder) AddUint16(k string, v uint16)       { enc.AddUint64(k, uint64(v)) }
   248  func (enc *logfmtEncoder) AddUint8(k string, v uint8)         { enc.AddUint64(k, uint64(v)) }
   249  func (enc *logfmtEncoder) AddUintptr(k string, v uintptr)     { enc.AddUint64(k, uint64(v)) }
   250  func (enc *logfmtEncoder) AppendComplex64(v complex64)        { enc.AppendComplex128(complex128(v)) }
   251  func (enc *logfmtEncoder) AppendFloat64(v float64)            { enc.appendFloat(v, 64) }
   252  func (enc *logfmtEncoder) AppendFloat32(v float32)            { enc.appendFloat(float64(v), 32) }
   253  func (enc *logfmtEncoder) AppendInt(v int)                    { enc.AppendInt64(int64(v)) }
   254  func (enc *logfmtEncoder) AppendInt32(v int32)                { enc.AppendInt64(int64(v)) }
   255  func (enc *logfmtEncoder) AppendInt16(v int16)                { enc.AppendInt64(int64(v)) }
   256  func (enc *logfmtEncoder) AppendInt8(v int8)                  { enc.AppendInt64(int64(v)) }
   257  func (enc *logfmtEncoder) AppendUint(v uint)                  { enc.AppendUint64(uint64(v)) }
   258  func (enc *logfmtEncoder) AppendUint32(v uint32)              { enc.AppendUint64(uint64(v)) }
   259  func (enc *logfmtEncoder) AppendUint16(v uint16)              { enc.AppendUint64(uint64(v)) }
   260  func (enc *logfmtEncoder) AppendUint8(v uint8)                { enc.AppendUint64(uint64(v)) }
   261  func (enc *logfmtEncoder) AppendUintptr(v uintptr)            { enc.AppendUint64(uint64(v)) }
   262  
   263  func (enc *logfmtEncoder) Clone() zapcore.Encoder {
   264  	clone := enc.clone()
   265  	clone.buf.Write(enc.buf.Bytes())
   266  	return clone
   267  }
   268  
   269  func (enc *logfmtEncoder) clone() *logfmtEncoder {
   270  	clone := getEncoder()
   271  	clone.EncoderConfig = enc.EncoderConfig
   272  	clone.buf = bufferpool.Get()
   273  	clone.namespaces = enc.namespaces
   274  	return clone
   275  }
   276  
   277  func (enc *logfmtEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
   278  	final := enc.clone()
   279  	if final.TimeKey != "" {
   280  		final.AddTime(final.TimeKey, ent.Time)
   281  	}
   282  	if final.LevelKey != "" {
   283  		final.addKeyWithoutNamespace(final.LevelKey)
   284  		cur := final.buf.Len()
   285  		final.EncodeLevel(ent.Level, final)
   286  		if cur == final.buf.Len() {
   287  			// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
   288  			// output valid.
   289  			final.AppendString(ent.Level.String())
   290  		}
   291  	}
   292  	if ent.LoggerName != "" && final.NameKey != "" {
   293  		final.addKeyWithoutNamespace(final.NameKey)
   294  		cur := final.buf.Len()
   295  		nameEncoder := final.EncodeName
   296  		if nameEncoder == nil {
   297  			nameEncoder = zapcore.FullNameEncoder
   298  		}
   299  		nameEncoder(ent.LoggerName, final)
   300  		if cur == final.buf.Len() {
   301  			// User-supplied EncodeName was a no-op. Fall back to strings to
   302  			// keep output valid.
   303  			final.AppendString(ent.LoggerName)
   304  		}
   305  	}
   306  	if ent.Caller.Defined && final.CallerKey != "" {
   307  		final.addKeyWithoutNamespace(final.CallerKey)
   308  		cur := final.buf.Len()
   309  		final.EncodeCaller(ent.Caller, final)
   310  		if cur == final.buf.Len() {
   311  			// User-supplied EncodeCaller was a no-op. Fall back to strings to
   312  			// keep output valid.
   313  			final.AppendString(ent.Caller.String())
   314  		}
   315  	}
   316  	if final.MessageKey != "" {
   317  		final.addKeyWithoutNamespace(enc.MessageKey)
   318  		final.AppendString(ent.Message)
   319  	}
   320  	if enc.buf.Len() > 0 {
   321  		final.buf.AppendByte(' ')
   322  		final.buf.Write(enc.buf.Bytes())
   323  	}
   324  	addFields(final, fields)
   325  	if ent.Stack != "" && final.StacktraceKey != "" {
   326  		final.addKeyWithoutNamespace(final.StacktraceKey)
   327  		final.AppendString(ent.Stack)
   328  	}
   329  	if final.LineEnding != "" {
   330  		final.buf.AppendString(final.LineEnding)
   331  	} else {
   332  		final.buf.AppendString(zapcore.DefaultLineEnding)
   333  	}
   334  
   335  	ret := final.buf
   336  	putEncoder(final)
   337  	return ret, nil
   338  }
   339  
   340  func (enc *logfmtEncoder) truncate() {
   341  	enc.buf.Reset()
   342  	enc.namespaces = nil
   343  }
   344  
   345  func (enc *logfmtEncoder) addKey(key string) {
   346  	if enc.buf.Len() > 0 {
   347  		enc.buf.AppendByte(' ')
   348  	}
   349  	for _, ns := range enc.namespaces {
   350  		enc.safeAddString(ns)
   351  		enc.buf.AppendByte('.')
   352  	}
   353  	enc.safeAddString(key)
   354  	enc.buf.AppendByte('=')
   355  }
   356  
   357  func (enc *logfmtEncoder) addKeyWithoutNamespace(key string) {
   358  	if enc.buf.Len() > 0 {
   359  		enc.buf.AppendByte(' ')
   360  	}
   361  	enc.safeAddString(key)
   362  	enc.buf.AppendByte('=')
   363  }
   364  
   365  func (enc *logfmtEncoder) appendFloat(val float64, bitSize int) {
   366  	switch {
   367  	case math.IsNaN(val):
   368  		enc.buf.AppendString(`NaN`)
   369  	case math.IsInf(val, 1):
   370  		enc.buf.AppendString(`+Inf`)
   371  	case math.IsInf(val, -1):
   372  		enc.buf.AppendString(`-Inf`)
   373  	default:
   374  		enc.buf.AppendFloat(val, bitSize)
   375  	}
   376  }
   377  
   378  // safeAddString JSON-escapes a string and appends it to the internal buffer.
   379  // Unlike the standard library's encoder, it doesn't attempt to protect the
   380  // user from browser vulnerabilities or JSONP-related problems.
   381  func (enc *logfmtEncoder) safeAddString(s string) {
   382  	for i := 0; i < len(s); {
   383  		if enc.tryAddRuneSelf(s[i]) {
   384  			i++
   385  			continue
   386  		}
   387  		r, size := utf8.DecodeRuneInString(s[i:])
   388  		if enc.tryAddRuneError(r, size) {
   389  			i++
   390  			continue
   391  		}
   392  		enc.buf.AppendString(s[i : i+size])
   393  		i += size
   394  	}
   395  }
   396  
   397  // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
   398  func (enc *logfmtEncoder) safeAddByteString(s []byte) {
   399  	for i := 0; i < len(s); {
   400  		if enc.tryAddRuneSelf(s[i]) {
   401  			i++
   402  			continue
   403  		}
   404  		r, size := utf8.DecodeRune(s[i:])
   405  		if enc.tryAddRuneError(r, size) {
   406  			i++
   407  			continue
   408  		}
   409  		enc.buf.Write(s[i : i+size])
   410  		i += size
   411  	}
   412  }
   413  
   414  // tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte.
   415  func (enc *logfmtEncoder) tryAddRuneSelf(b byte) bool {
   416  	if b >= utf8.RuneSelf {
   417  		return false
   418  	}
   419  	if 0x20 <= b && b != '\\' && b != '"' {
   420  		enc.buf.AppendByte(b)
   421  		return true
   422  	}
   423  	switch b {
   424  	case '\\', '"':
   425  		enc.buf.AppendByte('\\')
   426  		enc.buf.AppendByte(b)
   427  	case '\n':
   428  		enc.buf.AppendByte('\\')
   429  		enc.buf.AppendByte('n')
   430  	case '\r':
   431  		enc.buf.AppendByte('\\')
   432  		enc.buf.AppendByte('r')
   433  	case '\t':
   434  		enc.buf.AppendByte('\\')
   435  		enc.buf.AppendByte('t')
   436  	default:
   437  		// Encode bytes < 0x20, except for the escape sequences above.
   438  		enc.buf.AppendString(`\u00`)
   439  		enc.buf.AppendByte(_hex[b>>4])
   440  		enc.buf.AppendByte(_hex[b&0xF])
   441  	}
   442  	return true
   443  }
   444  
   445  func (enc *logfmtEncoder) tryAddRuneError(r rune, size int) bool {
   446  	if r == utf8.RuneError && size == 1 {
   447  		enc.buf.AppendString(`\ufffd`)
   448  		return true
   449  	}
   450  	return false
   451  }
   452  
   453  type literalEncoder struct {
   454  	*zapcore.EncoderConfig
   455  	buf *buffer.Buffer
   456  }
   457  
   458  func (enc *literalEncoder) AppendBool(value bool) {
   459  	enc.addSeparator()
   460  	if value {
   461  		enc.AppendString("true")
   462  	} else {
   463  		enc.AppendString("false")
   464  	}
   465  }
   466  
   467  func (enc *literalEncoder) AppendByteString(value []byte) {
   468  	enc.addSeparator()
   469  	enc.buf.AppendString(string(value))
   470  }
   471  
   472  func (enc *literalEncoder) AppendComplex128(value complex128) {
   473  	enc.addSeparator()
   474  	// Cast to a platform-independent, fixed-size type.
   475  	r, i := float64(real(value)), float64(imag(value))
   476  	enc.buf.AppendFloat(r, 64)
   477  	enc.buf.AppendByte('+')
   478  	enc.buf.AppendFloat(i, 64)
   479  	enc.buf.AppendByte('i')
   480  }
   481  
   482  func (enc *literalEncoder) AppendComplex64(value complex64) {
   483  	enc.AppendComplex128(complex128(value))
   484  }
   485  
   486  func (enc *literalEncoder) AppendFloat64(value float64) {
   487  	enc.addSeparator()
   488  	enc.buf.AppendFloat(value, 64)
   489  }
   490  
   491  func (enc *literalEncoder) AppendFloat32(value float32) {
   492  	enc.addSeparator()
   493  	enc.buf.AppendFloat(float64(value), 32)
   494  }
   495  
   496  func (enc *literalEncoder) AppendInt64(value int64) {
   497  	enc.addSeparator()
   498  	enc.buf.AppendInt(value)
   499  }
   500  
   501  func (enc *literalEncoder) AppendInt(v int)     { enc.AppendInt64(int64(v)) }
   502  func (enc *literalEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) }
   503  func (enc *literalEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) }
   504  func (enc *literalEncoder) AppendInt8(v int8)   { enc.AppendInt64(int64(v)) }
   505  
   506  func (enc *literalEncoder) AppendString(value string) {
   507  	enc.addSeparator()
   508  	enc.buf.AppendString(value)
   509  }
   510  
   511  func (enc *literalEncoder) AppendUint64(value uint64) {
   512  	enc.addSeparator()
   513  	enc.buf.AppendUint(value)
   514  }
   515  
   516  func (enc *literalEncoder) AppendUint(v uint)       { enc.AppendUint64(uint64(v)) }
   517  func (enc *literalEncoder) AppendUint32(v uint32)   { enc.AppendUint64(uint64(v)) }
   518  func (enc *literalEncoder) AppendUint16(v uint16)   { enc.AppendUint64(uint64(v)) }
   519  func (enc *literalEncoder) AppendUint8(v uint8)     { enc.AppendUint64(uint64(v)) }
   520  func (enc *literalEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) }
   521  
   522  func (enc *literalEncoder) AppendDuration(value time.Duration) {
   523  	cur := enc.buf.Len()
   524  	enc.EncodeDuration(value, enc)
   525  	if cur == enc.buf.Len() {
   526  		// User-supplied EncodeDuration is a no-op. Fall back to nanoseconds.
   527  		enc.AppendInt64(int64(value))
   528  	}
   529  }
   530  
   531  func (enc *literalEncoder) AppendTime(value time.Time) {
   532  	cur := enc.buf.Len()
   533  	enc.EncodeTime(value, enc)
   534  	if cur == enc.buf.Len() {
   535  		enc.AppendInt64(value.UnixNano())
   536  	}
   537  }
   538  
   539  func (enc *literalEncoder) AppendArray(arr zapcore.ArrayMarshaler) error {
   540  	return arr.MarshalLogArray(enc)
   541  }
   542  
   543  func (enc *literalEncoder) AppendObject(zapcore.ObjectMarshaler) error {
   544  	return ErrUnsupportedValueType
   545  }
   546  
   547  func (enc *literalEncoder) AppendReflected(value interface{}) error {
   548  	return ErrUnsupportedValueType
   549  }
   550  
   551  func (enc *literalEncoder) addSeparator() {
   552  	if enc.buf.Len() > 0 {
   553  		enc.buf.AppendByte(',')
   554  	}
   555  }
   556  
   557  func needsQuotedValueRune(r rune) bool {
   558  	return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
   559  }
   560  
   561  func addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) {
   562  	for i := range fields {
   563  		fields[i].AddTo(enc)
   564  	}
   565  }
   566  
   567  func init() {
   568  	zap.RegisterEncoder("logfmt", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
   569  		enc := NewLogfmtEncoder(cfg)
   570  		return enc, nil
   571  	})
   572  }