github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/jsonfilelog/jsonfilelog_test.go (about) 1 package jsonfilelog // import "github.com/docker/docker/daemon/logger/jsonfilelog" 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "encoding/json" 7 "io" 8 "os" 9 "path/filepath" 10 "reflect" 11 "strconv" 12 "testing" 13 "time" 14 15 "github.com/docker/docker/daemon/logger" 16 "github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog" 17 "gotest.tools/v3/assert" 18 is "gotest.tools/v3/assert/cmp" 19 "gotest.tools/v3/fs" 20 ) 21 22 func TestJSONFileLogger(t *testing.T) { 23 cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657" 24 tmp, err := os.MkdirTemp("", "docker-logger-") 25 if err != nil { 26 t.Fatal(err) 27 } 28 defer os.RemoveAll(tmp) 29 filename := filepath.Join(tmp, "container.log") 30 l, err := New(logger.Info{ 31 ContainerID: cid, 32 LogPath: filename, 33 }) 34 if err != nil { 35 t.Fatal(err) 36 } 37 defer l.Close() 38 39 if err := l.Log(&logger.Message{Line: []byte("line1"), Source: "src1"}); err != nil { 40 t.Fatal(err) 41 } 42 if err := l.Log(&logger.Message{Line: []byte("line2"), Source: "src2"}); err != nil { 43 t.Fatal(err) 44 } 45 if err := l.Log(&logger.Message{Line: []byte("line3"), Source: "src3"}); err != nil { 46 t.Fatal(err) 47 } 48 res, err := os.ReadFile(filename) 49 if err != nil { 50 t.Fatal(err) 51 } 52 expected := `{"log":"line1\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 53 {"log":"line2\n","stream":"src2","time":"0001-01-01T00:00:00Z"} 54 {"log":"line3\n","stream":"src3","time":"0001-01-01T00:00:00Z"} 55 ` 56 57 if string(res) != expected { 58 t.Fatalf("Wrong log content: %q, expected %q", res, expected) 59 } 60 } 61 62 func TestJSONFileLoggerWithTags(t *testing.T) { 63 cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657" 64 cname := "test-container" 65 tmp, err := os.MkdirTemp("", "docker-logger-") 66 67 assert.NilError(t, err) 68 69 defer os.RemoveAll(tmp) 70 filename := filepath.Join(tmp, "container.log") 71 l, err := New(logger.Info{ 72 Config: map[string]string{ 73 "tag": "{{.ID}}/{{.Name}}", // first 12 characters of ContainerID and full ContainerName 74 }, 75 ContainerID: cid, 76 ContainerName: cname, 77 LogPath: filename, 78 }) 79 80 assert.NilError(t, err) 81 defer l.Close() 82 83 err = l.Log(&logger.Message{Line: []byte("line1"), Source: "src1"}) 84 assert.NilError(t, err) 85 86 err = l.Log(&logger.Message{Line: []byte("line2"), Source: "src2"}) 87 assert.NilError(t, err) 88 89 err = l.Log(&logger.Message{Line: []byte("line3"), Source: "src3"}) 90 assert.NilError(t, err) 91 92 res, err := os.ReadFile(filename) 93 assert.NilError(t, err) 94 95 expected := `{"log":"line1\n","stream":"src1","attrs":{"tag":"a7317399f3f8/test-container"},"time":"0001-01-01T00:00:00Z"} 96 {"log":"line2\n","stream":"src2","attrs":{"tag":"a7317399f3f8/test-container"},"time":"0001-01-01T00:00:00Z"} 97 {"log":"line3\n","stream":"src3","attrs":{"tag":"a7317399f3f8/test-container"},"time":"0001-01-01T00:00:00Z"} 98 ` 99 assert.Check(t, is.Equal(expected, string(res))) 100 } 101 102 func BenchmarkJSONFileLoggerLog(b *testing.B) { 103 tmp := fs.NewDir(b, "bench-jsonfilelog") 104 defer tmp.Remove() 105 106 jsonlogger, err := New(logger.Info{ 107 ContainerID: "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657", 108 LogPath: tmp.Join("container.log"), 109 Config: map[string]string{ 110 "labels": "first,second", 111 "max-file": "10", 112 "compress": "true", 113 "max-size": "20m", 114 }, 115 ContainerLabels: map[string]string{ 116 "first": "label_value", 117 "second": "label_foo", 118 }, 119 }) 120 assert.NilError(b, err) 121 defer jsonlogger.Close() 122 123 t := time.Now().UTC() 124 for _, data := range [][]byte{ 125 []byte(""), 126 []byte("a short string"), 127 bytes.Repeat([]byte("a long string"), 100), 128 bytes.Repeat([]byte("a really long string"), 10000), 129 } { 130 b.Run(strconv.Itoa(len(data)), func(b *testing.B) { 131 testMsg := &logger.Message{ 132 Line: data, 133 Source: "stderr", 134 Timestamp: t, 135 } 136 137 buf := bytes.NewBuffer(nil) 138 assert.NilError(b, marshalMessage(testMsg, nil, buf)) 139 b.SetBytes(int64(buf.Len())) 140 b.ResetTimer() 141 for i := 0; i < b.N; i++ { 142 msg := logger.NewMessage() 143 msg.Line = testMsg.Line 144 msg.Timestamp = testMsg.Timestamp 145 msg.Source = testMsg.Source 146 if err := jsonlogger.Log(msg); err != nil { 147 b.Fatal(err) 148 } 149 } 150 }) 151 } 152 } 153 154 func TestJSONFileLoggerWithOpts(t *testing.T) { 155 cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657" 156 tmp, err := os.MkdirTemp("", "docker-logger-") 157 if err != nil { 158 t.Fatal(err) 159 } 160 defer os.RemoveAll(tmp) 161 filename := filepath.Join(tmp, "container.log") 162 config := map[string]string{"max-file": "3", "max-size": "1k", "compress": "true"} 163 l, err := New(logger.Info{ 164 ContainerID: cid, 165 LogPath: filename, 166 Config: config, 167 }) 168 if err != nil { 169 t.Fatal(err) 170 } 171 defer l.Close() 172 for i := 0; i < 36; i++ { 173 if err := l.Log(&logger.Message{Line: []byte("line" + strconv.Itoa(i)), Source: "src1"}); err != nil { 174 t.Fatal(err) 175 } 176 } 177 178 res, err := os.ReadFile(filename) 179 if err != nil { 180 t.Fatal(err) 181 } 182 183 penUlt, err := os.ReadFile(filename + ".1") 184 if err != nil { 185 if !os.IsNotExist(err) { 186 t.Fatal(err) 187 } 188 189 file, err := os.Open(filename + ".1.gz") 190 if err != nil { 191 t.Fatal(err) 192 } 193 defer file.Close() 194 zipReader, err := gzip.NewReader(file) 195 if err != nil { 196 t.Fatal(err) 197 } 198 defer zipReader.Close() 199 penUlt, err = io.ReadAll(zipReader) 200 if err != nil { 201 t.Fatal(err) 202 } 203 } 204 205 file, err := os.Open(filename + ".2.gz") 206 if err != nil { 207 t.Fatal(err) 208 } 209 defer file.Close() 210 zipReader, err := gzip.NewReader(file) 211 if err != nil { 212 t.Fatal(err) 213 } 214 defer zipReader.Close() 215 antepenult, err := io.ReadAll(zipReader) 216 if err != nil { 217 t.Fatal(err) 218 } 219 220 expectedAntepenultimate := `{"log":"line0\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 221 {"log":"line1\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 222 {"log":"line2\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 223 {"log":"line3\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 224 {"log":"line4\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 225 {"log":"line5\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 226 {"log":"line6\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 227 {"log":"line7\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 228 {"log":"line8\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 229 {"log":"line9\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 230 {"log":"line10\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 231 {"log":"line11\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 232 {"log":"line12\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 233 {"log":"line13\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 234 {"log":"line14\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 235 {"log":"line15\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 236 ` 237 expectedPenultimate := `{"log":"line16\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 238 {"log":"line17\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 239 {"log":"line18\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 240 {"log":"line19\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 241 {"log":"line20\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 242 {"log":"line21\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 243 {"log":"line22\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 244 {"log":"line23\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 245 {"log":"line24\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 246 {"log":"line25\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 247 {"log":"line26\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 248 {"log":"line27\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 249 {"log":"line28\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 250 {"log":"line29\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 251 {"log":"line30\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 252 {"log":"line31\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 253 ` 254 expected := `{"log":"line32\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 255 {"log":"line33\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 256 {"log":"line34\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 257 {"log":"line35\n","stream":"src1","time":"0001-01-01T00:00:00Z"} 258 ` 259 260 if string(res) != expected { 261 t.Fatalf("Wrong log content: %q, expected %q", res, expected) 262 } 263 if string(penUlt) != expectedPenultimate { 264 t.Fatalf("Wrong log content: %q, expected %q", penUlt, expectedPenultimate) 265 } 266 if string(antepenult) != expectedAntepenultimate { 267 t.Fatalf("Wrong log content: %q, expected %q", antepenult, expectedAntepenultimate) 268 } 269 } 270 271 func TestJSONFileLoggerWithLabelsEnv(t *testing.T) { 272 cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657" 273 tmp, err := os.MkdirTemp("", "docker-logger-") 274 if err != nil { 275 t.Fatal(err) 276 } 277 defer os.RemoveAll(tmp) 278 filename := filepath.Join(tmp, "container.log") 279 config := map[string]string{"labels": "rack,dc", "labels-regex": "^loc", "env": "environ,debug,ssl", "env-regex": "^dc"} 280 l, err := New(logger.Info{ 281 ContainerID: cid, 282 LogPath: filename, 283 Config: config, 284 ContainerLabels: map[string]string{"rack": "101", "dc": "lhr", "location": "here"}, 285 ContainerEnv: []string{"environ=production", "debug=false", "port=10001", "ssl=true", "dc_region=west"}, 286 }) 287 if err != nil { 288 t.Fatal(err) 289 } 290 defer l.Close() 291 if err := l.Log(&logger.Message{Line: []byte("line"), Source: "src1"}); err != nil { 292 t.Fatal(err) 293 } 294 res, err := os.ReadFile(filename) 295 if err != nil { 296 t.Fatal(err) 297 } 298 299 var jsonLog jsonlog.JSONLogs 300 if err := json.Unmarshal(res, &jsonLog); err != nil { 301 t.Fatal(err) 302 } 303 extra := make(map[string]string) 304 if err := json.Unmarshal(jsonLog.RawAttrs, &extra); err != nil { 305 t.Fatal(err) 306 } 307 expected := map[string]string{ 308 "rack": "101", 309 "dc": "lhr", 310 "location": "here", 311 "environ": "production", 312 "debug": "false", 313 "ssl": "true", 314 "dc_region": "west", 315 } 316 if !reflect.DeepEqual(extra, expected) { 317 t.Fatalf("Wrong log attrs: %q, expected %q", extra, expected) 318 } 319 }