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