package zapcore
import (
"encoding/base64"
"math"
"time"
"unicode/utf8"
"go.uber.org/zap/buffer"
"go.uber.org/zap/internal/bufferpool"
"go.uber.org/zap/internal/pool"
)
const _hex = "0123456789abcdef"
var _jsonPool = pool .New (func () *jsonEncoder {
return &jsonEncoder {}
})
func putJSONEncoder (enc *jsonEncoder ) {
if enc .reflectBuf != nil {
enc .reflectBuf .Free ()
}
enc .EncoderConfig = nil
enc .buf = nil
enc .spaced = false
enc .openNamespaces = 0
enc .reflectBuf = nil
enc .reflectEnc = nil
_jsonPool .Put (enc )
}
type jsonEncoder struct {
*EncoderConfig
buf *buffer .Buffer
spaced bool
openNamespaces int
reflectBuf *buffer .Buffer
reflectEnc ReflectedEncoder
}
func NewJSONEncoder (cfg EncoderConfig ) Encoder {
return newJSONEncoder (cfg , false )
}
func newJSONEncoder (cfg EncoderConfig , spaced bool ) *jsonEncoder {
if cfg .SkipLineEnding {
cfg .LineEnding = ""
} else if cfg .LineEnding == "" {
cfg .LineEnding = DefaultLineEnding
}
if cfg .NewReflectedEncoder == nil {
cfg .NewReflectedEncoder = defaultReflectedEncoder
}
return &jsonEncoder {
EncoderConfig : &cfg ,
buf : bufferpool .Get (),
spaced : spaced ,
}
}
func (enc *jsonEncoder ) AddArray (key string , arr ArrayMarshaler ) error {
enc .addKey (key )
return enc .AppendArray (arr )
}
func (enc *jsonEncoder ) AddObject (key string , obj ObjectMarshaler ) error {
enc .addKey (key )
return enc .AppendObject (obj )
}
func (enc *jsonEncoder ) AddBinary (key string , val []byte ) {
enc .AddString (key , base64 .StdEncoding .EncodeToString (val ))
}
func (enc *jsonEncoder ) AddByteString (key string , val []byte ) {
enc .addKey (key )
enc .AppendByteString (val )
}
func (enc *jsonEncoder ) AddBool (key string , val bool ) {
enc .addKey (key )
enc .AppendBool (val )
}
func (enc *jsonEncoder ) AddComplex128 (key string , val complex128 ) {
enc .addKey (key )
enc .AppendComplex128 (val )
}
func (enc *jsonEncoder ) AddComplex64 (key string , val complex64 ) {
enc .addKey (key )
enc .AppendComplex64 (val )
}
func (enc *jsonEncoder ) AddDuration (key string , val time .Duration ) {
enc .addKey (key )
enc .AppendDuration (val )
}
func (enc *jsonEncoder ) AddFloat64 (key string , val float64 ) {
enc .addKey (key )
enc .AppendFloat64 (val )
}
func (enc *jsonEncoder ) AddFloat32 (key string , val float32 ) {
enc .addKey (key )
enc .AppendFloat32 (val )
}
func (enc *jsonEncoder ) AddInt64 (key string , val int64 ) {
enc .addKey (key )
enc .AppendInt64 (val )
}
func (enc *jsonEncoder ) resetReflectBuf () {
if enc .reflectBuf == nil {
enc .reflectBuf = bufferpool .Get ()
enc .reflectEnc = enc .NewReflectedEncoder (enc .reflectBuf )
} else {
enc .reflectBuf .Reset ()
}
}
var nullLiteralBytes = []byte ("null" )
func (enc *jsonEncoder ) encodeReflected (obj interface {}) ([]byte , error ) {
if obj == nil {
return nullLiteralBytes , nil
}
enc .resetReflectBuf ()
if err := enc .reflectEnc .Encode (obj ); err != nil {
return nil , err
}
enc .reflectBuf .TrimNewline ()
return enc .reflectBuf .Bytes (), nil
}
func (enc *jsonEncoder ) AddReflected (key string , obj interface {}) error {
valueBytes , err := enc .encodeReflected (obj )
if err != nil {
return err
}
enc .addKey (key )
_, err = enc .buf .Write (valueBytes )
return err
}
func (enc *jsonEncoder ) OpenNamespace (key string ) {
enc .addKey (key )
enc .buf .AppendByte ('{' )
enc .openNamespaces ++
}
func (enc *jsonEncoder ) AddString (key , val string ) {
enc .addKey (key )
enc .AppendString (val )
}
func (enc *jsonEncoder ) AddTime (key string , val time .Time ) {
enc .addKey (key )
enc .AppendTime (val )
}
func (enc *jsonEncoder ) AddUint64 (key string , val uint64 ) {
enc .addKey (key )
enc .AppendUint64 (val )
}
func (enc *jsonEncoder ) AppendArray (arr ArrayMarshaler ) error {
enc .addElementSeparator ()
enc .buf .AppendByte ('[' )
err := arr .MarshalLogArray (enc )
enc .buf .AppendByte (']' )
return err
}
func (enc *jsonEncoder ) AppendObject (obj ObjectMarshaler ) error {
old := enc .openNamespaces
enc .openNamespaces = 0
enc .addElementSeparator ()
enc .buf .AppendByte ('{' )
err := obj .MarshalLogObject (enc )
enc .buf .AppendByte ('}' )
enc .closeOpenNamespaces ()
enc .openNamespaces = old
return err
}
func (enc *jsonEncoder ) AppendBool (val bool ) {
enc .addElementSeparator ()
enc .buf .AppendBool (val )
}
func (enc *jsonEncoder ) AppendByteString (val []byte ) {
enc .addElementSeparator ()
enc .buf .AppendByte ('"' )
enc .safeAddByteString (val )
enc .buf .AppendByte ('"' )
}
func (enc *jsonEncoder ) appendComplex (val complex128 , precision int ) {
enc .addElementSeparator ()
r , i := float64 (real (val )), float64 (imag (val ))
enc .buf .AppendByte ('"' )
enc .buf .AppendFloat (r , precision )
if i >= 0 {
enc .buf .AppendByte ('+' )
}
enc .buf .AppendFloat (i , precision )
enc .buf .AppendByte ('i' )
enc .buf .AppendByte ('"' )
}
func (enc *jsonEncoder ) AppendDuration (val time .Duration ) {
cur := enc .buf .Len ()
if e := enc .EncodeDuration ; e != nil {
e (val , enc )
}
if cur == enc .buf .Len () {
enc .AppendInt64 (int64 (val ))
}
}
func (enc *jsonEncoder ) AppendInt64 (val int64 ) {
enc .addElementSeparator ()
enc .buf .AppendInt (val )
}
func (enc *jsonEncoder ) AppendReflected (val interface {}) error {
valueBytes , err := enc .encodeReflected (val )
if err != nil {
return err
}
enc .addElementSeparator ()
_, err = enc .buf .Write (valueBytes )
return err
}
func (enc *jsonEncoder ) AppendString (val string ) {
enc .addElementSeparator ()
enc .buf .AppendByte ('"' )
enc .safeAddString (val )
enc .buf .AppendByte ('"' )
}
func (enc *jsonEncoder ) AppendTimeLayout (time time .Time , layout string ) {
enc .addElementSeparator ()
enc .buf .AppendByte ('"' )
enc .buf .AppendTime (time , layout )
enc .buf .AppendByte ('"' )
}
func (enc *jsonEncoder ) AppendTime (val time .Time ) {
cur := enc .buf .Len ()
if e := enc .EncodeTime ; e != nil {
e (val , enc )
}
if cur == enc .buf .Len () {
enc .AppendInt64 (val .UnixNano ())
}
}
func (enc *jsonEncoder ) AppendUint64 (val uint64 ) {
enc .addElementSeparator ()
enc .buf .AppendUint (val )
}
func (enc *jsonEncoder ) AddInt (k string , v int ) { enc .AddInt64 (k , int64 (v )) }
func (enc *jsonEncoder ) AddInt32 (k string , v int32 ) { enc .AddInt64 (k , int64 (v )) }
func (enc *jsonEncoder ) AddInt16 (k string , v int16 ) { enc .AddInt64 (k , int64 (v )) }
func (enc *jsonEncoder ) AddInt8 (k string , v int8 ) { enc .AddInt64 (k , int64 (v )) }
func (enc *jsonEncoder ) AddUint (k string , v uint ) { enc .AddUint64 (k , uint64 (v )) }
func (enc *jsonEncoder ) AddUint32 (k string , v uint32 ) { enc .AddUint64 (k , uint64 (v )) }
func (enc *jsonEncoder ) AddUint16 (k string , v uint16 ) { enc .AddUint64 (k , uint64 (v )) }
func (enc *jsonEncoder ) AddUint8 (k string , v uint8 ) { enc .AddUint64 (k , uint64 (v )) }
func (enc *jsonEncoder ) AddUintptr (k string , v uintptr ) { enc .AddUint64 (k , uint64 (v )) }
func (enc *jsonEncoder ) AppendComplex64 (v complex64 ) { enc .appendComplex (complex128 (v ), 32 ) }
func (enc *jsonEncoder ) AppendComplex128 (v complex128 ) { enc .appendComplex (complex128 (v ), 64 ) }
func (enc *jsonEncoder ) AppendFloat64 (v float64 ) { enc .appendFloat (v , 64 ) }
func (enc *jsonEncoder ) AppendFloat32 (v float32 ) { enc .appendFloat (float64 (v ), 32 ) }
func (enc *jsonEncoder ) AppendInt (v int ) { enc .AppendInt64 (int64 (v )) }
func (enc *jsonEncoder ) AppendInt32 (v int32 ) { enc .AppendInt64 (int64 (v )) }
func (enc *jsonEncoder ) AppendInt16 (v int16 ) { enc .AppendInt64 (int64 (v )) }
func (enc *jsonEncoder ) AppendInt8 (v int8 ) { enc .AppendInt64 (int64 (v )) }
func (enc *jsonEncoder ) AppendUint (v uint ) { enc .AppendUint64 (uint64 (v )) }
func (enc *jsonEncoder ) AppendUint32 (v uint32 ) { enc .AppendUint64 (uint64 (v )) }
func (enc *jsonEncoder ) AppendUint16 (v uint16 ) { enc .AppendUint64 (uint64 (v )) }
func (enc *jsonEncoder ) AppendUint8 (v uint8 ) { enc .AppendUint64 (uint64 (v )) }
func (enc *jsonEncoder ) AppendUintptr (v uintptr ) { enc .AppendUint64 (uint64 (v )) }
func (enc *jsonEncoder ) Clone () Encoder {
clone := enc .clone ()
clone .buf .Write (enc .buf .Bytes ())
return clone
}
func (enc *jsonEncoder ) clone () *jsonEncoder {
clone := _jsonPool .Get ()
clone .EncoderConfig = enc .EncoderConfig
clone .spaced = enc .spaced
clone .openNamespaces = enc .openNamespaces
clone .buf = bufferpool .Get ()
return clone
}
func (enc *jsonEncoder ) EncodeEntry (ent Entry , fields []Field ) (*buffer .Buffer , error ) {
final := enc .clone ()
final .buf .AppendByte ('{' )
if final .LevelKey != "" && final .EncodeLevel != nil {
final .addKey (final .LevelKey )
cur := final .buf .Len ()
final .EncodeLevel (ent .Level , final )
if cur == final .buf .Len () {
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 nameEncoder == nil {
nameEncoder = FullNameEncoder
}
nameEncoder (ent .LoggerName , final )
if cur == final .buf .Len () {
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 () {
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 ('}' )
final .buf .AppendString (final .LineEnding )
ret := final .buf
putJSONEncoder (final )
return ret , nil
}
func (enc *jsonEncoder ) truncate () {
enc .buf .Reset ()
}
func (enc *jsonEncoder ) closeOpenNamespaces () {
for i := 0 ; i < enc .openNamespaces ; i ++ {
enc .buf .AppendByte ('}' )
}
enc .openNamespaces = 0
}
func (enc *jsonEncoder ) addKey (key string ) {
enc .addElementSeparator ()
enc .buf .AppendByte ('"' )
enc .safeAddString (key )
enc .buf .AppendByte ('"' )
enc .buf .AppendByte (':' )
if enc .spaced {
enc .buf .AppendByte (' ' )
}
}
func (enc *jsonEncoder ) addElementSeparator () {
last := enc .buf .Len () - 1
if last < 0 {
return
}
switch enc .buf .Bytes ()[last ] {
case '{' , '[' , ':' , ',' , ' ' :
return
default :
enc .buf .AppendByte (',' )
if enc .spaced {
enc .buf .AppendByte (' ' )
}
}
}
func (enc *jsonEncoder ) appendFloat (val float64 , bitSize int ) {
enc .addElementSeparator ()
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 *jsonEncoder ) safeAddString (s string ) {
safeAppendStringLike (
(*buffer .Buffer ).AppendString ,
utf8 .DecodeRuneInString ,
enc .buf ,
s ,
)
}
func (enc *jsonEncoder ) safeAddByteString (s []byte ) {
safeAppendStringLike (
(*buffer .Buffer ).AppendBytes ,
utf8 .DecodeRune ,
enc .buf ,
s ,
)
}
func safeAppendStringLike [S []byte | string ](
appendTo func (*buffer .Buffer , S ),
decodeRune func (S ) (rune , int ),
buf *buffer .Buffer ,
s S ,
) {
last := 0
for i := 0 ; i < len (s ); {
if s [i ] >= utf8 .RuneSelf {
r , size := decodeRune (s [i :])
if r != utf8 .RuneError || size != 1 {
i += size
continue
}
appendTo (buf , s [last :i ])
buf .AppendString (`\ufffd` )
i ++
last = i
} else {
if s [i ] >= 0x20 && s [i ] != '\\' && s [i ] != '"' {
i ++
continue
}
appendTo (buf , s [last :i ])
switch s [i ] {
case '\\' , '"' :
buf .AppendByte ('\\' )
buf .AppendByte (s [i ])
case '\n' :
buf .AppendByte ('\\' )
buf .AppendByte ('n' )
case '\r' :
buf .AppendByte ('\\' )
buf .AppendByte ('r' )
case '\t' :
buf .AppendByte ('\\' )
buf .AppendByte ('t' )
default :
buf .AppendString (`\u00` )
buf .AppendByte (_hex [s [i ]>>4 ])
buf .AppendByte (_hex [s [i ]&0xF ])
}
i ++
last = i
}
}
appendTo (buf , s [last :])
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .