json_encoder.go raw

   1  // Copyright (c) 2016 Uber Technologies, Inc.
   2  //
   3  // Permission is hereby granted, free of charge, to any person obtaining a copy
   4  // of this software and associated documentation files (the "Software"), to deal
   5  // in the Software without restriction, including without limitation the rights
   6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   7  // copies of the Software, and to permit persons to whom the Software is
   8  // furnished to do so, subject to the following conditions:
   9  //
  10  // The above copyright notice and this permission notice shall be included in
  11  // all copies or substantial portions of the Software.
  12  //
  13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19  // THE SOFTWARE.
  20  
  21  package zapcore
  22  
  23  import (
  24  	"encoding/base64"
  25  	"math"
  26  	"time"
  27  	"unicode/utf8"
  28  
  29  	"go.uber.org/zap/buffer"
  30  	"go.uber.org/zap/internal/bufferpool"
  31  	"go.uber.org/zap/internal/pool"
  32  )
  33  
  34  // For JSON-escaping; see jsonEncoder.safeAddString below.
  35  const _hex = "0123456789abcdef"
  36  
  37  var _jsonPool = pool.New(func() *jsonEncoder {
  38  	return &jsonEncoder{}
  39  })
  40  
  41  func putJSONEncoder(enc *jsonEncoder) {
  42  	if enc.reflectBuf != nil {
  43  		enc.reflectBuf.Free()
  44  	}
  45  	enc.EncoderConfig = nil
  46  	enc.buf = nil
  47  	enc.spaced = false
  48  	enc.openNamespaces = 0
  49  	enc.reflectBuf = nil
  50  	enc.reflectEnc = nil
  51  	_jsonPool.Put(enc)
  52  }
  53  
  54  type jsonEncoder struct {
  55  	*EncoderConfig
  56  	buf            *buffer.Buffer
  57  	spaced         bool // include spaces after colons and commas
  58  	openNamespaces int
  59  
  60  	// for encoding generic values by reflection
  61  	reflectBuf *buffer.Buffer
  62  	reflectEnc ReflectedEncoder
  63  }
  64  
  65  // NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder
  66  // appropriately escapes all field keys and values.
  67  //
  68  // Note that the encoder doesn't deduplicate keys, so it's possible to produce
  69  // a message like
  70  //
  71  //	{"foo":"bar","foo":"baz"}
  72  //
  73  // This is permitted by the JSON specification, but not encouraged. Many
  74  // libraries will ignore duplicate key-value pairs (typically keeping the last
  75  // pair) when unmarshaling, but users should attempt to avoid adding duplicate
  76  // keys.
  77  func NewJSONEncoder(cfg EncoderConfig) Encoder {
  78  	return newJSONEncoder(cfg, false)
  79  }
  80  
  81  func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder {
  82  	if cfg.SkipLineEnding {
  83  		cfg.LineEnding = ""
  84  	} else if cfg.LineEnding == "" {
  85  		cfg.LineEnding = DefaultLineEnding
  86  	}
  87  
  88  	// If no EncoderConfig.NewReflectedEncoder is provided by the user, then use default
  89  	if cfg.NewReflectedEncoder == nil {
  90  		cfg.NewReflectedEncoder = defaultReflectedEncoder
  91  	}
  92  
  93  	return &jsonEncoder{
  94  		EncoderConfig: &cfg,
  95  		buf:           bufferpool.Get(),
  96  		spaced:        spaced,
  97  	}
  98  }
  99  
 100  func (enc *jsonEncoder) AddArray(key string, arr ArrayMarshaler) error {
 101  	enc.addKey(key)
 102  	return enc.AppendArray(arr)
 103  }
 104  
 105  func (enc *jsonEncoder) AddObject(key string, obj ObjectMarshaler) error {
 106  	enc.addKey(key)
 107  	return enc.AppendObject(obj)
 108  }
 109  
 110  func (enc *jsonEncoder) AddBinary(key string, val []byte) {
 111  	enc.AddString(key, base64.StdEncoding.EncodeToString(val))
 112  }
 113  
 114  func (enc *jsonEncoder) AddByteString(key string, val []byte) {
 115  	enc.addKey(key)
 116  	enc.AppendByteString(val)
 117  }
 118  
 119  func (enc *jsonEncoder) AddBool(key string, val bool) {
 120  	enc.addKey(key)
 121  	enc.AppendBool(val)
 122  }
 123  
 124  func (enc *jsonEncoder) AddComplex128(key string, val complex128) {
 125  	enc.addKey(key)
 126  	enc.AppendComplex128(val)
 127  }
 128  
 129  func (enc *jsonEncoder) AddComplex64(key string, val complex64) {
 130  	enc.addKey(key)
 131  	enc.AppendComplex64(val)
 132  }
 133  
 134  func (enc *jsonEncoder) AddDuration(key string, val time.Duration) {
 135  	enc.addKey(key)
 136  	enc.AppendDuration(val)
 137  }
 138  
 139  func (enc *jsonEncoder) AddFloat64(key string, val float64) {
 140  	enc.addKey(key)
 141  	enc.AppendFloat64(val)
 142  }
 143  
 144  func (enc *jsonEncoder) AddFloat32(key string, val float32) {
 145  	enc.addKey(key)
 146  	enc.AppendFloat32(val)
 147  }
 148  
 149  func (enc *jsonEncoder) AddInt64(key string, val int64) {
 150  	enc.addKey(key)
 151  	enc.AppendInt64(val)
 152  }
 153  
 154  func (enc *jsonEncoder) resetReflectBuf() {
 155  	if enc.reflectBuf == nil {
 156  		enc.reflectBuf = bufferpool.Get()
 157  		enc.reflectEnc = enc.NewReflectedEncoder(enc.reflectBuf)
 158  	} else {
 159  		enc.reflectBuf.Reset()
 160  	}
 161  }
 162  
 163  var nullLiteralBytes = []byte("null")
 164  
 165  // Only invoke the standard JSON encoder if there is actually something to
 166  // encode; otherwise write JSON null literal directly.
 167  func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) {
 168  	if obj == nil {
 169  		return nullLiteralBytes, nil
 170  	}
 171  	enc.resetReflectBuf()
 172  	if err := enc.reflectEnc.Encode(obj); err != nil {
 173  		return nil, err
 174  	}
 175  	enc.reflectBuf.TrimNewline()
 176  	return enc.reflectBuf.Bytes(), nil
 177  }
 178  
 179  func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error {
 180  	valueBytes, err := enc.encodeReflected(obj)
 181  	if err != nil {
 182  		return err
 183  	}
 184  	enc.addKey(key)
 185  	_, err = enc.buf.Write(valueBytes)
 186  	return err
 187  }
 188  
 189  func (enc *jsonEncoder) OpenNamespace(key string) {
 190  	enc.addKey(key)
 191  	enc.buf.AppendByte('{')
 192  	enc.openNamespaces++
 193  }
 194  
 195  func (enc *jsonEncoder) AddString(key, val string) {
 196  	enc.addKey(key)
 197  	enc.AppendString(val)
 198  }
 199  
 200  func (enc *jsonEncoder) AddTime(key string, val time.Time) {
 201  	enc.addKey(key)
 202  	enc.AppendTime(val)
 203  }
 204  
 205  func (enc *jsonEncoder) AddUint64(key string, val uint64) {
 206  	enc.addKey(key)
 207  	enc.AppendUint64(val)
 208  }
 209  
 210  func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error {
 211  	enc.addElementSeparator()
 212  	enc.buf.AppendByte('[')
 213  	err := arr.MarshalLogArray(enc)
 214  	enc.buf.AppendByte(']')
 215  	return err
 216  }
 217  
 218  func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error {
 219  	// Close ONLY new openNamespaces that are created during
 220  	// AppendObject().
 221  	old := enc.openNamespaces
 222  	enc.openNamespaces = 0
 223  	enc.addElementSeparator()
 224  	enc.buf.AppendByte('{')
 225  	err := obj.MarshalLogObject(enc)
 226  	enc.buf.AppendByte('}')
 227  	enc.closeOpenNamespaces()
 228  	enc.openNamespaces = old
 229  	return err
 230  }
 231  
 232  func (enc *jsonEncoder) AppendBool(val bool) {
 233  	enc.addElementSeparator()
 234  	enc.buf.AppendBool(val)
 235  }
 236  
 237  func (enc *jsonEncoder) AppendByteString(val []byte) {
 238  	enc.addElementSeparator()
 239  	enc.buf.AppendByte('"')
 240  	enc.safeAddByteString(val)
 241  	enc.buf.AppendByte('"')
 242  }
 243  
 244  // appendComplex appends the encoded form of the provided complex128 value.
 245  // precision specifies the encoding precision for the real and imaginary
 246  // components of the complex number.
 247  func (enc *jsonEncoder) appendComplex(val complex128, precision int) {
 248  	enc.addElementSeparator()
 249  	// Cast to a platform-independent, fixed-size type.
 250  	r, i := float64(real(val)), float64(imag(val))
 251  	enc.buf.AppendByte('"')
 252  	// Because we're always in a quoted string, we can use strconv without
 253  	// special-casing NaN and +/-Inf.
 254  	enc.buf.AppendFloat(r, precision)
 255  	// If imaginary part is less than 0, minus (-) sign is added by default
 256  	// by AppendFloat.
 257  	if i >= 0 {
 258  		enc.buf.AppendByte('+')
 259  	}
 260  	enc.buf.AppendFloat(i, precision)
 261  	enc.buf.AppendByte('i')
 262  	enc.buf.AppendByte('"')
 263  }
 264  
 265  func (enc *jsonEncoder) AppendDuration(val time.Duration) {
 266  	cur := enc.buf.Len()
 267  	if e := enc.EncodeDuration; e != nil {
 268  		e(val, enc)
 269  	}
 270  	if cur == enc.buf.Len() {
 271  		// User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep
 272  		// JSON valid.
 273  		enc.AppendInt64(int64(val))
 274  	}
 275  }
 276  
 277  func (enc *jsonEncoder) AppendInt64(val int64) {
 278  	enc.addElementSeparator()
 279  	enc.buf.AppendInt(val)
 280  }
 281  
 282  func (enc *jsonEncoder) AppendReflected(val interface{}) error {
 283  	valueBytes, err := enc.encodeReflected(val)
 284  	if err != nil {
 285  		return err
 286  	}
 287  	enc.addElementSeparator()
 288  	_, err = enc.buf.Write(valueBytes)
 289  	return err
 290  }
 291  
 292  func (enc *jsonEncoder) AppendString(val string) {
 293  	enc.addElementSeparator()
 294  	enc.buf.AppendByte('"')
 295  	enc.safeAddString(val)
 296  	enc.buf.AppendByte('"')
 297  }
 298  
 299  func (enc *jsonEncoder) AppendTimeLayout(time time.Time, layout string) {
 300  	enc.addElementSeparator()
 301  	enc.buf.AppendByte('"')
 302  	enc.buf.AppendTime(time, layout)
 303  	enc.buf.AppendByte('"')
 304  }
 305  
 306  func (enc *jsonEncoder) AppendTime(val time.Time) {
 307  	cur := enc.buf.Len()
 308  	if e := enc.EncodeTime; e != nil {
 309  		e(val, enc)
 310  	}
 311  	if cur == enc.buf.Len() {
 312  		// User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep
 313  		// output JSON valid.
 314  		enc.AppendInt64(val.UnixNano())
 315  	}
 316  }
 317  
 318  func (enc *jsonEncoder) AppendUint64(val uint64) {
 319  	enc.addElementSeparator()
 320  	enc.buf.AppendUint(val)
 321  }
 322  
 323  func (enc *jsonEncoder) AddInt(k string, v int)         { enc.AddInt64(k, int64(v)) }
 324  func (enc *jsonEncoder) AddInt32(k string, v int32)     { enc.AddInt64(k, int64(v)) }
 325  func (enc *jsonEncoder) AddInt16(k string, v int16)     { enc.AddInt64(k, int64(v)) }
 326  func (enc *jsonEncoder) AddInt8(k string, v int8)       { enc.AddInt64(k, int64(v)) }
 327  func (enc *jsonEncoder) AddUint(k string, v uint)       { enc.AddUint64(k, uint64(v)) }
 328  func (enc *jsonEncoder) AddUint32(k string, v uint32)   { enc.AddUint64(k, uint64(v)) }
 329  func (enc *jsonEncoder) AddUint16(k string, v uint16)   { enc.AddUint64(k, uint64(v)) }
 330  func (enc *jsonEncoder) AddUint8(k string, v uint8)     { enc.AddUint64(k, uint64(v)) }
 331  func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) }
 332  func (enc *jsonEncoder) AppendComplex64(v complex64)    { enc.appendComplex(complex128(v), 32) }
 333  func (enc *jsonEncoder) AppendComplex128(v complex128)  { enc.appendComplex(complex128(v), 64) }
 334  func (enc *jsonEncoder) AppendFloat64(v float64)        { enc.appendFloat(v, 64) }
 335  func (enc *jsonEncoder) AppendFloat32(v float32)        { enc.appendFloat(float64(v), 32) }
 336  func (enc *jsonEncoder) AppendInt(v int)                { enc.AppendInt64(int64(v)) }
 337  func (enc *jsonEncoder) AppendInt32(v int32)            { enc.AppendInt64(int64(v)) }
 338  func (enc *jsonEncoder) AppendInt16(v int16)            { enc.AppendInt64(int64(v)) }
 339  func (enc *jsonEncoder) AppendInt8(v int8)              { enc.AppendInt64(int64(v)) }
 340  func (enc *jsonEncoder) AppendUint(v uint)              { enc.AppendUint64(uint64(v)) }
 341  func (enc *jsonEncoder) AppendUint32(v uint32)          { enc.AppendUint64(uint64(v)) }
 342  func (enc *jsonEncoder) AppendUint16(v uint16)          { enc.AppendUint64(uint64(v)) }
 343  func (enc *jsonEncoder) AppendUint8(v uint8)            { enc.AppendUint64(uint64(v)) }
 344  func (enc *jsonEncoder) AppendUintptr(v uintptr)        { enc.AppendUint64(uint64(v)) }
 345  
 346  func (enc *jsonEncoder) Clone() Encoder {
 347  	clone := enc.clone()
 348  	clone.buf.Write(enc.buf.Bytes())
 349  	return clone
 350  }
 351  
 352  func (enc *jsonEncoder) clone() *jsonEncoder {
 353  	clone := _jsonPool.Get()
 354  	clone.EncoderConfig = enc.EncoderConfig
 355  	clone.spaced = enc.spaced
 356  	clone.openNamespaces = enc.openNamespaces
 357  	clone.buf = bufferpool.Get()
 358  	return clone
 359  }
 360  
 361  func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
 362  	final := enc.clone()
 363  	final.buf.AppendByte('{')
 364  
 365  	if final.LevelKey != "" && final.EncodeLevel != nil {
 366  		final.addKey(final.LevelKey)
 367  		cur := final.buf.Len()
 368  		final.EncodeLevel(ent.Level, final)
 369  		if cur == final.buf.Len() {
 370  			// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
 371  			// output JSON valid.
 372  			final.AppendString(ent.Level.String())
 373  		}
 374  	}
 375  	if final.TimeKey != "" && !ent.Time.IsZero() {
 376  		final.AddTime(final.TimeKey, ent.Time)
 377  	}
 378  	if ent.LoggerName != "" && final.NameKey != "" {
 379  		final.addKey(final.NameKey)
 380  		cur := final.buf.Len()
 381  		nameEncoder := final.EncodeName
 382  
 383  		// if no name encoder provided, fall back to FullNameEncoder for backwards
 384  		// compatibility
 385  		if nameEncoder == nil {
 386  			nameEncoder = FullNameEncoder
 387  		}
 388  
 389  		nameEncoder(ent.LoggerName, final)
 390  		if cur == final.buf.Len() {
 391  			// User-supplied EncodeName was a no-op. Fall back to strings to
 392  			// keep output JSON valid.
 393  			final.AppendString(ent.LoggerName)
 394  		}
 395  	}
 396  	if ent.Caller.Defined {
 397  		if final.CallerKey != "" {
 398  			final.addKey(final.CallerKey)
 399  			cur := final.buf.Len()
 400  			final.EncodeCaller(ent.Caller, final)
 401  			if cur == final.buf.Len() {
 402  				// User-supplied EncodeCaller was a no-op. Fall back to strings to
 403  				// keep output JSON valid.
 404  				final.AppendString(ent.Caller.String())
 405  			}
 406  		}
 407  		if final.FunctionKey != "" {
 408  			final.addKey(final.FunctionKey)
 409  			final.AppendString(ent.Caller.Function)
 410  		}
 411  	}
 412  	if final.MessageKey != "" {
 413  		final.addKey(enc.MessageKey)
 414  		final.AppendString(ent.Message)
 415  	}
 416  	if enc.buf.Len() > 0 {
 417  		final.addElementSeparator()
 418  		final.buf.Write(enc.buf.Bytes())
 419  	}
 420  	addFields(final, fields)
 421  	final.closeOpenNamespaces()
 422  	if ent.Stack != "" && final.StacktraceKey != "" {
 423  		final.AddString(final.StacktraceKey, ent.Stack)
 424  	}
 425  	final.buf.AppendByte('}')
 426  	final.buf.AppendString(final.LineEnding)
 427  
 428  	ret := final.buf
 429  	putJSONEncoder(final)
 430  	return ret, nil
 431  }
 432  
 433  func (enc *jsonEncoder) truncate() {
 434  	enc.buf.Reset()
 435  }
 436  
 437  func (enc *jsonEncoder) closeOpenNamespaces() {
 438  	for i := 0; i < enc.openNamespaces; i++ {
 439  		enc.buf.AppendByte('}')
 440  	}
 441  	enc.openNamespaces = 0
 442  }
 443  
 444  func (enc *jsonEncoder) addKey(key string) {
 445  	enc.addElementSeparator()
 446  	enc.buf.AppendByte('"')
 447  	enc.safeAddString(key)
 448  	enc.buf.AppendByte('"')
 449  	enc.buf.AppendByte(':')
 450  	if enc.spaced {
 451  		enc.buf.AppendByte(' ')
 452  	}
 453  }
 454  
 455  func (enc *jsonEncoder) addElementSeparator() {
 456  	last := enc.buf.Len() - 1
 457  	if last < 0 {
 458  		return
 459  	}
 460  	switch enc.buf.Bytes()[last] {
 461  	case '{', '[', ':', ',', ' ':
 462  		return
 463  	default:
 464  		enc.buf.AppendByte(',')
 465  		if enc.spaced {
 466  			enc.buf.AppendByte(' ')
 467  		}
 468  	}
 469  }
 470  
 471  func (enc *jsonEncoder) appendFloat(val float64, bitSize int) {
 472  	enc.addElementSeparator()
 473  	switch {
 474  	case math.IsNaN(val):
 475  		enc.buf.AppendString(`"NaN"`)
 476  	case math.IsInf(val, 1):
 477  		enc.buf.AppendString(`"+Inf"`)
 478  	case math.IsInf(val, -1):
 479  		enc.buf.AppendString(`"-Inf"`)
 480  	default:
 481  		enc.buf.AppendFloat(val, bitSize)
 482  	}
 483  }
 484  
 485  // safeAddString JSON-escapes a string and appends it to the internal buffer.
 486  // Unlike the standard library's encoder, it doesn't attempt to protect the
 487  // user from browser vulnerabilities or JSONP-related problems.
 488  func (enc *jsonEncoder) safeAddString(s string) {
 489  	safeAppendStringLike(
 490  		(*buffer.Buffer).AppendString,
 491  		utf8.DecodeRuneInString,
 492  		enc.buf,
 493  		s,
 494  	)
 495  }
 496  
 497  // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
 498  func (enc *jsonEncoder) safeAddByteString(s []byte) {
 499  	safeAppendStringLike(
 500  		(*buffer.Buffer).AppendBytes,
 501  		utf8.DecodeRune,
 502  		enc.buf,
 503  		s,
 504  	)
 505  }
 506  
 507  // safeAppendStringLike is a generic implementation of safeAddString and safeAddByteString.
 508  // It appends a string or byte slice to the buffer, escaping all special characters.
 509  func safeAppendStringLike[S []byte | string](
 510  	// appendTo appends this string-like object to the buffer.
 511  	appendTo func(*buffer.Buffer, S),
 512  	// decodeRune decodes the next rune from the string-like object
 513  	// and returns its value and width in bytes.
 514  	decodeRune func(S) (rune, int),
 515  	buf *buffer.Buffer,
 516  	s S,
 517  ) {
 518  	// The encoding logic below works by skipping over characters
 519  	// that can be safely copied as-is,
 520  	// until a character is found that needs special handling.
 521  	// At that point, we copy everything we've seen so far,
 522  	// and then handle that special character.
 523  	//
 524  	// last is the index of the last byte that was copied to the buffer.
 525  	last := 0
 526  	for i := 0; i < len(s); {
 527  		if s[i] >= utf8.RuneSelf {
 528  			// Character >= RuneSelf may be part of a multi-byte rune.
 529  			// They need to be decoded before we can decide how to handle them.
 530  			r, size := decodeRune(s[i:])
 531  			if r != utf8.RuneError || size != 1 {
 532  				// No special handling required.
 533  				// Skip over this rune and continue.
 534  				i += size
 535  				continue
 536  			}
 537  
 538  			// Invalid UTF-8 sequence.
 539  			// Replace it with the Unicode replacement character.
 540  			appendTo(buf, s[last:i])
 541  			buf.AppendString(`\ufffd`)
 542  
 543  			i++
 544  			last = i
 545  		} else {
 546  			// Character < RuneSelf is a single-byte UTF-8 rune.
 547  			if s[i] >= 0x20 && s[i] != '\\' && s[i] != '"' {
 548  				// No escaping necessary.
 549  				// Skip over this character and continue.
 550  				i++
 551  				continue
 552  			}
 553  
 554  			// This character needs to be escaped.
 555  			appendTo(buf, s[last:i])
 556  			switch s[i] {
 557  			case '\\', '"':
 558  				buf.AppendByte('\\')
 559  				buf.AppendByte(s[i])
 560  			case '\n':
 561  				buf.AppendByte('\\')
 562  				buf.AppendByte('n')
 563  			case '\r':
 564  				buf.AppendByte('\\')
 565  				buf.AppendByte('r')
 566  			case '\t':
 567  				buf.AppendByte('\\')
 568  				buf.AppendByte('t')
 569  			default:
 570  				// Encode bytes < 0x20, except for the escape sequences above.
 571  				buf.AppendString(`\u00`)
 572  				buf.AppendByte(_hex[s[i]>>4])
 573  				buf.AppendByte(_hex[s[i]&0xF])
 574  			}
 575  
 576  			i++
 577  			last = i
 578  		}
 579  	}
 580  
 581  	// add remaining
 582  	appendTo(buf, s[last:])
 583  }
 584