github.com/resin-io/docker@v1.13.1/pkg/jsonlog/jsonlogbytes.go (about) 1 package jsonlog 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "unicode/utf8" 7 ) 8 9 // JSONLogs is based on JSONLog. 10 // It allows marshalling JSONLog from Log as []byte 11 // and an already marshalled Created timestamp. 12 type JSONLogs struct { 13 Log []byte `json:"log,omitempty"` 14 Stream string `json:"stream,omitempty"` 15 Created string `json:"time"` 16 17 // json-encoded bytes 18 RawAttrs json.RawMessage `json:"attrs,omitempty"` 19 } 20 21 // MarshalJSONBuf is based on the same method from JSONLog 22 // It has been modified to take into account the necessary changes. 23 func (mj *JSONLogs) MarshalJSONBuf(buf *bytes.Buffer) error { 24 var first = true 25 26 buf.WriteString(`{`) 27 if len(mj.Log) != 0 { 28 first = false 29 buf.WriteString(`"log":`) 30 ffjsonWriteJSONBytesAsString(buf, mj.Log) 31 } 32 if len(mj.Stream) != 0 { 33 if first == true { 34 first = false 35 } else { 36 buf.WriteString(`,`) 37 } 38 buf.WriteString(`"stream":`) 39 ffjsonWriteJSONString(buf, mj.Stream) 40 } 41 if len(mj.RawAttrs) > 0 { 42 if first { 43 first = false 44 } else { 45 buf.WriteString(`,`) 46 } 47 buf.WriteString(`"attrs":`) 48 buf.Write(mj.RawAttrs) 49 } 50 if !first { 51 buf.WriteString(`,`) 52 } 53 buf.WriteString(`"time":`) 54 buf.WriteString(mj.Created) 55 buf.WriteString(`}`) 56 return nil 57 } 58 59 // This is based on ffjsonWriteJSONBytesAsString. It has been changed 60 // to accept a string passed as a slice of bytes. 61 func ffjsonWriteJSONBytesAsString(buf *bytes.Buffer, s []byte) { 62 const hex = "0123456789abcdef" 63 64 buf.WriteByte('"') 65 start := 0 66 for i := 0; i < len(s); { 67 if b := s[i]; b < utf8.RuneSelf { 68 if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { 69 i++ 70 continue 71 } 72 if start < i { 73 buf.Write(s[start:i]) 74 } 75 switch b { 76 case '\\', '"': 77 buf.WriteByte('\\') 78 buf.WriteByte(b) 79 case '\n': 80 buf.WriteByte('\\') 81 buf.WriteByte('n') 82 case '\r': 83 buf.WriteByte('\\') 84 buf.WriteByte('r') 85 default: 86 87 buf.WriteString(`\u00`) 88 buf.WriteByte(hex[b>>4]) 89 buf.WriteByte(hex[b&0xF]) 90 } 91 i++ 92 start = i 93 continue 94 } 95 c, size := utf8.DecodeRune(s[i:]) 96 if c == utf8.RuneError && size == 1 { 97 if start < i { 98 buf.Write(s[start:i]) 99 } 100 buf.WriteString(`\ufffd`) 101 i += size 102 start = i 103 continue 104 } 105 106 if c == '\u2028' || c == '\u2029' { 107 if start < i { 108 buf.Write(s[start:i]) 109 } 110 buf.WriteString(`\u202`) 111 buf.WriteByte(hex[c&0xF]) 112 i += size 113 start = i 114 continue 115 } 116 i += size 117 } 118 if start < len(s) { 119 buf.Write(s[start:]) 120 } 121 buf.WriteByte('"') 122 }