Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -147,9 +147,8 @@ func tailFile(f io.ReadSeeker, logWatcher *logger.LogWatcher, tail int, since ti |
| 147 | 147 |
rdr = bytes.NewBuffer(bytes.Join(ls, []byte("\n")))
|
| 148 | 148 |
} |
| 149 | 149 |
dec := json.NewDecoder(rdr) |
| 150 |
- l := &jsonlog.JSONLog{}
|
|
| 151 | 150 |
for {
|
| 152 |
- msg, err := decodeLogLine(dec, l) |
|
| 151 |
+ msg, err := decodeLogLine(dec, &jsonlog.JSONLog{})
|
|
| 153 | 152 |
if err != nil {
|
| 154 | 153 |
if err != io.EOF {
|
| 155 | 154 |
logWatcher.Err <- err |
| 156 | 155 |
deleted file mode 100644 |
| ... | ... |
@@ -1,178 +0,0 @@ |
| 1 |
-// This code was initially generated by ffjson <https://github.com/pquerna/ffjson> |
|
| 2 |
-// This code was generated via the following steps: |
|
| 3 |
-// $ go get -u github.com/pquerna/ffjson |
|
| 4 |
-// $ make BIND_DIR=. shell |
|
| 5 |
-// $ ffjson pkg/jsonlog/jsonlog.go |
|
| 6 |
-// $ mv pkg/jsonglog/jsonlog_ffjson.go pkg/jsonlog/jsonlog_marshalling.go |
|
| 7 |
-// |
|
| 8 |
-// It has been modified to improve the performance of time marshalling to JSON |
|
| 9 |
-// and to clean it up. |
|
| 10 |
-// Should this code need to be regenerated when the JSONLog struct is changed, |
|
| 11 |
-// the relevant changes which have been made are: |
|
| 12 |
-// import ( |
|
| 13 |
-// "bytes" |
|
| 14 |
-//- |
|
| 15 |
-// "unicode/utf8" |
|
| 16 |
-// ) |
|
| 17 |
-// |
|
| 18 |
-// func (mj *JSONLog) MarshalJSON() ([]byte, error) {
|
|
| 19 |
-//@@ -20,13 +16,13 @@ func (mj *JSONLog) MarshalJSON() ([]byte, error) {
|
|
| 20 |
-// } |
|
| 21 |
-// return buf.Bytes(), nil |
|
| 22 |
-// } |
|
| 23 |
-//+ |
|
| 24 |
-// func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error {
|
|
| 25 |
-//- var err error |
|
| 26 |
-//- var obj []byte |
|
| 27 |
-//- var first bool = true |
|
| 28 |
-//- _ = obj |
|
| 29 |
-//- _ = err |
|
| 30 |
-//- _ = first |
|
| 31 |
-//+ var ( |
|
| 32 |
-//+ err error |
|
| 33 |
-//+ timestamp string |
|
| 34 |
-//+ first bool = true |
|
| 35 |
-//+ ) |
|
| 36 |
-// buf.WriteString(`{`)
|
|
| 37 |
-// if len(mj.Log) != 0 {
|
|
| 38 |
-// if first == true {
|
|
| 39 |
-//@@ -52,11 +48,11 @@ func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error {
|
|
| 40 |
-// buf.WriteString(`,`) |
|
| 41 |
-// } |
|
| 42 |
-// buf.WriteString(`"time":`) |
|
| 43 |
-//- obj, err = mj.Created.MarshalJSON() |
|
| 44 |
-//+ timestamp, err = FastTimeMarshalJSON(mj.Created) |
|
| 45 |
-// if err != nil {
|
|
| 46 |
-// return err |
|
| 47 |
-// } |
|
| 48 |
-//- buf.Write(obj) |
|
| 49 |
-//+ buf.WriteString(timestamp) |
|
| 50 |
-// buf.WriteString(`}`) |
|
| 51 |
-// return nil |
|
| 52 |
-// } |
|
| 53 |
-// @@ -81,9 +81,10 @@ func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error {
|
|
| 54 |
-// if len(mj.Log) != 0 {
|
|
| 55 |
-// - if first == true {
|
|
| 56 |
-// - first = false |
|
| 57 |
-// - } else {
|
|
| 58 |
-// - buf.WriteString(`,`) |
|
| 59 |
-// - } |
|
| 60 |
-// + first = false |
|
| 61 |
-// buf.WriteString(`"log":`) |
|
| 62 |
-// ffjsonWriteJSONString(buf, mj.Log) |
|
| 63 |
-// } |
|
| 64 |
- |
|
| 65 |
-package jsonlog |
|
| 66 |
- |
|
| 67 |
-import ( |
|
| 68 |
- "bytes" |
|
| 69 |
- "unicode/utf8" |
|
| 70 |
-) |
|
| 71 |
- |
|
| 72 |
-// MarshalJSON marshals the JSONLog. |
|
| 73 |
-func (mj *JSONLog) MarshalJSON() ([]byte, error) {
|
|
| 74 |
- var buf bytes.Buffer |
|
| 75 |
- buf.Grow(1024) |
|
| 76 |
- if err := mj.MarshalJSONBuf(&buf); err != nil {
|
|
| 77 |
- return nil, err |
|
| 78 |
- } |
|
| 79 |
- return buf.Bytes(), nil |
|
| 80 |
-} |
|
| 81 |
- |
|
| 82 |
-// MarshalJSONBuf marshals the JSONLog and stores the result to a bytes.Buffer. |
|
| 83 |
-func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error {
|
|
| 84 |
- var ( |
|
| 85 |
- err error |
|
| 86 |
- timestamp string |
|
| 87 |
- first = true |
|
| 88 |
- ) |
|
| 89 |
- buf.WriteString(`{`)
|
|
| 90 |
- if len(mj.Log) != 0 {
|
|
| 91 |
- first = false |
|
| 92 |
- buf.WriteString(`"log":`) |
|
| 93 |
- ffjsonWriteJSONString(buf, mj.Log) |
|
| 94 |
- } |
|
| 95 |
- if len(mj.Stream) != 0 {
|
|
| 96 |
- if first {
|
|
| 97 |
- first = false |
|
| 98 |
- } else {
|
|
| 99 |
- buf.WriteString(`,`) |
|
| 100 |
- } |
|
| 101 |
- buf.WriteString(`"stream":`) |
|
| 102 |
- ffjsonWriteJSONString(buf, mj.Stream) |
|
| 103 |
- } |
|
| 104 |
- if !first {
|
|
| 105 |
- buf.WriteString(`,`) |
|
| 106 |
- } |
|
| 107 |
- buf.WriteString(`"time":`) |
|
| 108 |
- timestamp, err = fastTimeMarshalJSON(mj.Created) |
|
| 109 |
- if err != nil {
|
|
| 110 |
- return err |
|
| 111 |
- } |
|
| 112 |
- buf.WriteString(timestamp) |
|
| 113 |
- buf.WriteString(`}`) |
|
| 114 |
- return nil |
|
| 115 |
-} |
|
| 116 |
- |
|
| 117 |
-func ffjsonWriteJSONString(buf *bytes.Buffer, s string) {
|
|
| 118 |
- const hex = "0123456789abcdef" |
|
| 119 |
- |
|
| 120 |
- buf.WriteByte('"')
|
|
| 121 |
- start := 0 |
|
| 122 |
- for i := 0; i < len(s); {
|
|
| 123 |
- if b := s[i]; b < utf8.RuneSelf {
|
|
| 124 |
- if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
|
|
| 125 |
- i++ |
|
| 126 |
- continue |
|
| 127 |
- } |
|
| 128 |
- if start < i {
|
|
| 129 |
- buf.WriteString(s[start:i]) |
|
| 130 |
- } |
|
| 131 |
- switch b {
|
|
| 132 |
- case '\\', '"': |
|
| 133 |
- buf.WriteByte('\\')
|
|
| 134 |
- buf.WriteByte(b) |
|
| 135 |
- case '\n': |
|
| 136 |
- buf.WriteByte('\\')
|
|
| 137 |
- buf.WriteByte('n')
|
|
| 138 |
- case '\r': |
|
| 139 |
- buf.WriteByte('\\')
|
|
| 140 |
- buf.WriteByte('r')
|
|
| 141 |
- default: |
|
| 142 |
- |
|
| 143 |
- buf.WriteString(`\u00`) |
|
| 144 |
- buf.WriteByte(hex[b>>4]) |
|
| 145 |
- buf.WriteByte(hex[b&0xF]) |
|
| 146 |
- } |
|
| 147 |
- i++ |
|
| 148 |
- start = i |
|
| 149 |
- continue |
|
| 150 |
- } |
|
| 151 |
- c, size := utf8.DecodeRuneInString(s[i:]) |
|
| 152 |
- if c == utf8.RuneError && size == 1 {
|
|
| 153 |
- if start < i {
|
|
| 154 |
- buf.WriteString(s[start:i]) |
|
| 155 |
- } |
|
| 156 |
- buf.WriteString(`\ufffd`) |
|
| 157 |
- i += size |
|
| 158 |
- start = i |
|
| 159 |
- continue |
|
| 160 |
- } |
|
| 161 |
- |
|
| 162 |
- if c == '\u2028' || c == '\u2029' {
|
|
| 163 |
- if start < i {
|
|
| 164 |
- buf.WriteString(s[start:i]) |
|
| 165 |
- } |
|
| 166 |
- buf.WriteString(`\u202`) |
|
| 167 |
- buf.WriteByte(hex[c&0xF]) |
|
| 168 |
- i += size |
|
| 169 |
- start = i |
|
| 170 |
- continue |
|
| 171 |
- } |
|
| 172 |
- i += size |
|
| 173 |
- } |
|
| 174 |
- if start < len(s) {
|
|
| 175 |
- buf.WriteString(s[start:]) |
|
| 176 |
- } |
|
| 177 |
- buf.WriteByte('"')
|
|
| 178 |
-} |
| 179 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,32 +0,0 @@ |
| 1 |
-package jsonlog |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "regexp" |
|
| 5 |
- "testing" |
|
| 6 |
- |
|
| 7 |
- "encoding/json" |
|
| 8 |
- "github.com/stretchr/testify/assert" |
|
| 9 |
- "github.com/stretchr/testify/require" |
|
| 10 |
-) |
|
| 11 |
- |
|
| 12 |
-func TestJSONLogMarshalJSON(t *testing.T) {
|
|
| 13 |
- logs := map[*JSONLog]string{
|
|
| 14 |
- {Log: `"A log line with \\"`}: `^{\"log\":\"\\\"A log line with \\\\\\\\\\\"\",\"time\":\".{20,}\"}$`,
|
|
| 15 |
- {Log: "A log line"}: `^{\"log\":\"A log line\",\"time\":\".{20,}\"}$`,
|
|
| 16 |
- {Log: "A log line with \r"}: `^{\"log\":\"A log line with \\r\",\"time\":\".{20,}\"}$`,
|
|
| 17 |
- {Log: "A log line with & < >"}: `^{\"log\":\"A log line with \\u0026 \\u003c \\u003e\",\"time\":\".{20,}\"}$`,
|
|
| 18 |
- {Log: "A log line with utf8 : 🚀 ψ ω β"}: `^{\"log\":\"A log line with utf8 : 🚀 ψ ω β\",\"time\":\".{20,}\"}$`,
|
|
| 19 |
- {Stream: "stdout"}: `^{\"stream\":\"stdout\",\"time\":\".{20,}\"}$`,
|
|
| 20 |
- {}: `^{\"time\":\".{20,}\"}$`,
|
|
| 21 |
- // These ones are a little weird |
|
| 22 |
- {Log: "\u2028 \u2029"}: `^{\"log\":\"\\u2028 \\u2029\",\"time\":\".{20,}\"}$`,
|
|
| 23 |
- {Log: string([]byte{0xaF})}: `^{\"log\":\"\\ufffd\",\"time\":\".{20,}\"}$`,
|
|
| 24 |
- {Log: string([]byte{0x7F})}: `^{\"log\":\"\x7f\",\"time\":\".{20,}\"}$`,
|
|
| 25 |
- } |
|
| 26 |
- for jsonLog, expression := range logs {
|
|
| 27 |
- data, err := jsonLog.MarshalJSON() |
|
| 28 |
- require.NoError(t, err) |
|
| 29 |
- assert.Regexp(t, regexp.MustCompile(expression), string(data)) |
|
| 30 |
- assert.NoError(t, json.Unmarshal(data, &map[string]interface{}{}))
|
|
| 31 |
- } |
|
| 32 |
-} |
| ... | ... |
@@ -61,8 +61,72 @@ func (mj *JSONLogs) MarshalJSONBuf(buf *bytes.Buffer) error {
|
| 61 | 61 |
return nil |
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 |
-// This is based on ffjsonWriteJSONBytesAsString. It has been changed |
|
| 64 |
+func ffjsonWriteJSONString(buf *bytes.Buffer, s string) {
|
|
| 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.WriteString(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.DecodeRuneInString(s[i:]) |
|
| 99 |
+ if c == utf8.RuneError && size == 1 {
|
|
| 100 |
+ if start < i {
|
|
| 101 |
+ buf.WriteString(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.WriteString(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.WriteString(s[start:]) |
|
| 123 |
+ } |
|
| 124 |
+ buf.WriteByte('"')
|
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+// This is based on ffjsonWriteJSONString. It has been changed |
|
| 65 | 128 |
// to accept a string passed as a slice of bytes. |
| 129 |
+// TODO: remove duplication with ffjsonWriteJSONString |
|
| 66 | 130 |
func ffjsonWriteJSONBytesAsString(buf *bytes.Buffer, s []byte) {
|
| 67 | 131 |
const hex = "0123456789abcdef" |
| 68 | 132 |
|