summary refs log tree commit diff
path: root/vendor/github.com/rs/zerolog/internal
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-10-25 15:55:50 +0200
committerEmile <git@emile.space>2024-10-25 15:55:50 +0200
commitc90f36e3dd179d2de96f4f5fe38d8dc9a9de6dfe (patch)
tree89e9afb41c5bf76f48cfb09305a2d3db8d302b06 /vendor/github.com/rs/zerolog/internal
parent98bbb0f559a8883bc47bae80607dbe326a448e61 (diff)
vendor HEAD main
Diffstat (limited to 'vendor/github.com/rs/zerolog/internal')
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/README.md56
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/base.go19
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/cbor.go102
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go654
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/string.go117
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/time.go93
-rw-r--r--vendor/github.com/rs/zerolog/internal/cbor/types.go486
-rw-r--r--vendor/github.com/rs/zerolog/internal/json/base.go19
-rw-r--r--vendor/github.com/rs/zerolog/internal/json/bytes.go85
-rw-r--r--vendor/github.com/rs/zerolog/internal/json/string.go149
-rw-r--r--vendor/github.com/rs/zerolog/internal/json/time.go113
-rw-r--r--vendor/github.com/rs/zerolog/internal/json/types.go435
12 files changed, 2328 insertions, 0 deletions
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/README.md b/vendor/github.com/rs/zerolog/internal/cbor/README.md
new file mode 100644
index 0000000..92c2e8c
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/README.md
@@ -0,0 +1,56 @@
+## Reference:
+   CBOR Encoding is described in [RFC7049](https://tools.ietf.org/html/rfc7049)
+
+## Comparison of JSON vs CBOR
+
+Two main areas of reduction are:
+
+1. CPU usage to write a log msg 
+2. Size (in bytes) of log messages.
+
+
+CPU Usage savings are below:
+```
+name                                    JSON time/op    CBOR time/op   delta
+Info-32                                   15.3ns ± 1%    11.7ns ± 3%  -23.78%  (p=0.000 n=9+10)      
+ContextFields-32                          16.2ns ± 2%    12.3ns ± 3%  -23.97%  (p=0.000 n=9+9)       
+ContextAppend-32                          6.70ns ± 0%    6.20ns ± 0%   -7.44%  (p=0.000 n=9+9)       
+LogFields-32                              66.4ns ± 0%    24.6ns ± 2%  -62.89%  (p=0.000 n=10+9)      
+LogArrayObject-32                          911ns ±11%     768ns ± 6%  -15.64%  (p=0.000 n=10+10)     
+LogFieldType/Floats-32                    70.3ns ± 2%    29.5ns ± 1%  -57.98%  (p=0.000 n=10+10)     
+LogFieldType/Err-32                       14.0ns ± 3%    12.1ns ± 8%  -13.20%  (p=0.000 n=8+10)      
+LogFieldType/Dur-32                       17.2ns ± 2%    13.1ns ± 1%  -24.27%  (p=0.000 n=10+9)      
+LogFieldType/Object-32                    54.3ns ±11%    52.3ns ± 7%     ~     (p=0.239 n=10+10)     
+LogFieldType/Ints-32                      20.3ns ± 2%    15.1ns ± 2%  -25.50%  (p=0.000 n=9+10)      
+LogFieldType/Interfaces-32                 642ns ±11%     621ns ± 9%     ~     (p=0.118 n=10+10)     
+LogFieldType/Interface(Objects)-32         635ns ±13%     632ns ± 9%     ~     (p=0.592 n=10+10)     
+LogFieldType/Times-32                      294ns ± 0%      27ns ± 1%  -90.71%  (p=0.000 n=10+9)      
+LogFieldType/Durs-32                       121ns ± 0%      33ns ± 2%  -72.44%  (p=0.000 n=9+9)       
+LogFieldType/Interface(Object)-32         56.6ns ± 8%    52.3ns ± 8%   -7.54%  (p=0.007 n=10+10)     
+LogFieldType/Errs-32                      17.8ns ± 3%    16.1ns ± 2%   -9.71%  (p=0.000 n=10+9)      
+LogFieldType/Time-32                      40.5ns ± 1%    12.7ns ± 6%  -68.66%  (p=0.000 n=8+9)       
+LogFieldType/Bool-32                      12.0ns ± 5%    10.2ns ± 2%  -15.18%  (p=0.000 n=10+8)      
+LogFieldType/Bools-32                     17.2ns ± 2%    12.6ns ± 4%  -26.63%  (p=0.000 n=10+10)     
+LogFieldType/Int-32                       12.3ns ± 2%    11.2ns ± 4%   -9.27%  (p=0.000 n=9+10)      
+LogFieldType/Float-32                     16.7ns ± 1%    12.6ns ± 2%  -24.42%  (p=0.000 n=7+9)       
+LogFieldType/Str-32                       12.7ns ± 7%    11.3ns ± 7%  -10.88%  (p=0.000 n=10+9)      
+LogFieldType/Strs-32                      20.3ns ± 3%    18.2ns ± 3%  -10.25%  (p=0.000 n=9+10)      
+LogFieldType/Interface-32                  183ns ±12%     175ns ± 9%     ~     (p=0.078 n=10+10)     
+```
+
+Log message size savings is greatly dependent on the number and type of fields in the log message.
+Assuming this log message (with an Integer, timestamp and string, in addition to level).
+
+`{"level":"error","Fault":41650,"time":"2018-04-01T15:18:19-07:00","message":"Some Message"}`
+
+Two measurements were done for the log file sizes - one without any compression, second
+using [compress/zlib](https://golang.org/pkg/compress/zlib/). 
+
+Results for 10,000 log messages:
+
+| Log Format |  Plain File Size (in KB) | Compressed File Size (in KB) |
+| :--- | :---: | :---: |
+| JSON | 920 | 28 |
+| CBOR | 550 | 28 |
+
+The example used to calculate the above data is available in [Examples](examples).
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/base.go b/vendor/github.com/rs/zerolog/internal/cbor/base.go
new file mode 100644
index 0000000..51fe86c
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/base.go
@@ -0,0 +1,19 @@
+package cbor
+
+// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice.
+// Making it package level instead of embedded in Encoder brings
+// some extra efforts at importing, but avoids value copy when the functions
+// of Encoder being invoked.
+// DO REMEMBER to set this variable at importing, or
+// you might get a nil pointer dereference panic at runtime.
+var JSONMarshalFunc func(v interface{}) ([]byte, error)
+
+type Encoder struct{}
+
+// AppendKey adds a key (string) to the binary encoded log message
+func (e Encoder) AppendKey(dst []byte, key string) []byte {
+	if len(dst) < 1 {
+		dst = e.AppendBeginMarker(dst)
+	}
+	return e.AppendString(dst, key)
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/cbor.go b/vendor/github.com/rs/zerolog/internal/cbor/cbor.go
new file mode 100644
index 0000000..1bf1443
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/cbor.go
@@ -0,0 +1,102 @@
+// Package cbor provides primitives for storing different data
+// in the CBOR (binary) format. CBOR is defined in RFC7049.
+package cbor
+
+import "time"
+
+const (
+	majorOffset   = 5
+	additionalMax = 23
+
+	// Non Values.
+	additionalTypeBoolFalse byte = 20
+	additionalTypeBoolTrue  byte = 21
+	additionalTypeNull      byte = 22
+
+	// Integer (+ve and -ve) Sub-types.
+	additionalTypeIntUint8  byte = 24
+	additionalTypeIntUint16 byte = 25
+	additionalTypeIntUint32 byte = 26
+	additionalTypeIntUint64 byte = 27
+
+	// Float Sub-types.
+	additionalTypeFloat16 byte = 25
+	additionalTypeFloat32 byte = 26
+	additionalTypeFloat64 byte = 27
+	additionalTypeBreak   byte = 31
+
+	// Tag Sub-types.
+	additionalTypeTimestamp    byte = 01
+	additionalTypeEmbeddedCBOR byte = 63
+
+	// Extended Tags - from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
+	additionalTypeTagNetworkAddr   uint16 = 260
+	additionalTypeTagNetworkPrefix uint16 = 261
+	additionalTypeEmbeddedJSON     uint16 = 262
+	additionalTypeTagHexString     uint16 = 263
+
+	// Unspecified number of elements.
+	additionalTypeInfiniteCount byte = 31
+)
+const (
+	majorTypeUnsignedInt    byte = iota << majorOffset // Major type 0
+	majorTypeNegativeInt                               // Major type 1
+	majorTypeByteString                                // Major type 2
+	majorTypeUtf8String                                // Major type 3
+	majorTypeArray                                     // Major type 4
+	majorTypeMap                                       // Major type 5
+	majorTypeTags                                      // Major type 6
+	majorTypeSimpleAndFloat                            // Major type 7
+)
+
+const (
+	maskOutAdditionalType byte = (7 << majorOffset)
+	maskOutMajorType      byte = 31
+)
+
+const (
+	float32Nan         = "\xfa\x7f\xc0\x00\x00"
+	float32PosInfinity = "\xfa\x7f\x80\x00\x00"
+	float32NegInfinity = "\xfa\xff\x80\x00\x00"
+	float64Nan         = "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"
+	float64PosInfinity = "\xfb\x7f\xf0\x00\x00\x00\x00\x00\x00"
+	float64NegInfinity = "\xfb\xff\xf0\x00\x00\x00\x00\x00\x00"
+)
+
+// IntegerTimeFieldFormat indicates the format of timestamp decoded
+// from an integer (time in seconds).
+var IntegerTimeFieldFormat = time.RFC3339
+
+// NanoTimeFieldFormat indicates the format of timestamp decoded
+// from a float value (time in seconds and nanoseconds).
+var NanoTimeFieldFormat = time.RFC3339Nano
+
+func appendCborTypePrefix(dst []byte, major byte, number uint64) []byte {
+	byteCount := 8
+	var minor byte
+	switch {
+	case number < 256:
+		byteCount = 1
+		minor = additionalTypeIntUint8
+
+	case number < 65536:
+		byteCount = 2
+		minor = additionalTypeIntUint16
+
+	case number < 4294967296:
+		byteCount = 4
+		minor = additionalTypeIntUint32
+
+	default:
+		byteCount = 8
+		minor = additionalTypeIntUint64
+
+	}
+
+	dst = append(dst, major|minor)
+	byteCount--
+	for ; byteCount >= 0; byteCount-- {
+		dst = append(dst, byte(number>>(uint(byteCount)*8)))
+	}
+	return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go b/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go
new file mode 100644
index 0000000..5633e66
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go
@@ -0,0 +1,654 @@
+package cbor
+
+// This file contains code to decode a stream of CBOR Data into JSON.
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/base64"
+	"fmt"
+	"io"
+	"math"
+	"net"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+	"unicode/utf8"
+)
+
+var decodeTimeZone *time.Location
+
+const hexTable = "0123456789abcdef"
+
+const isFloat32 = 4
+const isFloat64 = 8
+
+func readNBytes(src *bufio.Reader, n int) []byte {
+	ret := make([]byte, n)
+	for i := 0; i < n; i++ {
+		ch, e := src.ReadByte()
+		if e != nil {
+			panic(fmt.Errorf("Tried to Read %d Bytes.. But hit end of file", n))
+		}
+		ret[i] = ch
+	}
+	return ret
+}
+
+func readByte(src *bufio.Reader) byte {
+	b, e := src.ReadByte()
+	if e != nil {
+		panic(fmt.Errorf("Tried to Read 1 Byte.. But hit end of file"))
+	}
+	return b
+}
+
+func decodeIntAdditionalType(src *bufio.Reader, minor byte) int64 {
+	val := int64(0)
+	if minor <= 23 {
+		val = int64(minor)
+	} else {
+		bytesToRead := 0
+		switch minor {
+		case additionalTypeIntUint8:
+			bytesToRead = 1
+		case additionalTypeIntUint16:
+			bytesToRead = 2
+		case additionalTypeIntUint32:
+			bytesToRead = 4
+		case additionalTypeIntUint64:
+			bytesToRead = 8
+		default:
+			panic(fmt.Errorf("Invalid Additional Type: %d in decodeInteger (expected <28)", minor))
+		}
+		pb := readNBytes(src, bytesToRead)
+		for i := 0; i < bytesToRead; i++ {
+			val = val * 256
+			val += int64(pb[i])
+		}
+	}
+	return val
+}
+
+func decodeInteger(src *bufio.Reader) int64 {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeUnsignedInt && major != majorTypeNegativeInt {
+		panic(fmt.Errorf("Major type is: %d in decodeInteger!! (expected 0 or 1)", major))
+	}
+	val := decodeIntAdditionalType(src, minor)
+	if major == 0 {
+		return val
+	}
+	return (-1 - val)
+}
+
+func decodeFloat(src *bufio.Reader) (float64, int) {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeSimpleAndFloat {
+		panic(fmt.Errorf("Incorrect Major type is: %d in decodeFloat", major))
+	}
+
+	switch minor {
+	case additionalTypeFloat16:
+		panic(fmt.Errorf("float16 is not supported in decodeFloat"))
+
+	case additionalTypeFloat32:
+		pb := readNBytes(src, 4)
+		switch string(pb) {
+		case float32Nan:
+			return math.NaN(), isFloat32
+		case float32PosInfinity:
+			return math.Inf(0), isFloat32
+		case float32NegInfinity:
+			return math.Inf(-1), isFloat32
+		}
+		n := uint32(0)
+		for i := 0; i < 4; i++ {
+			n = n * 256
+			n += uint32(pb[i])
+		}
+		val := math.Float32frombits(n)
+		return float64(val), isFloat32
+	case additionalTypeFloat64:
+		pb := readNBytes(src, 8)
+		switch string(pb) {
+		case float64Nan:
+			return math.NaN(), isFloat64
+		case float64PosInfinity:
+			return math.Inf(0), isFloat64
+		case float64NegInfinity:
+			return math.Inf(-1), isFloat64
+		}
+		n := uint64(0)
+		for i := 0; i < 8; i++ {
+			n = n * 256
+			n += uint64(pb[i])
+		}
+		val := math.Float64frombits(n)
+		return val, isFloat64
+	}
+	panic(fmt.Errorf("Invalid Additional Type: %d in decodeFloat", minor))
+}
+
+func decodeStringComplex(dst []byte, s string, pos uint) []byte {
+	i := int(pos)
+	start := 0
+
+	for i < len(s) {
+		b := s[i]
+		if b >= utf8.RuneSelf {
+			r, size := utf8.DecodeRuneInString(s[i:])
+			if r == utf8.RuneError && size == 1 {
+				// In case of error, first append previous simple characters to
+				// the byte slice if any and append a replacement character code
+				// in place of the invalid sequence.
+				if start < i {
+					dst = append(dst, s[start:i]...)
+				}
+				dst = append(dst, `\ufffd`...)
+				i += size
+				start = i
+				continue
+			}
+			i += size
+			continue
+		}
+		if b >= 0x20 && b <= 0x7e && b != '\\' && b != '"' {
+			i++
+			continue
+		}
+		// We encountered a character that needs to be encoded.
+		// Let's append the previous simple characters to the byte slice
+		// and switch our operation to read and encode the remainder
+		// characters byte-by-byte.
+		if start < i {
+			dst = append(dst, s[start:i]...)
+		}
+		switch b {
+		case '"', '\\':
+			dst = append(dst, '\\', b)
+		case '\b':
+			dst = append(dst, '\\', 'b')
+		case '\f':
+			dst = append(dst, '\\', 'f')
+		case '\n':
+			dst = append(dst, '\\', 'n')
+		case '\r':
+			dst = append(dst, '\\', 'r')
+		case '\t':
+			dst = append(dst, '\\', 't')
+		default:
+			dst = append(dst, '\\', 'u', '0', '0', hexTable[b>>4], hexTable[b&0xF])
+		}
+		i++
+		start = i
+	}
+	if start < len(s) {
+		dst = append(dst, s[start:]...)
+	}
+	return dst
+}
+
+func decodeString(src *bufio.Reader, noQuotes bool) []byte {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeByteString {
+		panic(fmt.Errorf("Major type is: %d in decodeString", major))
+	}
+	result := []byte{}
+	if !noQuotes {
+		result = append(result, '"')
+	}
+	length := decodeIntAdditionalType(src, minor)
+	len := int(length)
+	pbs := readNBytes(src, len)
+	result = append(result, pbs...)
+	if noQuotes {
+		return result
+	}
+	return append(result, '"')
+}
+func decodeStringToDataUrl(src *bufio.Reader, mimeType string) []byte {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeByteString {
+		panic(fmt.Errorf("Major type is: %d in decodeString", major))
+	}
+	length := decodeIntAdditionalType(src, minor)
+	l := int(length)
+	enc := base64.StdEncoding
+	lEnc := enc.EncodedLen(l)
+	result := make([]byte, len("\"data:;base64,\"")+len(mimeType)+lEnc)
+	dest := result
+	u := copy(dest, "\"data:")
+	dest = dest[u:]
+	u = copy(dest, mimeType)
+	dest = dest[u:]
+	u = copy(dest, ";base64,")
+	dest = dest[u:]
+	pbs := readNBytes(src, l)
+	enc.Encode(dest, pbs)
+	dest = dest[lEnc:]
+	dest[0] = '"'
+	return result
+}
+
+func decodeUTF8String(src *bufio.Reader) []byte {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeUtf8String {
+		panic(fmt.Errorf("Major type is: %d in decodeUTF8String", major))
+	}
+	result := []byte{'"'}
+	length := decodeIntAdditionalType(src, minor)
+	len := int(length)
+	pbs := readNBytes(src, len)
+
+	for i := 0; i < len; i++ {
+		// Check if the character needs encoding. Control characters, slashes,
+		// and the double quote need json encoding. Bytes above the ascii
+		// boundary needs utf8 encoding.
+		if pbs[i] < 0x20 || pbs[i] > 0x7e || pbs[i] == '\\' || pbs[i] == '"' {
+			// We encountered a character that needs to be encoded. Switch
+			// to complex version of the algorithm.
+			dst := []byte{'"'}
+			dst = decodeStringComplex(dst, string(pbs), uint(i))
+			return append(dst, '"')
+		}
+	}
+	// The string has no need for encoding and therefore is directly
+	// appended to the byte slice.
+	result = append(result, pbs...)
+	return append(result, '"')
+}
+
+func array2Json(src *bufio.Reader, dst io.Writer) {
+	dst.Write([]byte{'['})
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeArray {
+		panic(fmt.Errorf("Major type is: %d in array2Json", major))
+	}
+	len := 0
+	unSpecifiedCount := false
+	if minor == additionalTypeInfiniteCount {
+		unSpecifiedCount = true
+	} else {
+		length := decodeIntAdditionalType(src, minor)
+		len = int(length)
+	}
+	for i := 0; unSpecifiedCount || i < len; i++ {
+		if unSpecifiedCount {
+			pb, e := src.Peek(1)
+			if e != nil {
+				panic(e)
+			}
+			if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+				readByte(src)
+				break
+			}
+		}
+		cbor2JsonOneObject(src, dst)
+		if unSpecifiedCount {
+			pb, e := src.Peek(1)
+			if e != nil {
+				panic(e)
+			}
+			if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+				readByte(src)
+				break
+			}
+			dst.Write([]byte{','})
+		} else if i+1 < len {
+			dst.Write([]byte{','})
+		}
+	}
+	dst.Write([]byte{']'})
+}
+
+func map2Json(src *bufio.Reader, dst io.Writer) {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeMap {
+		panic(fmt.Errorf("Major type is: %d in map2Json", major))
+	}
+	len := 0
+	unSpecifiedCount := false
+	if minor == additionalTypeInfiniteCount {
+		unSpecifiedCount = true
+	} else {
+		length := decodeIntAdditionalType(src, minor)
+		len = int(length)
+	}
+	dst.Write([]byte{'{'})
+	for i := 0; unSpecifiedCount || i < len; i++ {
+		if unSpecifiedCount {
+			pb, e := src.Peek(1)
+			if e != nil {
+				panic(e)
+			}
+			if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+				readByte(src)
+				break
+			}
+		}
+		cbor2JsonOneObject(src, dst)
+		if i%2 == 0 {
+			// Even position values are keys.
+			dst.Write([]byte{':'})
+		} else {
+			if unSpecifiedCount {
+				pb, e := src.Peek(1)
+				if e != nil {
+					panic(e)
+				}
+				if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+					readByte(src)
+					break
+				}
+				dst.Write([]byte{','})
+			} else if i+1 < len {
+				dst.Write([]byte{','})
+			}
+		}
+	}
+	dst.Write([]byte{'}'})
+}
+
+func decodeTagData(src *bufio.Reader) []byte {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeTags {
+		panic(fmt.Errorf("Major type is: %d in decodeTagData", major))
+	}
+	switch minor {
+	case additionalTypeTimestamp:
+		return decodeTimeStamp(src)
+	case additionalTypeIntUint8:
+		val := decodeIntAdditionalType(src, minor)
+		switch byte(val) {
+		case additionalTypeEmbeddedCBOR:
+			pb := readByte(src)
+			dataMajor := pb & maskOutAdditionalType
+			if dataMajor != majorTypeByteString {
+				panic(fmt.Errorf("Unsupported embedded Type: %d in decodeEmbeddedCBOR", dataMajor))
+			}
+			src.UnreadByte()
+			return decodeStringToDataUrl(src, "application/cbor")
+		default:
+			panic(fmt.Errorf("Unsupported Additional Tag Type: %d in decodeTagData", val))
+		}
+
+	// Tag value is larger than 256 (so uint16).
+	case additionalTypeIntUint16:
+		val := decodeIntAdditionalType(src, minor)
+
+		switch uint16(val) {
+		case additionalTypeEmbeddedJSON:
+			pb := readByte(src)
+			dataMajor := pb & maskOutAdditionalType
+			if dataMajor != majorTypeByteString {
+				panic(fmt.Errorf("Unsupported embedded Type: %d in decodeEmbeddedJSON", dataMajor))
+			}
+			src.UnreadByte()
+			return decodeString(src, true)
+
+		case additionalTypeTagNetworkAddr:
+			octets := decodeString(src, true)
+			ss := []byte{'"'}
+			switch len(octets) {
+			case 6: // MAC address.
+				ha := net.HardwareAddr(octets)
+				ss = append(append(ss, ha.String()...), '"')
+			case 4: // IPv4 address.
+				fallthrough
+			case 16: // IPv6 address.
+				ip := net.IP(octets)
+				ss = append(append(ss, ip.String()...), '"')
+			default:
+				panic(fmt.Errorf("Unexpected Network Address length: %d (expected 4,6,16)", len(octets)))
+			}
+			return ss
+
+		case additionalTypeTagNetworkPrefix:
+			pb := readByte(src)
+			if pb != majorTypeMap|0x1 {
+				panic(fmt.Errorf("IP Prefix is NOT of MAP of 1 elements as expected"))
+			}
+			octets := decodeString(src, true)
+			val := decodeInteger(src)
+			ip := net.IP(octets)
+			var mask net.IPMask
+			pfxLen := int(val)
+			if len(octets) == 4 {
+				mask = net.CIDRMask(pfxLen, 32)
+			} else {
+				mask = net.CIDRMask(pfxLen, 128)
+			}
+			ipPfx := net.IPNet{IP: ip, Mask: mask}
+			ss := []byte{'"'}
+			ss = append(append(ss, ipPfx.String()...), '"')
+			return ss
+
+		case additionalTypeTagHexString:
+			octets := decodeString(src, true)
+			ss := []byte{'"'}
+			for _, v := range octets {
+				ss = append(ss, hexTable[v>>4], hexTable[v&0x0f])
+			}
+			return append(ss, '"')
+
+		default:
+			panic(fmt.Errorf("Unsupported Additional Tag Type: %d in decodeTagData", val))
+		}
+	}
+	panic(fmt.Errorf("Unsupported Additional Type: %d in decodeTagData", minor))
+}
+
+func decodeTimeStamp(src *bufio.Reader) []byte {
+	pb := readByte(src)
+	src.UnreadByte()
+	tsMajor := pb & maskOutAdditionalType
+	if tsMajor == majorTypeUnsignedInt || tsMajor == majorTypeNegativeInt {
+		n := decodeInteger(src)
+		t := time.Unix(n, 0)
+		if decodeTimeZone != nil {
+			t = t.In(decodeTimeZone)
+		} else {
+			t = t.In(time.UTC)
+		}
+		tsb := []byte{}
+		tsb = append(tsb, '"')
+		tsb = t.AppendFormat(tsb, IntegerTimeFieldFormat)
+		tsb = append(tsb, '"')
+		return tsb
+	} else if tsMajor == majorTypeSimpleAndFloat {
+		n, _ := decodeFloat(src)
+		secs := int64(n)
+		n -= float64(secs)
+		n *= float64(1e9)
+		t := time.Unix(secs, int64(n))
+		if decodeTimeZone != nil {
+			t = t.In(decodeTimeZone)
+		} else {
+			t = t.In(time.UTC)
+		}
+		tsb := []byte{}
+		tsb = append(tsb, '"')
+		tsb = t.AppendFormat(tsb, NanoTimeFieldFormat)
+		tsb = append(tsb, '"')
+		return tsb
+	}
+	panic(fmt.Errorf("TS format is neigther int nor float: %d", tsMajor))
+}
+
+func decodeSimpleFloat(src *bufio.Reader) []byte {
+	pb := readByte(src)
+	major := pb & maskOutAdditionalType
+	minor := pb & maskOutMajorType
+	if major != majorTypeSimpleAndFloat {
+		panic(fmt.Errorf("Major type is: %d in decodeSimpleFloat", major))
+	}
+	switch minor {
+	case additionalTypeBoolTrue:
+		return []byte("true")
+	case additionalTypeBoolFalse:
+		return []byte("false")
+	case additionalTypeNull:
+		return []byte("null")
+	case additionalTypeFloat16:
+		fallthrough
+	case additionalTypeFloat32:
+		fallthrough
+	case additionalTypeFloat64:
+		src.UnreadByte()
+		v, bc := decodeFloat(src)
+		ba := []byte{}
+		switch {
+		case math.IsNaN(v):
+			return []byte("\"NaN\"")
+		case math.IsInf(v, 1):
+			return []byte("\"+Inf\"")
+		case math.IsInf(v, -1):
+			return []byte("\"-Inf\"")
+		}
+		if bc == isFloat32 {
+			ba = strconv.AppendFloat(ba, v, 'f', -1, 32)
+		} else if bc == isFloat64 {
+			ba = strconv.AppendFloat(ba, v, 'f', -1, 64)
+		} else {
+			panic(fmt.Errorf("Invalid Float precision from decodeFloat: %d", bc))
+		}
+		return ba
+	default:
+		panic(fmt.Errorf("Invalid Additional Type: %d in decodeSimpleFloat", minor))
+	}
+}
+
+func cbor2JsonOneObject(src *bufio.Reader, dst io.Writer) {
+	pb, e := src.Peek(1)
+	if e != nil {
+		panic(e)
+	}
+	major := (pb[0] & maskOutAdditionalType)
+
+	switch major {
+	case majorTypeUnsignedInt:
+		fallthrough
+	case majorTypeNegativeInt:
+		n := decodeInteger(src)
+		dst.Write([]byte(strconv.Itoa(int(n))))
+
+	case majorTypeByteString:
+		s := decodeString(src, false)
+		dst.Write(s)
+
+	case majorTypeUtf8String:
+		s := decodeUTF8String(src)
+		dst.Write(s)
+
+	case majorTypeArray:
+		array2Json(src, dst)
+
+	case majorTypeMap:
+		map2Json(src, dst)
+
+	case majorTypeTags:
+		s := decodeTagData(src)
+		dst.Write(s)
+
+	case majorTypeSimpleAndFloat:
+		s := decodeSimpleFloat(src)
+		dst.Write(s)
+	}
+}
+
+func moreBytesToRead(src *bufio.Reader) bool {
+	_, e := src.ReadByte()
+	if e == nil {
+		src.UnreadByte()
+		return true
+	}
+	return false
+}
+
+// Cbor2JsonManyObjects decodes all the CBOR Objects read from src
+// reader. It keeps on decoding until reader returns EOF (error when reading).
+// Decoded string is written to the dst. At the end of every CBOR Object
+// newline is written to the output stream.
+//
+// Returns error (if any) that was encountered during decode.
+// The child functions will generate a panic when error is encountered and
+// this function will recover non-runtime Errors and return the reason as error.
+func Cbor2JsonManyObjects(src io.Reader, dst io.Writer) (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			if _, ok := r.(runtime.Error); ok {
+				panic(r)
+			}
+			err = r.(error)
+		}
+	}()
+	bufRdr := bufio.NewReader(src)
+	for moreBytesToRead(bufRdr) {
+		cbor2JsonOneObject(bufRdr, dst)
+		dst.Write([]byte("\n"))
+	}
+	return nil
+}
+
+// Detect if the bytes to be printed is Binary or not.
+func binaryFmt(p []byte) bool {
+	if len(p) > 0 && p[0] > 0x7F {
+		return true
+	}
+	return false
+}
+
+func getReader(str string) *bufio.Reader {
+	return bufio.NewReader(strings.NewReader(str))
+}
+
+// DecodeIfBinaryToString converts a binary formatted log msg to a
+// JSON formatted String Log message - suitable for printing to Console/Syslog.
+func DecodeIfBinaryToString(in []byte) string {
+	if binaryFmt(in) {
+		var b bytes.Buffer
+		Cbor2JsonManyObjects(strings.NewReader(string(in)), &b)
+		return b.String()
+	}
+	return string(in)
+}
+
+// DecodeObjectToStr checks if the input is a binary format, if so,
+// it will decode a single Object and return the decoded string.
+func DecodeObjectToStr(in []byte) string {
+	if binaryFmt(in) {
+		var b bytes.Buffer
+		cbor2JsonOneObject(getReader(string(in)), &b)
+		return b.String()
+	}
+	return string(in)
+}
+
+// DecodeIfBinaryToBytes checks if the input is a binary format, if so,
+// it will decode all Objects and return the decoded string as byte array.
+func DecodeIfBinaryToBytes(in []byte) []byte {
+	if binaryFmt(in) {
+		var b bytes.Buffer
+		Cbor2JsonManyObjects(bytes.NewReader(in), &b)
+		return b.Bytes()
+	}
+	return in
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/string.go b/vendor/github.com/rs/zerolog/internal/cbor/string.go
new file mode 100644
index 0000000..9fc9a4f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/string.go
@@ -0,0 +1,117 @@
+package cbor
+
+import "fmt"
+
+// AppendStrings encodes and adds an array of strings to the dst byte array.
+func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendString(dst, v)
+	}
+	return dst
+}
+
+// AppendString encodes and adds a string to the dst byte array.
+func (Encoder) AppendString(dst []byte, s string) []byte {
+	major := majorTypeUtf8String
+
+	l := len(s)
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, majorTypeUtf8String, uint64(l))
+	}
+	return append(dst, s...)
+}
+
+// AppendStringers encodes and adds an array of Stringer values
+// to the dst byte array.
+func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte {
+	if len(vals) == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	dst = e.AppendArrayStart(dst)
+	dst = e.AppendStringer(dst, vals[0])
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = e.AppendStringer(dst, val)
+		}
+	}
+	return e.AppendArrayEnd(dst)
+}
+
+// AppendStringer encodes and adds the Stringer value to the dst
+// byte array.
+func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte {
+	if val == nil {
+		return e.AppendNil(dst)
+	}
+	return e.AppendString(dst, val.String())
+}
+
+// AppendBytes encodes and adds an array of bytes to the dst byte array.
+func (Encoder) AppendBytes(dst, s []byte) []byte {
+	major := majorTypeByteString
+
+	l := len(s)
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	return append(dst, s...)
+}
+
+// AppendEmbeddedJSON adds a tag and embeds input JSON as such.
+func AppendEmbeddedJSON(dst, s []byte) []byte {
+	major := majorTypeTags
+	minor := additionalTypeEmbeddedJSON
+
+	// Append the TAG to indicate this is Embedded JSON.
+	dst = append(dst, major|additionalTypeIntUint16)
+	dst = append(dst, byte(minor>>8))
+	dst = append(dst, byte(minor&0xff))
+
+	// Append the JSON Object as Byte String.
+	major = majorTypeByteString
+
+	l := len(s)
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	return append(dst, s...)
+}
+
+// AppendEmbeddedCBOR adds a tag and embeds input CBOR as such.
+func AppendEmbeddedCBOR(dst, s []byte) []byte {
+	major := majorTypeTags
+	minor := additionalTypeEmbeddedCBOR
+
+	// Append the TAG to indicate this is Embedded JSON.
+	dst = append(dst, major|additionalTypeIntUint8)
+	dst = append(dst, minor)
+
+	// Append the CBOR Object as Byte String.
+	major = majorTypeByteString
+
+	l := len(s)
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	return append(dst, s...)
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/time.go b/vendor/github.com/rs/zerolog/internal/cbor/time.go
new file mode 100644
index 0000000..7c0ecce
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/time.go
@@ -0,0 +1,93 @@
+package cbor
+
+import (
+	"time"
+)
+
+func appendIntegerTimestamp(dst []byte, t time.Time) []byte {
+	major := majorTypeTags
+	minor := additionalTypeTimestamp
+	dst = append(dst, major|minor)
+	secs := t.Unix()
+	var val uint64
+	if secs < 0 {
+		major = majorTypeNegativeInt
+		val = uint64(-secs - 1)
+	} else {
+		major = majorTypeUnsignedInt
+		val = uint64(secs)
+	}
+	dst = appendCborTypePrefix(dst, major, val)
+	return dst
+}
+
+func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte {
+	major := majorTypeTags
+	minor := additionalTypeTimestamp
+	dst = append(dst, major|minor)
+	secs := t.Unix()
+	nanos := t.Nanosecond()
+	var val float64
+	val = float64(secs)*1.0 + float64(nanos)*1e-9
+	return e.AppendFloat64(dst, val, -1)
+}
+
+// AppendTime encodes and adds a timestamp to the dst byte array.
+func (e Encoder) AppendTime(dst []byte, t time.Time, unused string) []byte {
+	utc := t.UTC()
+	if utc.Nanosecond() == 0 {
+		return appendIntegerTimestamp(dst, utc)
+	}
+	return e.appendFloatTimestamp(dst, utc)
+}
+
+// AppendTimes encodes and adds an array of timestamps to the dst byte array.
+func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+
+	for _, t := range vals {
+		dst = e.AppendTime(dst, t, unused)
+	}
+	return dst
+}
+
+// AppendDuration encodes and adds a duration to the dst byte array.
+// useInt field indicates whether to store the duration as seconds (integer) or
+// as seconds+nanoseconds (float).
+func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, unused int) []byte {
+	if useInt {
+		return e.AppendInt64(dst, int64(d/unit))
+	}
+	return e.AppendFloat64(dst, float64(d)/float64(unit), unused)
+}
+
+// AppendDurations encodes and adds an array of durations to the dst byte array.
+// useInt field indicates whether to store the duration as seconds (integer) or
+// as seconds+nanoseconds (float).
+func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, unused int) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, d := range vals {
+		dst = e.AppendDuration(dst, d, unit, useInt, unused)
+	}
+	return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/types.go b/vendor/github.com/rs/zerolog/internal/cbor/types.go
new file mode 100644
index 0000000..454d68b
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/types.go
@@ -0,0 +1,486 @@
+package cbor
+
+import (
+	"fmt"
+	"math"
+	"net"
+	"reflect"
+)
+
+// AppendNil inserts a 'Nil' object into the dst byte array.
+func (Encoder) AppendNil(dst []byte) []byte {
+	return append(dst, majorTypeSimpleAndFloat|additionalTypeNull)
+}
+
+// AppendBeginMarker inserts a map start into the dst byte array.
+func (Encoder) AppendBeginMarker(dst []byte) []byte {
+	return append(dst, majorTypeMap|additionalTypeInfiniteCount)
+}
+
+// AppendEndMarker inserts a map end into the dst byte array.
+func (Encoder) AppendEndMarker(dst []byte) []byte {
+	return append(dst, majorTypeSimpleAndFloat|additionalTypeBreak)
+}
+
+// AppendObjectData takes an object in form of a byte array and appends to dst.
+func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
+	// BeginMarker is present in the dst, which
+	// should not be copied when appending to existing data.
+	return append(dst, o[1:]...)
+}
+
+// AppendArrayStart adds markers to indicate the start of an array.
+func (Encoder) AppendArrayStart(dst []byte) []byte {
+	return append(dst, majorTypeArray|additionalTypeInfiniteCount)
+}
+
+// AppendArrayEnd adds markers to indicate the end of an array.
+func (Encoder) AppendArrayEnd(dst []byte) []byte {
+	return append(dst, majorTypeSimpleAndFloat|additionalTypeBreak)
+}
+
+// AppendArrayDelim adds markers to indicate end of a particular array element.
+func (Encoder) AppendArrayDelim(dst []byte) []byte {
+	//No delimiters needed in cbor
+	return dst
+}
+
+// AppendLineBreak is a noop that keep API compat with json encoder.
+func (Encoder) AppendLineBreak(dst []byte) []byte {
+	// No line breaks needed in binary format.
+	return dst
+}
+
+// AppendBool encodes and inserts a boolean value into the dst byte array.
+func (Encoder) AppendBool(dst []byte, val bool) []byte {
+	b := additionalTypeBoolFalse
+	if val {
+		b = additionalTypeBoolTrue
+	}
+	return append(dst, majorTypeSimpleAndFloat|b)
+}
+
+// AppendBools encodes and inserts an array of boolean values into the dst byte array.
+func (e Encoder) AppendBools(dst []byte, vals []bool) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendBool(dst, v)
+	}
+	return dst
+}
+
+// AppendInt encodes and inserts an integer value into the dst byte array.
+func (Encoder) AppendInt(dst []byte, val int) []byte {
+	major := majorTypeUnsignedInt
+	contentVal := val
+	if val < 0 {
+		major = majorTypeNegativeInt
+		contentVal = -val - 1
+	}
+	if contentVal <= additionalMax {
+		lb := byte(contentVal)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(contentVal))
+	}
+	return dst
+}
+
+// AppendInts encodes and inserts an array of integer values into the dst byte array.
+func (e Encoder) AppendInts(dst []byte, vals []int) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendInt(dst, v)
+	}
+	return dst
+}
+
+// AppendInt8 encodes and inserts an int8 value into the dst byte array.
+func (e Encoder) AppendInt8(dst []byte, val int8) []byte {
+	return e.AppendInt(dst, int(val))
+}
+
+// AppendInts8 encodes and inserts an array of integer values into the dst byte array.
+func (e Encoder) AppendInts8(dst []byte, vals []int8) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendInt(dst, int(v))
+	}
+	return dst
+}
+
+// AppendInt16 encodes and inserts a int16 value into the dst byte array.
+func (e Encoder) AppendInt16(dst []byte, val int16) []byte {
+	return e.AppendInt(dst, int(val))
+}
+
+// AppendInts16 encodes and inserts an array of int16 values into the dst byte array.
+func (e Encoder) AppendInts16(dst []byte, vals []int16) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendInt(dst, int(v))
+	}
+	return dst
+}
+
+// AppendInt32 encodes and inserts a int32 value into the dst byte array.
+func (e Encoder) AppendInt32(dst []byte, val int32) []byte {
+	return e.AppendInt(dst, int(val))
+}
+
+// AppendInts32 encodes and inserts an array of int32 values into the dst byte array.
+func (e Encoder) AppendInts32(dst []byte, vals []int32) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendInt(dst, int(v))
+	}
+	return dst
+}
+
+// AppendInt64 encodes and inserts a int64 value into the dst byte array.
+func (Encoder) AppendInt64(dst []byte, val int64) []byte {
+	major := majorTypeUnsignedInt
+	contentVal := val
+	if val < 0 {
+		major = majorTypeNegativeInt
+		contentVal = -val - 1
+	}
+	if contentVal <= additionalMax {
+		lb := byte(contentVal)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(contentVal))
+	}
+	return dst
+}
+
+// AppendInts64 encodes and inserts an array of int64 values into the dst byte array.
+func (e Encoder) AppendInts64(dst []byte, vals []int64) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendInt64(dst, v)
+	}
+	return dst
+}
+
+// AppendUint encodes and inserts an unsigned integer value into the dst byte array.
+func (e Encoder) AppendUint(dst []byte, val uint) []byte {
+	return e.AppendInt64(dst, int64(val))
+}
+
+// AppendUints encodes and inserts an array of unsigned integer values into the dst byte array.
+func (e Encoder) AppendUints(dst []byte, vals []uint) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendUint(dst, v)
+	}
+	return dst
+}
+
+// AppendUint8 encodes and inserts a unsigned int8 value into the dst byte array.
+func (e Encoder) AppendUint8(dst []byte, val uint8) []byte {
+	return e.AppendUint(dst, uint(val))
+}
+
+// AppendUints8 encodes and inserts an array of uint8 values into the dst byte array.
+func (e Encoder) AppendUints8(dst []byte, vals []uint8) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendUint8(dst, v)
+	}
+	return dst
+}
+
+// AppendUint16 encodes and inserts a uint16 value into the dst byte array.
+func (e Encoder) AppendUint16(dst []byte, val uint16) []byte {
+	return e.AppendUint(dst, uint(val))
+}
+
+// AppendUints16 encodes and inserts an array of uint16 values into the dst byte array.
+func (e Encoder) AppendUints16(dst []byte, vals []uint16) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendUint16(dst, v)
+	}
+	return dst
+}
+
+// AppendUint32 encodes and inserts a uint32 value into the dst byte array.
+func (e Encoder) AppendUint32(dst []byte, val uint32) []byte {
+	return e.AppendUint(dst, uint(val))
+}
+
+// AppendUints32 encodes and inserts an array of uint32 values into the dst byte array.
+func (e Encoder) AppendUints32(dst []byte, vals []uint32) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendUint32(dst, v)
+	}
+	return dst
+}
+
+// AppendUint64 encodes and inserts a uint64 value into the dst byte array.
+func (Encoder) AppendUint64(dst []byte, val uint64) []byte {
+	major := majorTypeUnsignedInt
+	contentVal := val
+	if contentVal <= additionalMax {
+		lb := byte(contentVal)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, contentVal)
+	}
+	return dst
+}
+
+// AppendUints64 encodes and inserts an array of uint64 values into the dst byte array.
+func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendUint64(dst, v)
+	}
+	return dst
+}
+
+// AppendFloat32 encodes and inserts a single precision float value into the dst byte array.
+func (Encoder) AppendFloat32(dst []byte, val float32, unused int) []byte {
+	switch {
+	case math.IsNaN(float64(val)):
+		return append(dst, "\xfa\x7f\xc0\x00\x00"...)
+	case math.IsInf(float64(val), 1):
+		return append(dst, "\xfa\x7f\x80\x00\x00"...)
+	case math.IsInf(float64(val), -1):
+		return append(dst, "\xfa\xff\x80\x00\x00"...)
+	}
+	major := majorTypeSimpleAndFloat
+	subType := additionalTypeFloat32
+	n := math.Float32bits(val)
+	var buf [4]byte
+	for i := uint(0); i < 4; i++ {
+		buf[i] = byte(n >> ((3 - i) * 8))
+	}
+	return append(append(dst, major|subType), buf[0], buf[1], buf[2], buf[3])
+}
+
+// AppendFloats32 encodes and inserts an array of single precision float value into the dst byte array.
+func (e Encoder) AppendFloats32(dst []byte, vals []float32, unused int) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendFloat32(dst, v, unused)
+	}
+	return dst
+}
+
+// AppendFloat64 encodes and inserts a double precision float value into the dst byte array.
+func (Encoder) AppendFloat64(dst []byte, val float64, unused int) []byte {
+	switch {
+	case math.IsNaN(val):
+		return append(dst, "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"...)
+	case math.IsInf(val, 1):
+		return append(dst, "\xfb\x7f\xf0\x00\x00\x00\x00\x00\x00"...)
+	case math.IsInf(val, -1):
+		return append(dst, "\xfb\xff\xf0\x00\x00\x00\x00\x00\x00"...)
+	}
+	major := majorTypeSimpleAndFloat
+	subType := additionalTypeFloat64
+	n := math.Float64bits(val)
+	dst = append(dst, major|subType)
+	for i := uint(1); i <= 8; i++ {
+		b := byte(n >> ((8 - i) * 8))
+		dst = append(dst, b)
+	}
+	return dst
+}
+
+// AppendFloats64 encodes and inserts an array of double precision float values into the dst byte array.
+func (e Encoder) AppendFloats64(dst []byte, vals []float64, unused int) []byte {
+	major := majorTypeArray
+	l := len(vals)
+	if l == 0 {
+		return e.AppendArrayEnd(e.AppendArrayStart(dst))
+	}
+	if l <= additionalMax {
+		lb := byte(l)
+		dst = append(dst, major|lb)
+	} else {
+		dst = appendCborTypePrefix(dst, major, uint64(l))
+	}
+	for _, v := range vals {
+		dst = e.AppendFloat64(dst, v, unused)
+	}
+	return dst
+}
+
+// AppendInterface takes an arbitrary object and converts it to JSON and embeds it dst.
+func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
+	marshaled, err := JSONMarshalFunc(i)
+	if err != nil {
+		return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))
+	}
+	return AppendEmbeddedJSON(dst, marshaled)
+}
+
+// AppendType appends the parameter type (as a string) to the input byte slice.
+func (e Encoder) AppendType(dst []byte, i interface{}) []byte {
+	if i == nil {
+		return e.AppendString(dst, "<nil>")
+	}
+	return e.AppendString(dst, reflect.TypeOf(i).String())
+}
+
+// AppendIPAddr encodes and inserts an IP Address (IPv4 or IPv6).
+func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte {
+	dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+	dst = append(dst, byte(additionalTypeTagNetworkAddr>>8))
+	dst = append(dst, byte(additionalTypeTagNetworkAddr&0xff))
+	return e.AppendBytes(dst, ip)
+}
+
+// AppendIPPrefix encodes and inserts an IP Address Prefix (Address + Mask Length).
+func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte {
+	dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+	dst = append(dst, byte(additionalTypeTagNetworkPrefix>>8))
+	dst = append(dst, byte(additionalTypeTagNetworkPrefix&0xff))
+
+	// Prefix is a tuple (aka MAP of 1 pair of elements) -
+	// first element is prefix, second is mask length.
+	dst = append(dst, majorTypeMap|0x1)
+	dst = e.AppendBytes(dst, pfx.IP)
+	maskLen, _ := pfx.Mask.Size()
+	return e.AppendUint8(dst, uint8(maskLen))
+}
+
+// AppendMACAddr encodes and inserts a Hardware (MAC) address.
+func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte {
+	dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+	dst = append(dst, byte(additionalTypeTagNetworkAddr>>8))
+	dst = append(dst, byte(additionalTypeTagNetworkAddr&0xff))
+	return e.AppendBytes(dst, ha)
+}
+
+// AppendHex adds a TAG and inserts a hex bytes as a string.
+func (e Encoder) AppendHex(dst []byte, val []byte) []byte {
+	dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+	dst = append(dst, byte(additionalTypeTagHexString>>8))
+	dst = append(dst, byte(additionalTypeTagHexString&0xff))
+	return e.AppendBytes(dst, val)
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/base.go b/vendor/github.com/rs/zerolog/internal/json/base.go
new file mode 100644
index 0000000..09ec59f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/base.go
@@ -0,0 +1,19 @@
+package json
+
+// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice.
+// Making it package level instead of embedded in Encoder brings
+// some extra efforts at importing, but avoids value copy when the functions
+// of Encoder being invoked.
+// DO REMEMBER to set this variable at importing, or
+// you might get a nil pointer dereference panic at runtime.
+var JSONMarshalFunc func(v interface{}) ([]byte, error)
+
+type Encoder struct{}
+
+// AppendKey appends a new key to the output JSON.
+func (e Encoder) AppendKey(dst []byte, key string) []byte {
+	if dst[len(dst)-1] != '{' {
+		dst = append(dst, ',')
+	}
+	return append(e.AppendString(dst, key), ':')
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/bytes.go b/vendor/github.com/rs/zerolog/internal/json/bytes.go
new file mode 100644
index 0000000..de64120
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/bytes.go
@@ -0,0 +1,85 @@
+package json
+
+import "unicode/utf8"
+
+// AppendBytes is a mirror of appendString with []byte arg
+func (Encoder) AppendBytes(dst, s []byte) []byte {
+	dst = append(dst, '"')
+	for i := 0; i < len(s); i++ {
+		if !noEscapeTable[s[i]] {
+			dst = appendBytesComplex(dst, s, i)
+			return append(dst, '"')
+		}
+	}
+	dst = append(dst, s...)
+	return append(dst, '"')
+}
+
+// AppendHex encodes the input bytes to a hex string and appends
+// the encoded string to the input byte slice.
+//
+// The operation loops though each byte and encodes it as hex using
+// the hex lookup table.
+func (Encoder) AppendHex(dst, s []byte) []byte {
+	dst = append(dst, '"')
+	for _, v := range s {
+		dst = append(dst, hex[v>>4], hex[v&0x0f])
+	}
+	return append(dst, '"')
+}
+
+// appendBytesComplex is a mirror of the appendStringComplex
+// with []byte arg
+func appendBytesComplex(dst, s []byte, i int) []byte {
+	start := 0
+	for i < len(s) {
+		b := s[i]
+		if b >= utf8.RuneSelf {
+			r, size := utf8.DecodeRune(s[i:])
+			if r == utf8.RuneError && size == 1 {
+				if start < i {
+					dst = append(dst, s[start:i]...)
+				}
+				dst = append(dst, `\ufffd`...)
+				i += size
+				start = i
+				continue
+			}
+			i += size
+			continue
+		}
+		if noEscapeTable[b] {
+			i++
+			continue
+		}
+		// We encountered a character that needs to be encoded.
+		// Let's append the previous simple characters to the byte slice
+		// and switch our operation to read and encode the remainder
+		// characters byte-by-byte.
+		if start < i {
+			dst = append(dst, s[start:i]...)
+		}
+		switch b {
+		case '"', '\\':
+			dst = append(dst, '\\', b)
+		case '\b':
+			dst = append(dst, '\\', 'b')
+		case '\f':
+			dst = append(dst, '\\', 'f')
+		case '\n':
+			dst = append(dst, '\\', 'n')
+		case '\r':
+			dst = append(dst, '\\', 'r')
+		case '\t':
+			dst = append(dst, '\\', 't')
+		default:
+			dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])
+		}
+		i++
+		start = i
+	}
+	if start < len(s) {
+		dst = append(dst, s[start:]...)
+	}
+	return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/string.go b/vendor/github.com/rs/zerolog/internal/json/string.go
new file mode 100644
index 0000000..fd7770f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/string.go
@@ -0,0 +1,149 @@
+package json
+
+import (
+	"fmt"
+	"unicode/utf8"
+)
+
+const hex = "0123456789abcdef"
+
+var noEscapeTable = [256]bool{}
+
+func init() {
+	for i := 0; i <= 0x7e; i++ {
+		noEscapeTable[i] = i >= 0x20 && i != '\\' && i != '"'
+	}
+}
+
+// AppendStrings encodes the input strings to json and
+// appends the encoded string list to the input byte slice.
+func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = e.AppendString(dst, vals[0])
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = e.AppendString(append(dst, ','), val)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendString encodes the input string to json and appends
+// the encoded string to the input byte slice.
+//
+// The operation loops though each byte in the string looking
+// for characters that need json or utf8 encoding. If the string
+// does not need encoding, then the string is appended in its
+// entirety to the byte slice.
+// If we encounter a byte that does need encoding, switch up
+// the operation and perform a byte-by-byte read-encode-append.
+func (Encoder) AppendString(dst []byte, s string) []byte {
+	// Start with a double quote.
+	dst = append(dst, '"')
+	// Loop through each character in the string.
+	for i := 0; i < len(s); i++ {
+		// Check if the character needs encoding. Control characters, slashes,
+		// and the double quote need json encoding. Bytes above the ascii
+		// boundary needs utf8 encoding.
+		if !noEscapeTable[s[i]] {
+			// We encountered a character that needs to be encoded. Switch
+			// to complex version of the algorithm.
+			dst = appendStringComplex(dst, s, i)
+			return append(dst, '"')
+		}
+	}
+	// The string has no need for encoding and therefore is directly
+	// appended to the byte slice.
+	dst = append(dst, s...)
+	// End with a double quote
+	return append(dst, '"')
+}
+
+// AppendStringers encodes the provided Stringer list to json and
+// appends the encoded Stringer list to the input byte slice.
+func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = e.AppendStringer(dst, vals[0])
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = e.AppendStringer(append(dst, ','), val)
+		}
+	}
+	return append(dst, ']')
+}
+
+// AppendStringer encodes the input Stringer to json and appends the
+// encoded Stringer value to the input byte slice.
+func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte {
+	if val == nil {
+		return e.AppendInterface(dst, nil)
+	}
+	return e.AppendString(dst, val.String())
+}
+
+//// appendStringComplex is used by appendString to take over an in
+// progress JSON string encoding that encountered a character that needs
+// to be encoded.
+func appendStringComplex(dst []byte, s string, i int) []byte {
+	start := 0
+	for i < len(s) {
+		b := s[i]
+		if b >= utf8.RuneSelf {
+			r, size := utf8.DecodeRuneInString(s[i:])
+			if r == utf8.RuneError && size == 1 {
+				// In case of error, first append previous simple characters to
+				// the byte slice if any and append a replacement character code
+				// in place of the invalid sequence.
+				if start < i {
+					dst = append(dst, s[start:i]...)
+				}
+				dst = append(dst, `\ufffd`...)
+				i += size
+				start = i
+				continue
+			}
+			i += size
+			continue
+		}
+		if noEscapeTable[b] {
+			i++
+			continue
+		}
+		// We encountered a character that needs to be encoded.
+		// Let's append the previous simple characters to the byte slice
+		// and switch our operation to read and encode the remainder
+		// characters byte-by-byte.
+		if start < i {
+			dst = append(dst, s[start:i]...)
+		}
+		switch b {
+		case '"', '\\':
+			dst = append(dst, '\\', b)
+		case '\b':
+			dst = append(dst, '\\', 'b')
+		case '\f':
+			dst = append(dst, '\\', 'f')
+		case '\n':
+			dst = append(dst, '\\', 'n')
+		case '\r':
+			dst = append(dst, '\\', 'r')
+		case '\t':
+			dst = append(dst, '\\', 't')
+		default:
+			dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])
+		}
+		i++
+		start = i
+	}
+	if start < len(s) {
+		dst = append(dst, s[start:]...)
+	}
+	return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/time.go b/vendor/github.com/rs/zerolog/internal/json/time.go
new file mode 100644
index 0000000..08cbbd9
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/time.go
@@ -0,0 +1,113 @@
+package json
+
+import (
+	"strconv"
+	"time"
+)
+
+const (
+	// Import from zerolog/global.go
+	timeFormatUnix      = ""
+	timeFormatUnixMs    = "UNIXMS"
+	timeFormatUnixMicro = "UNIXMICRO"
+	timeFormatUnixNano  = "UNIXNANO"
+)
+
+// AppendTime formats the input time with the given format
+// and appends the encoded string to the input byte slice.
+func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte {
+	switch format {
+	case timeFormatUnix:
+		return e.AppendInt64(dst, t.Unix())
+	case timeFormatUnixMs:
+		return e.AppendInt64(dst, t.UnixNano()/1000000)
+	case timeFormatUnixMicro:
+		return e.AppendInt64(dst, t.UnixNano()/1000)
+	case timeFormatUnixNano:
+		return e.AppendInt64(dst, t.UnixNano())
+	}
+	return append(t.AppendFormat(append(dst, '"'), format), '"')
+}
+
+// AppendTimes converts the input times with the given format
+// and appends the encoded string list to the input byte slice.
+func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) []byte {
+	switch format {
+	case timeFormatUnix:
+		return appendUnixTimes(dst, vals)
+	case timeFormatUnixMs:
+		return appendUnixNanoTimes(dst, vals, 1000000)
+	case timeFormatUnixMicro:
+		return appendUnixNanoTimes(dst, vals, 1000)
+	case timeFormatUnixNano:
+		return appendUnixNanoTimes(dst, vals, 1)
+	}
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = append(vals[0].AppendFormat(append(dst, '"'), format), '"')
+	if len(vals) > 1 {
+		for _, t := range vals[1:] {
+			dst = append(t.AppendFormat(append(dst, ',', '"'), format), '"')
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+func appendUnixTimes(dst []byte, vals []time.Time) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, vals[0].Unix(), 10)
+	if len(vals) > 1 {
+		for _, t := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), t.Unix(), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, vals[0].UnixNano()/div, 10)
+	if len(vals) > 1 {
+		for _, t := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/div, 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendDuration formats the input duration with the given unit & format
+// and appends the encoded string to the input byte slice.
+func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte {
+	if useInt {
+		return strconv.AppendInt(dst, int64(d/unit), 10)
+	}
+	return e.AppendFloat64(dst, float64(d)/float64(unit), precision)
+}
+
+// AppendDurations formats the input durations with the given unit & format
+// and appends the encoded string list to the input byte slice.
+func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = e.AppendDuration(dst, vals[0], unit, useInt, precision)
+	if len(vals) > 1 {
+		for _, d := range vals[1:] {
+			dst = e.AppendDuration(append(dst, ','), d, unit, useInt, precision)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/types.go b/vendor/github.com/rs/zerolog/internal/json/types.go
new file mode 100644
index 0000000..7930491
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/types.go
@@ -0,0 +1,435 @@
+package json
+
+import (
+	"fmt"
+	"math"
+	"net"
+	"reflect"
+	"strconv"
+)
+
+// AppendNil inserts a 'Nil' object into the dst byte array.
+func (Encoder) AppendNil(dst []byte) []byte {
+	return append(dst, "null"...)
+}
+
+// AppendBeginMarker inserts a map start into the dst byte array.
+func (Encoder) AppendBeginMarker(dst []byte) []byte {
+	return append(dst, '{')
+}
+
+// AppendEndMarker inserts a map end into the dst byte array.
+func (Encoder) AppendEndMarker(dst []byte) []byte {
+	return append(dst, '}')
+}
+
+// AppendLineBreak appends a line break.
+func (Encoder) AppendLineBreak(dst []byte) []byte {
+	return append(dst, '\n')
+}
+
+// AppendArrayStart adds markers to indicate the start of an array.
+func (Encoder) AppendArrayStart(dst []byte) []byte {
+	return append(dst, '[')
+}
+
+// AppendArrayEnd adds markers to indicate the end of an array.
+func (Encoder) AppendArrayEnd(dst []byte) []byte {
+	return append(dst, ']')
+}
+
+// AppendArrayDelim adds markers to indicate end of a particular array element.
+func (Encoder) AppendArrayDelim(dst []byte) []byte {
+	if len(dst) > 0 {
+		return append(dst, ',')
+	}
+	return dst
+}
+
+// AppendBool converts the input bool to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendBool(dst []byte, val bool) []byte {
+	return strconv.AppendBool(dst, val)
+}
+
+// AppendBools encodes the input bools to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendBools(dst []byte, vals []bool) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendBool(dst, vals[0])
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendBool(append(dst, ','), val)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendInt converts the input int to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt(dst []byte, val int) []byte {
+	return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts encodes the input ints to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts(dst []byte, vals []int) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendInt8 converts the input []int8 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt8(dst []byte, val int8) []byte {
+	return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts8 encodes the input int8s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts8(dst []byte, vals []int8) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendInt16 converts the input int16 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt16(dst []byte, val int16) []byte {
+	return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts16 encodes the input int16s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts16(dst []byte, vals []int16) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendInt32 converts the input int32 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt32(dst []byte, val int32) []byte {
+	return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts32 encodes the input int32s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts32(dst []byte, vals []int32) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendInt64 converts the input int64 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt64(dst []byte, val int64) []byte {
+	return strconv.AppendInt(dst, val, 10)
+}
+
+// AppendInts64 encodes the input int64s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts64(dst []byte, vals []int64) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendInt(dst, vals[0], 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendInt(append(dst, ','), val, 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendUint converts the input uint to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint(dst []byte, val uint) []byte {
+	return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints encodes the input uints to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints(dst []byte, vals []uint) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendUint8 converts the input uint8 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint8(dst []byte, val uint8) []byte {
+	return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints8 encodes the input uint8s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints8(dst []byte, vals []uint8) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendUint16 converts the input uint16 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint16(dst []byte, val uint16) []byte {
+	return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints16 encodes the input uint16s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints16(dst []byte, vals []uint16) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendUint32 converts the input uint32 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint32(dst []byte, val uint32) []byte {
+	return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints32 encodes the input uint32s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints32(dst []byte, vals []uint32) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendUint64 converts the input uint64 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint64(dst []byte, val uint64) []byte {
+	return strconv.AppendUint(dst, val, 10)
+}
+
+// AppendUints64 encodes the input uint64s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = strconv.AppendUint(dst, vals[0], 10)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = strconv.AppendUint(append(dst, ','), val, 10)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+func appendFloat(dst []byte, val float64, bitSize, precision int) []byte {
+	// JSON does not permit NaN or Infinity. A typical JSON encoder would fail
+	// with an error, but a logging library wants the data to get through so we
+	// make a tradeoff and store those types as string.
+	switch {
+	case math.IsNaN(val):
+		return append(dst, `"NaN"`...)
+	case math.IsInf(val, 1):
+		return append(dst, `"+Inf"`...)
+	case math.IsInf(val, -1):
+		return append(dst, `"-Inf"`...)
+	}
+	// convert as if by es6 number to string conversion
+	// see also https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/encoding/json/encode.go;l=573
+	strFmt := byte('f')
+	// If precision is set to a value other than -1, we always just format the float using that precision.
+	if precision == -1 {
+		// Use float32 comparisons for underlying float32 value to get precise cutoffs right.
+		if abs := math.Abs(val); abs != 0 {
+			if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
+				strFmt = 'e'
+			}
+		}
+	}
+	dst = strconv.AppendFloat(dst, val, strFmt, precision, bitSize)
+	if strFmt == 'e' {
+		// Clean up e-09 to e-9
+		n := len(dst)
+		if n >= 4 && dst[n-4] == 'e' && dst[n-3] == '-' && dst[n-2] == '0' {
+			dst[n-2] = dst[n-1]
+			dst = dst[:n-1]
+		}
+	}
+	return dst
+}
+
+// AppendFloat32 converts the input float32 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendFloat32(dst []byte, val float32, precision int) []byte {
+	return appendFloat(dst, float64(val), 32, precision)
+}
+
+// AppendFloats32 encodes the input float32s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendFloats32(dst []byte, vals []float32, precision int) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = appendFloat(dst, float64(vals[0]), 32, precision)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = appendFloat(append(dst, ','), float64(val), 32, precision)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendFloat64 converts the input float64 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendFloat64(dst []byte, val float64, precision int) []byte {
+	return appendFloat(dst, val, 64, precision)
+}
+
+// AppendFloats64 encodes the input float64s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendFloats64(dst []byte, vals []float64, precision int) []byte {
+	if len(vals) == 0 {
+		return append(dst, '[', ']')
+	}
+	dst = append(dst, '[')
+	dst = appendFloat(dst, vals[0], 64, precision)
+	if len(vals) > 1 {
+		for _, val := range vals[1:] {
+			dst = appendFloat(append(dst, ','), val, 64, precision)
+		}
+	}
+	dst = append(dst, ']')
+	return dst
+}
+
+// AppendInterface marshals the input interface to a string and
+// appends the encoded string to the input byte slice.
+func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
+	marshaled, err := JSONMarshalFunc(i)
+	if err != nil {
+		return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))
+	}
+	return append(dst, marshaled...)
+}
+
+// AppendType appends the parameter type (as a string) to the input byte slice.
+func (e Encoder) AppendType(dst []byte, i interface{}) []byte {
+	if i == nil {
+		return e.AppendString(dst, "<nil>")
+	}
+	return e.AppendString(dst, reflect.TypeOf(i).String())
+}
+
+// AppendObjectData takes in an object that is already in a byte array
+// and adds it to the dst.
+func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
+	// Three conditions apply here:
+	// 1. new content starts with '{' - which should be dropped   OR
+	// 2. new content starts with '{' - which should be replaced with ','
+	//    to separate with existing content OR
+	// 3. existing content has already other fields
+	if o[0] == '{' {
+		if len(dst) > 1 {
+			dst = append(dst, ',')
+		}
+		o = o[1:]
+	} else if len(dst) > 1 {
+		dst = append(dst, ',')
+	}
+	return append(dst, o...)
+}
+
+// AppendIPAddr adds IPv4 or IPv6 address to dst.
+func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte {
+	return e.AppendString(dst, ip.String())
+}
+
+// AppendIPPrefix adds IPv4 or IPv6 Prefix (address & mask) to dst.
+func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte {
+	return e.AppendString(dst, pfx.String())
+
+}
+
+// AppendMACAddr adds MAC address to dst.
+func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte {
+	return e.AppendString(dst, ha.String())
+}