Signed-off-by: Vincent Demeester <vincent@sbr.pm>
| ... | ... |
@@ -52,6 +52,17 @@ |
| 52 | 52 |
// buf.WriteString(`}`) |
| 53 | 53 |
// return nil |
| 54 | 54 |
// } |
| 55 |
+// @@ -81,9 +81,10 @@ func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error {
|
|
| 56 |
+// if len(mj.Log) != 0 {
|
|
| 57 |
+// - if first == true {
|
|
| 58 |
+// - first = false |
|
| 59 |
+// - } else {
|
|
| 60 |
+// - buf.WriteString(`,`) |
|
| 61 |
+// - } |
|
| 62 |
+// + first = false |
|
| 63 |
+// buf.WriteString(`"log":`) |
|
| 64 |
+// ffjson_WriteJsonString(buf, mj.Log) |
|
| 65 |
+// } |
|
| 55 | 66 |
|
| 56 | 67 |
package jsonlog |
| 57 | 68 |
|
| ... | ... |
@@ -79,11 +90,7 @@ func (mj *JSONLog) MarshalJSONBuf(buf *bytes.Buffer) error {
|
| 79 | 79 |
) |
| 80 | 80 |
buf.WriteString(`{`)
|
| 81 | 81 |
if len(mj.Log) != 0 {
|
| 82 |
- if first == true {
|
|
| 83 |
- first = false |
|
| 84 |
- } else {
|
|
| 85 |
- buf.WriteString(`,`) |
|
| 86 |
- } |
|
| 82 |
+ first = false |
|
| 87 | 83 |
buf.WriteString(`"log":`) |
| 88 | 84 |
ffjson_WriteJsonString(buf, mj.Log) |
| 89 | 85 |
} |
| 90 | 86 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,34 @@ |
| 0 |
+package jsonlog |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "regexp" |
|
| 4 |
+ "testing" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func TestJSONLogMarshalJSON(t *testing.T) {
|
|
| 8 |
+ logs := map[JSONLog]string{
|
|
| 9 |
+ JSONLog{Log: `"A log line with \\"`}: `^{\"log\":\"\\\"A log line with \\\\\\\\\\\"\",\"time\":\".{20,}\"}$`,
|
|
| 10 |
+ JSONLog{Log: "A log line"}: `^{\"log\":\"A log line\",\"time\":\".{20,}\"}$`,
|
|
| 11 |
+ JSONLog{Log: "A log line with \r"}: `^{\"log\":\"A log line with \\r\",\"time\":\".{20,}\"}$`,
|
|
| 12 |
+ JSONLog{Log: "A log line with & < >"}: `^{\"log\":\"A log line with \\u0026 \\u003c \\u003e\",\"time\":\".{20,}\"}$`,
|
|
| 13 |
+ JSONLog{Log: "A log line with utf8 : 🚀 ψ ω β"}: `^{\"log\":\"A log line with utf8 : 🚀 ψ ω β\",\"time\":\".{20,}\"}$`,
|
|
| 14 |
+ JSONLog{Stream: "stdout"}: `^{\"stream\":\"stdout\",\"time\":\".{20,}\"}$`,
|
|
| 15 |
+ JSONLog{}: `^{\"time\":\".{20,}\"}$`,
|
|
| 16 |
+ // These ones are a little weird |
|
| 17 |
+ JSONLog{Log: "\u2028 \u2029"}: `^{\"log\":\"\\u2028 \\u2029\",\"time\":\".{20,}\"}$`,
|
|
| 18 |
+ JSONLog{Log: string([]byte{0xaF})}: `^{\"log\":\"\\ufffd\",\"time\":\".{20,}\"}$`,
|
|
| 19 |
+ JSONLog{Log: string([]byte{0x7F})}: `^{\"log\":\"\x7f\",\"time\":\".{20,}\"}$`,
|
|
| 20 |
+ } |
|
| 21 |
+ for jsonLog, expression := range logs {
|
|
| 22 |
+ data, err := jsonLog.MarshalJSON() |
|
| 23 |
+ if err != nil {
|
|
| 24 |
+ t.Fatal(err) |
|
| 25 |
+ } |
|
| 26 |
+ res := string(data) |
|
| 27 |
+ t.Logf("Result of WriteLog: %q", res)
|
|
| 28 |
+ logRe := regexp.MustCompile(expression) |
|
| 29 |
+ if !logRe.MatchString(res) {
|
|
| 30 |
+ t.Fatalf("Log line not in expected format [%v]: %q", expression, res)
|
|
| 31 |
+ } |
|
| 32 |
+ } |
|
| 33 |
+} |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"encoding/json" |
| 6 | 6 |
"io/ioutil" |
| 7 | 7 |
"regexp" |
| 8 |
+ "strconv" |
|
| 8 | 9 |
"strings" |
| 9 | 10 |
"testing" |
| 10 | 11 |
"time" |
| ... | ... |
@@ -12,29 +13,123 @@ import ( |
| 12 | 12 |
"github.com/docker/docker/pkg/timeutils" |
| 13 | 13 |
) |
| 14 | 14 |
|
| 15 |
-func TestWriteLog(t *testing.T) {
|
|
| 15 |
+// Invalid json should return an error |
|
| 16 |
+func TestWriteLogWithInvalidJSON(t *testing.T) {
|
|
| 17 |
+ json := strings.NewReader("Invalid json")
|
|
| 18 |
+ w := bytes.NewBuffer(nil) |
|
| 19 |
+ if err := WriteLog(json, w, "json", time.Time{}); err == nil {
|
|
| 20 |
+ t.Fatalf("Expected an error, got [%v]", w.String())
|
|
| 21 |
+ } |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+// Any format is valid, it will just print it |
|
| 25 |
+func TestWriteLogWithInvalidFormat(t *testing.T) {
|
|
| 26 |
+ testLine := "Line that thinks that it is log line from docker\n" |
|
| 16 | 27 |
var buf bytes.Buffer |
| 17 | 28 |
e := json.NewEncoder(&buf) |
| 29 |
+ for i := 0; i < 35; i++ {
|
|
| 30 |
+ e.Encode(JSONLog{Log: testLine, Stream: "stdout", Created: time.Now()})
|
|
| 31 |
+ } |
|
| 32 |
+ w := bytes.NewBuffer(nil) |
|
| 33 |
+ if err := WriteLog(&buf, w, "invalid format", time.Time{}); err != nil {
|
|
| 34 |
+ t.Fatal(err) |
|
| 35 |
+ } |
|
| 36 |
+ res := w.String() |
|
| 37 |
+ t.Logf("Result of WriteLog: %q", res)
|
|
| 38 |
+ lines := strings.Split(strings.TrimSpace(res), "\n") |
|
| 39 |
+ expression := "^invalid format Line that thinks that it is log line from docker$" |
|
| 40 |
+ logRe := regexp.MustCompile(expression) |
|
| 41 |
+ expectedLines := 35 |
|
| 42 |
+ if len(lines) != expectedLines {
|
|
| 43 |
+ t.Fatalf("Must be %v lines but got %d", expectedLines, len(lines))
|
|
| 44 |
+ } |
|
| 45 |
+ for _, l := range lines {
|
|
| 46 |
+ if !logRe.MatchString(l) {
|
|
| 47 |
+ t.Fatalf("Log line not in expected format [%v]: %q", expression, l)
|
|
| 48 |
+ } |
|
| 49 |
+ } |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+// Having multiple Log/Stream element |
|
| 53 |
+func TestWriteLogWithMultipleStreamLog(t *testing.T) {
|
|
| 18 | 54 |
testLine := "Line that thinks that it is log line from docker\n" |
| 19 |
- for i := 0; i < 30; i++ {
|
|
| 55 |
+ var buf bytes.Buffer |
|
| 56 |
+ e := json.NewEncoder(&buf) |
|
| 57 |
+ for i := 0; i < 35; i++ {
|
|
| 20 | 58 |
e.Encode(JSONLog{Log: testLine, Stream: "stdout", Created: time.Now()})
|
| 21 | 59 |
} |
| 22 | 60 |
w := bytes.NewBuffer(nil) |
| 23 |
- format := timeutils.RFC3339NanoFixed |
|
| 24 |
- if err := WriteLog(&buf, w, format, time.Time{}); err != nil {
|
|
| 61 |
+ if err := WriteLog(&buf, w, "invalid format", time.Time{}); err != nil {
|
|
| 25 | 62 |
t.Fatal(err) |
| 26 | 63 |
} |
| 27 | 64 |
res := w.String() |
| 28 | 65 |
t.Logf("Result of WriteLog: %q", res)
|
| 29 | 66 |
lines := strings.Split(strings.TrimSpace(res), "\n") |
| 30 |
- if len(lines) != 30 {
|
|
| 31 |
- t.Fatalf("Must be 30 lines but got %d", len(lines))
|
|
| 67 |
+ expression := "^invalid format Line that thinks that it is log line from docker$" |
|
| 68 |
+ logRe := regexp.MustCompile(expression) |
|
| 69 |
+ expectedLines := 35 |
|
| 70 |
+ if len(lines) != expectedLines {
|
|
| 71 |
+ t.Fatalf("Must be %v lines but got %d", expectedLines, len(lines))
|
|
| 32 | 72 |
} |
| 33 |
- // 30+ symbols, five more can come from system timezone |
|
| 34 |
- logRe := regexp.MustCompile(`.{30,} Line that thinks that it is log line from docker`)
|
|
| 35 | 73 |
for _, l := range lines {
|
| 36 | 74 |
if !logRe.MatchString(l) {
|
| 37 |
- t.Fatalf("Log line not in expected format: %q", l)
|
|
| 75 |
+ t.Fatalf("Log line not in expected format [%v]: %q", expression, l)
|
|
| 76 |
+ } |
|
| 77 |
+ } |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 80 |
+// Write log with since after created, it won't print anything |
|
| 81 |
+func TestWriteLogWithDate(t *testing.T) {
|
|
| 82 |
+ created, _ := time.Parse("YYYY-MM-dd", "2015-01-01")
|
|
| 83 |
+ var buf bytes.Buffer |
|
| 84 |
+ testLine := "Line that thinks that it is log line from docker\n" |
|
| 85 |
+ jsonLog := JSONLog{Log: testLine, Stream: "stdout", Created: created}
|
|
| 86 |
+ if err := json.NewEncoder(&buf).Encode(jsonLog); err != nil {
|
|
| 87 |
+ t.Fatal(err) |
|
| 88 |
+ } |
|
| 89 |
+ w := bytes.NewBuffer(nil) |
|
| 90 |
+ if err := WriteLog(&buf, w, "json", time.Now()); err != nil {
|
|
| 91 |
+ t.Fatal(err) |
|
| 92 |
+ } |
|
| 93 |
+ res := w.String() |
|
| 94 |
+ if res != "" {
|
|
| 95 |
+ t.Fatalf("Expected empty log, got [%v]", res)
|
|
| 96 |
+ } |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+// Happy path :) |
|
| 100 |
+func TestWriteLog(t *testing.T) {
|
|
| 101 |
+ testLine := "Line that thinks that it is log line from docker\n" |
|
| 102 |
+ format := timeutils.RFC3339NanoFixed |
|
| 103 |
+ logs := map[string][]string{
|
|
| 104 |
+ "": {"35", "^Line that thinks that it is log line from docker$"},
|
|
| 105 |
+ "json": {"1", `^{\"log\":\"Line that thinks that it is log line from docker\\n\",\"stream\":\"stdout\",\"time\":.{30,}\"}$`},
|
|
| 106 |
+ // 30+ symbols, five more can come from system timezone |
|
| 107 |
+ format: {"35", `.{30,} Line that thinks that it is log line from docker`},
|
|
| 108 |
+ } |
|
| 109 |
+ for givenFormat, expressionAndLines := range logs {
|
|
| 110 |
+ expectedLines, _ := strconv.Atoi(expressionAndLines[0]) |
|
| 111 |
+ expression := expressionAndLines[1] |
|
| 112 |
+ var buf bytes.Buffer |
|
| 113 |
+ e := json.NewEncoder(&buf) |
|
| 114 |
+ for i := 0; i < 35; i++ {
|
|
| 115 |
+ e.Encode(JSONLog{Log: testLine, Stream: "stdout", Created: time.Now()})
|
|
| 116 |
+ } |
|
| 117 |
+ w := bytes.NewBuffer(nil) |
|
| 118 |
+ if err := WriteLog(&buf, w, givenFormat, time.Time{}); err != nil {
|
|
| 119 |
+ t.Fatal(err) |
|
| 120 |
+ } |
|
| 121 |
+ res := w.String() |
|
| 122 |
+ t.Logf("Result of WriteLog: %q", res)
|
|
| 123 |
+ lines := strings.Split(strings.TrimSpace(res), "\n") |
|
| 124 |
+ if len(lines) != expectedLines {
|
|
| 125 |
+ t.Fatalf("Must be %v lines but got %d", expectedLines, len(lines))
|
|
| 126 |
+ } |
|
| 127 |
+ logRe := regexp.MustCompile(expression) |
|
| 128 |
+ for _, l := range lines {
|
|
| 129 |
+ if !logRe.MatchString(l) {
|
|
| 130 |
+ t.Fatalf("Log line not in expected format [%v]: %q", expression, l)
|
|
| 131 |
+ } |
|
| 38 | 132 |
} |
| 39 | 133 |
} |
| 40 | 134 |
} |
| ... | ... |
@@ -21,11 +21,7 @@ func (mj *JSONLogBytes) MarshalJSONBuf(buf *bytes.Buffer) error {
|
| 21 | 21 |
|
| 22 | 22 |
buf.WriteString(`{`)
|
| 23 | 23 |
if len(mj.Log) != 0 {
|
| 24 |
- if first == true {
|
|
| 25 |
- first = false |
|
| 26 |
- } else {
|
|
| 27 |
- buf.WriteString(`,`) |
|
| 28 |
- } |
|
| 24 |
+ first = false |
|
| 29 | 25 |
buf.WriteString(`"log":`) |
| 30 | 26 |
ffjson_WriteJsonBytesAsString(buf, mj.Log) |
| 31 | 27 |
} |
| 32 | 28 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,37 @@ |
| 0 |
+package jsonlog |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "regexp" |
|
| 5 |
+ "testing" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestJSONLogBytesMarshalJSONBuf(t *testing.T) {
|
|
| 9 |
+ logs := map[*JSONLogBytes]string{
|
|
| 10 |
+ &JSONLogBytes{Log: []byte(`"A log line with \\"`)}: `^{\"log\":\"\\\"A log line with \\\\\\\\\\\"\",\"time\":}$`,
|
|
| 11 |
+ &JSONLogBytes{Log: []byte("A log line")}: `^{\"log\":\"A log line\",\"time\":}$`,
|
|
| 12 |
+ &JSONLogBytes{Log: []byte("A log line with \r")}: `^{\"log\":\"A log line with \\r\",\"time\":}$`,
|
|
| 13 |
+ &JSONLogBytes{Log: []byte("A log line with & < >")}: `^{\"log\":\"A log line with \\u0026 \\u003c \\u003e\",\"time\":}$`,
|
|
| 14 |
+ &JSONLogBytes{Log: []byte("A log line with utf8 : 🚀 ψ ω β")}: `^{\"log\":\"A log line with utf8 : 🚀 ψ ω β\",\"time\":}$`,
|
|
| 15 |
+ &JSONLogBytes{Stream: "stdout"}: `^{\"stream\":\"stdout\",\"time\":}$`,
|
|
| 16 |
+ &JSONLogBytes{Stream: "stdout", Log: []byte("A log line")}: `^{\"log\":\"A log line\",\"stream\":\"stdout\",\"time\":}$`,
|
|
| 17 |
+ &JSONLogBytes{Created: "time"}: `^{\"time\":time}$`,
|
|
| 18 |
+ &JSONLogBytes{}: `^{\"time\":}$`,
|
|
| 19 |
+ // These ones are a little weird |
|
| 20 |
+ &JSONLogBytes{Log: []byte("\u2028 \u2029")}: `^{\"log\":\"\\u2028 \\u2029\",\"time\":}$`,
|
|
| 21 |
+ &JSONLogBytes{Log: []byte{0xaF}}: `^{\"log\":\"\\ufffd\",\"time\":}$`,
|
|
| 22 |
+ &JSONLogBytes{Log: []byte{0x7F}}: `^{\"log\":\"\x7f\",\"time\":}$`,
|
|
| 23 |
+ } |
|
| 24 |
+ for jsonLog, expression := range logs {
|
|
| 25 |
+ var buf bytes.Buffer |
|
| 26 |
+ if err := jsonLog.MarshalJSONBuf(&buf); err != nil {
|
|
| 27 |
+ t.Fatal(err) |
|
| 28 |
+ } |
|
| 29 |
+ res := buf.String() |
|
| 30 |
+ t.Logf("Result of WriteLog: %q", res)
|
|
| 31 |
+ logRe := regexp.MustCompile(expression) |
|
| 32 |
+ if !logRe.MatchString(res) {
|
|
| 33 |
+ t.Fatalf("Log line not in expected format [%v]: %q", expression, res)
|
|
| 34 |
+ } |
|
| 35 |
+ } |
|
| 36 |
+} |