Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin authored on 2017/09/23 04:37:16... | ... |
@@ -113,18 +113,14 @@ func writeMessageBuf(w io.Writer, m *logger.Message, extra json.RawMessage, buf |
113 | 113 |
} |
114 | 114 |
|
115 | 115 |
func marshalMessage(msg *logger.Message, extra json.RawMessage, buf *bytes.Buffer) error { |
116 |
- timestamp, err := jsonlog.FastTimeMarshalJSON(msg.Timestamp) |
|
117 |
- if err != nil { |
|
118 |
- return err |
|
119 |
- } |
|
120 | 116 |
logLine := msg.Line |
121 | 117 |
if !msg.Partial { |
122 | 118 |
logLine = append(msg.Line, '\n') |
123 | 119 |
} |
124 |
- err = (&jsonlog.JSONLogs{ |
|
120 |
+ err := (&jsonlog.JSONLogs{ |
|
125 | 121 |
Log: logLine, |
126 | 122 |
Stream: msg.Source, |
127 |
- Created: timestamp, |
|
123 |
+ Created: msg.Timestamp, |
|
128 | 124 |
RawAttrs: extra, |
129 | 125 |
}).MarshalJSONBuf(buf) |
130 | 126 |
if err != nil { |
... | ... |
@@ -105,7 +105,7 @@ func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error { |
105 | 105 |
buf.WriteString(`,`) |
106 | 106 |
} |
107 | 107 |
buf.WriteString(`"time":`) |
108 |
- timestamp, err = FastTimeMarshalJSON(mj.Created) |
|
108 |
+ timestamp, err = fastTimeMarshalJSON(mj.Created) |
|
109 | 109 |
if err != nil { |
110 | 110 |
return err |
111 | 111 |
} |
... | ... |
@@ -3,6 +3,10 @@ package jsonlog |
3 | 3 |
import ( |
4 | 4 |
"regexp" |
5 | 5 |
"testing" |
6 |
+ |
|
7 |
+ "encoding/json" |
|
8 |
+ "github.com/stretchr/testify/assert" |
|
9 |
+ "github.com/stretchr/testify/require" |
|
6 | 10 |
) |
7 | 11 |
|
8 | 12 |
func TestJSONLogMarshalJSON(t *testing.T) { |
... | ... |
@@ -21,14 +25,8 @@ func TestJSONLogMarshalJSON(t *testing.T) { |
21 | 21 |
} |
22 | 22 |
for jsonLog, expression := range logs { |
23 | 23 |
data, err := jsonLog.MarshalJSON() |
24 |
- if err != nil { |
|
25 |
- t.Fatal(err) |
|
26 |
- } |
|
27 |
- res := string(data) |
|
28 |
- t.Logf("Result of WriteLog: %q", res) |
|
29 |
- logRe := regexp.MustCompile(expression) |
|
30 |
- if !logRe.MatchString(res) { |
|
31 |
- t.Fatalf("Log line not in expected format [%v]: %q", expression, res) |
|
32 |
- } |
|
24 |
+ require.NoError(t, err) |
|
25 |
+ assert.Regexp(t, regexp.MustCompile(expression), string(data)) |
|
26 |
+ assert.NoError(t, json.Unmarshal(data, &map[string]interface{}{})) |
|
33 | 27 |
} |
34 | 28 |
} |
... | ... |
@@ -3,16 +3,15 @@ package jsonlog |
3 | 3 |
import ( |
4 | 4 |
"bytes" |
5 | 5 |
"encoding/json" |
6 |
+ "time" |
|
6 | 7 |
"unicode/utf8" |
7 | 8 |
) |
8 | 9 |
|
9 |
-// JSONLogs is based on JSONLog. |
|
10 |
-// It allows marshalling JSONLog from Log as []byte |
|
11 |
-// and an already marshalled Created timestamp. |
|
10 |
+// JSONLogs marshals encoded JSONLog objects |
|
12 | 11 |
type JSONLogs struct { |
13 |
- Log []byte `json:"log,omitempty"` |
|
14 |
- Stream string `json:"stream,omitempty"` |
|
15 |
- Created string `json:"time"` |
|
12 |
+ Log []byte `json:"log,omitempty"` |
|
13 |
+ Stream string `json:"stream,omitempty"` |
|
14 |
+ Created time.Time `json:"time"` |
|
16 | 15 |
|
17 | 16 |
// json-encoded bytes |
18 | 17 |
RawAttrs json.RawMessage `json:"attrs,omitempty"` |
... | ... |
@@ -50,8 +49,14 @@ func (mj *JSONLogs) MarshalJSONBuf(buf *bytes.Buffer) error { |
50 | 50 |
if !first { |
51 | 51 |
buf.WriteString(`,`) |
52 | 52 |
} |
53 |
+ |
|
54 |
+ created, err := fastTimeMarshalJSON(mj.Created) |
|
55 |
+ if err != nil { |
|
56 |
+ return err |
|
57 |
+ } |
|
58 |
+ |
|
53 | 59 |
buf.WriteString(`"time":`) |
54 |
- buf.WriteString(mj.Created) |
|
60 |
+ buf.WriteString(created) |
|
55 | 61 |
buf.WriteString(`}`) |
56 | 62 |
return nil |
57 | 63 |
} |
... | ... |
@@ -2,38 +2,39 @@ package jsonlog |
2 | 2 |
|
3 | 3 |
import ( |
4 | 4 |
"bytes" |
5 |
+ "encoding/json" |
|
5 | 6 |
"regexp" |
6 | 7 |
"testing" |
8 |
+ "time" |
|
9 |
+ |
|
10 |
+ "github.com/stretchr/testify/assert" |
|
11 |
+ "github.com/stretchr/testify/require" |
|
7 | 12 |
) |
8 | 13 |
|
9 | 14 |
func TestJSONLogsMarshalJSONBuf(t *testing.T) { |
10 | 15 |
logs := map[*JSONLogs]string{ |
11 |
- {Log: []byte(`"A log line with \\"`)}: `^{\"log\":\"\\\"A log line with \\\\\\\\\\\"\",\"time\":}$`, |
|
12 |
- {Log: []byte("A log line")}: `^{\"log\":\"A log line\",\"time\":}$`, |
|
13 |
- {Log: []byte("A log line with \r")}: `^{\"log\":\"A log line with \\r\",\"time\":}$`, |
|
14 |
- {Log: []byte("A log line with & < >")}: `^{\"log\":\"A log line with \\u0026 \\u003c \\u003e\",\"time\":}$`, |
|
15 |
- {Log: []byte("A log line with utf8 : 🚀 ψ ω β")}: `^{\"log\":\"A log line with utf8 : 🚀 ψ ω β\",\"time\":}$`, |
|
16 |
- {Stream: "stdout"}: `^{\"stream\":\"stdout\",\"time\":}$`, |
|
17 |
- {Stream: "stdout", Log: []byte("A log line")}: `^{\"log\":\"A log line\",\"stream\":\"stdout\",\"time\":}$`, |
|
18 |
- {Created: "time"}: `^{\"time\":time}$`, |
|
19 |
- {}: `^{\"time\":}$`, |
|
16 |
+ {Log: []byte(`"A log line with \\"`)}: `^{\"log\":\"\\\"A log line with \\\\\\\\\\\"\",\"time\":`, |
|
17 |
+ {Log: []byte("A log line")}: `^{\"log\":\"A log line\",\"time\":`, |
|
18 |
+ {Log: []byte("A log line with \r")}: `^{\"log\":\"A log line with \\r\",\"time\":`, |
|
19 |
+ {Log: []byte("A log line with & < >")}: `^{\"log\":\"A log line with \\u0026 \\u003c \\u003e\",\"time\":`, |
|
20 |
+ {Log: []byte("A log line with utf8 : 🚀 ψ ω β")}: `^{\"log\":\"A log line with utf8 : 🚀 ψ ω β\",\"time\":`, |
|
21 |
+ {Stream: "stdout"}: `^{\"stream\":\"stdout\",\"time\":`, |
|
22 |
+ {Stream: "stdout", Log: []byte("A log line")}: `^{\"log\":\"A log line\",\"stream\":\"stdout\",\"time\":`, |
|
23 |
+ {Created: time.Date(2017, 9, 1, 1, 1, 1, 1, time.UTC)}: `^{\"time\":"2017-09-01T01:01:01.000000001Z"}$`, |
|
24 |
+ |
|
25 |
+ {}: `^{\"time\":"0001-01-01T00:00:00Z"}$`, |
|
20 | 26 |
// These ones are a little weird |
21 |
- {Log: []byte("\u2028 \u2029")}: `^{\"log\":\"\\u2028 \\u2029\",\"time\":}$`, |
|
22 |
- {Log: []byte{0xaF}}: `^{\"log\":\"\\ufffd\",\"time\":}$`, |
|
23 |
- {Log: []byte{0x7F}}: `^{\"log\":\"\x7f\",\"time\":}$`, |
|
27 |
+ {Log: []byte("\u2028 \u2029")}: `^{\"log\":\"\\u2028 \\u2029\",\"time\":`, |
|
28 |
+ {Log: []byte{0xaF}}: `^{\"log\":\"\\ufffd\",\"time\":`, |
|
29 |
+ {Log: []byte{0x7F}}: `^{\"log\":\"\x7f\",\"time\":`, |
|
24 | 30 |
// with raw attributes |
25 |
- {Log: []byte("A log line"), RawAttrs: []byte(`{"hello":"world","value":1234}`)}: `^{\"log\":\"A log line\",\"attrs\":{\"hello\":\"world\",\"value\":1234},\"time\":}$`, |
|
31 |
+ {Log: []byte("A log line"), RawAttrs: []byte(`{"hello":"world","value":1234}`)}: `^{\"log\":\"A log line\",\"attrs\":{\"hello\":\"world\",\"value\":1234},\"time\":`, |
|
26 | 32 |
} |
27 | 33 |
for jsonLog, expression := range logs { |
28 | 34 |
var buf bytes.Buffer |
29 |
- if err := jsonLog.MarshalJSONBuf(&buf); err != nil { |
|
30 |
- t.Fatal(err) |
|
31 |
- } |
|
32 |
- res := buf.String() |
|
33 |
- t.Logf("Result of WriteLog: %q", res) |
|
34 |
- logRe := regexp.MustCompile(expression) |
|
35 |
- if !logRe.MatchString(res) { |
|
36 |
- t.Fatalf("Log line not in expected format [%v]: %q", expression, res) |
|
37 |
- } |
|
35 |
+ err := jsonLog.MarshalJSONBuf(&buf) |
|
36 |
+ require.NoError(t, err) |
|
37 |
+ assert.Regexp(t, regexp.MustCompile(expression), buf.String()) |
|
38 |
+ assert.NoError(t, json.Unmarshal(buf.Bytes(), &map[string]interface{}{})) |
|
38 | 39 |
} |
39 | 40 |
} |
... | ... |
@@ -8,9 +8,9 @@ import ( |
8 | 8 |
|
9 | 9 |
const jsonFormat = `"` + time.RFC3339Nano + `"` |
10 | 10 |
|
11 |
-// FastTimeMarshalJSON avoids one of the extra allocations that |
|
11 |
+// fastTimeMarshalJSON avoids one of the extra allocations that |
|
12 | 12 |
// time.MarshalJSON is making. |
13 |
-func FastTimeMarshalJSON(t time.Time) (string, error) { |
|
13 |
+func fastTimeMarshalJSON(t time.Time) (string, error) { |
|
14 | 14 |
if y := t.Year(); y < 0 || y >= 10000 { |
15 | 15 |
// RFC 3339 is clear that years are 4 digits exactly. |
16 | 16 |
// See golang.org/issue/4556#c15 for more discussion. |
... | ... |
@@ -3,45 +3,33 @@ package jsonlog |
3 | 3 |
import ( |
4 | 4 |
"testing" |
5 | 5 |
"time" |
6 |
+ |
|
7 |
+ "github.com/docker/docker/internal/testutil" |
|
8 |
+ "github.com/stretchr/testify/assert" |
|
9 |
+ "github.com/stretchr/testify/require" |
|
6 | 10 |
) |
7 | 11 |
|
8 |
-// Testing to ensure 'year' fields is between 0 and 9999 |
|
9 |
-func TestFastTimeMarshalJSONWithInvalidDate(t *testing.T) { |
|
12 |
+func TestFastTimeMarshalJSONWithInvalidYear(t *testing.T) { |
|
10 | 13 |
aTime := time.Date(-1, 1, 1, 0, 0, 0, 0, time.Local) |
11 |
- json, err := FastTimeMarshalJSON(aTime) |
|
12 |
- if err == nil { |
|
13 |
- t.Fatalf("FastTimeMarshalJSON should throw an error, but was '%v'", json) |
|
14 |
- } |
|
15 |
- anotherTime := time.Date(10000, 1, 1, 0, 0, 0, 0, time.Local) |
|
16 |
- json, err = FastTimeMarshalJSON(anotherTime) |
|
17 |
- if err == nil { |
|
18 |
- t.Fatalf("FastTimeMarshalJSON should throw an error, but was '%v'", json) |
|
19 |
- } |
|
14 |
+ _, err := fastTimeMarshalJSON(aTime) |
|
15 |
+ testutil.ErrorContains(t, err, "year outside of range") |
|
20 | 16 |
|
17 |
+ anotherTime := time.Date(10000, 1, 1, 0, 0, 0, 0, time.Local) |
|
18 |
+ _, err = fastTimeMarshalJSON(anotherTime) |
|
19 |
+ testutil.ErrorContains(t, err, "year outside of range") |
|
21 | 20 |
} |
22 | 21 |
|
23 | 22 |
func TestFastTimeMarshalJSON(t *testing.T) { |
24 | 23 |
aTime := time.Date(2015, 5, 29, 11, 1, 2, 3, time.UTC) |
25 |
- json, err := FastTimeMarshalJSON(aTime) |
|
26 |
- if err != nil { |
|
27 |
- t.Fatal(err) |
|
28 |
- } |
|
29 |
- expected := "\"2015-05-29T11:01:02.000000003Z\"" |
|
30 |
- if json != expected { |
|
31 |
- t.Fatalf("Expected %v, got %v", expected, json) |
|
32 |
- } |
|
24 |
+ json, err := fastTimeMarshalJSON(aTime) |
|
25 |
+ require.NoError(t, err) |
|
26 |
+ assert.Equal(t, "\"2015-05-29T11:01:02.000000003Z\"", json) |
|
33 | 27 |
|
34 | 28 |
location, err := time.LoadLocation("Europe/Paris") |
35 |
- if err != nil { |
|
36 |
- t.Fatal(err) |
|
37 |
- } |
|
29 |
+ require.NoError(t, err) |
|
30 |
+ |
|
38 | 31 |
aTime = time.Date(2015, 5, 29, 11, 1, 2, 3, location) |
39 |
- json, err = FastTimeMarshalJSON(aTime) |
|
40 |
- if err != nil { |
|
41 |
- t.Fatal(err) |
|
42 |
- } |
|
43 |
- expected = "\"2015-05-29T11:01:02.000000003+02:00\"" |
|
44 |
- if json != expected { |
|
45 |
- t.Fatalf("Expected %v, got %v", expected, json) |
|
46 |
- } |
|
32 |
+ json, err = fastTimeMarshalJSON(aTime) |
|
33 |
+ require.NoError(t, err) |
|
34 |
+ assert.Equal(t, "\"2015-05-29T11:01:02.000000003+02:00\"", json) |
|
47 | 35 |
} |