github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/logger/jsonfilelog/jsonlog/jsonlogbytes.go (about) 1 package jsonlog // import "github.com/demonoid81/moby/daemon/logger/jsonfilelog/jsonlog" 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "time" 7 "unicode/utf8" 8 ) 9 10 // JSONLogs marshals encoded JSONLog objects 11 type JSONLogs struct { 12 Log []byte `json:"log,omitempty"` 13 Stream string `json:"stream,omitempty"` 14 Created time.Time `json:"time"` 15 16 // json-encoded bytes 17 RawAttrs json.RawMessage `json:"attrs,omitempty"` 18 } 19 20 // MarshalJSONBuf is an optimized JSON marshaller that avoids reflection 21 // and unnecessary allocation. 22 func (mj *JSONLogs) MarshalJSONBuf(buf *bytes.Buffer) error { 23 var first = true 24 25 buf.WriteString(`{`) 26 if len(mj.Log) != 0 { 27 first = false 28 buf.WriteString(`"log":`) 29 ffjsonWriteJSONBytesAsString(buf, mj.Log) 30 } 31 if len(mj.Stream) != 0 { 32 if first { 33 first = false 34 } else { 35 buf.WriteString(`,`) 36 } 37 buf.WriteString(`"stream":`) 38 ffjsonWriteJSONBytesAsString(buf, []byte(mj.Stream)) 39 } 40 if len(mj.RawAttrs) > 0 { 41 if first { 42 first = false 43 } else { 44 buf.WriteString(`,`) 45 } 46 buf.WriteString(`"attrs":`) 47 buf.Write(mj.RawAttrs) 48 } 49 if !first { 50 buf.WriteString(`,`) 51 } 52 53 created, err := fastTimeMarshalJSON(mj.Created) 54 if err != nil { 55 return err 56 } 57 58 buf.WriteString(`"time":`) 59 buf.WriteString(created) 60 buf.WriteString(`}`) 61 return nil 62 } 63 64 func ffjsonWriteJSONBytesAsString(buf *bytes.Buffer, s []byte) { 65 const hex = "0123456789abcdef" 66 67 buf.WriteByte('"') 68 start := 0 69 for i := 0; i < len(s); { 70 if b := s[i]; b < utf8.RuneSelf { 71 if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { 72 i++ 73 continue 74 } 75 if start < i { 76 buf.Write(s[start:i]) 77 } 78 switch b { 79 case '\\', '"': 80 buf.WriteByte('\\') 81 buf.WriteByte(b) 82 case '\n': 83 buf.WriteByte('\\') 84 buf.WriteByte('n') 85 case '\r': 86 buf.WriteByte('\\') 87 buf.WriteByte('r') 88 default: 89 90 buf.WriteString(`\u00`) 91 buf.WriteByte(hex[b>>4]) 92 buf.WriteByte(hex[b&0xF]) 93 } 94 i++ 95 start = i 96 continue 97 } 98 c, size := utf8.DecodeRune(s[i:]) 99 if c == utf8.RuneError && size == 1 { 100 if start < i { 101 buf.Write(s[start:i]) 102 } 103 buf.WriteString(`\ufffd`) 104 i += size 105 start = i 106 continue 107 } 108 109 if c == '\u2028' || c == '\u2029' { 110 if start < i { 111 buf.Write(s[start:i]) 112 } 113 buf.WriteString(`\u202`) 114 buf.WriteByte(hex[c&0xF]) 115 i += size 116 start = i 117 continue 118 } 119 i += size 120 } 121 if start < len(s) { 122 buf.Write(s[start:]) 123 } 124 buf.WriteByte('"') 125 }