123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- package jsonfilelog // import "github.com/docker/docker/daemon/logger/jsonfilelog"
- import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "strconv"
- "testing"
- "text/tabwriter"
- "time"
- "github.com/docker/docker/daemon/logger"
- "github.com/docker/docker/daemon/logger/loggertest"
- "gotest.tools/v3/assert"
- )
- func BenchmarkJSONFileLoggerReadLogs(b *testing.B) {
- tmp := b.TempDir()
- jsonlogger, err := New(logger.Info{
- ContainerID: "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657",
- LogPath: filepath.Join(tmp, "container.log"),
- Config: map[string]string{
- "labels": "first,second",
- },
- ContainerLabels: map[string]string{
- "first": "label_value",
- "second": "label_foo",
- },
- })
- assert.NilError(b, err)
- defer jsonlogger.Close()
- const line = "Line that thinks that it is log line from docker\n"
- ts := time.Date(2007, 1, 2, 3, 4, 5, 6, time.UTC)
- msg := func() *logger.Message {
- m := logger.NewMessage()
- m.Line = append(m.Line, line...)
- m.Source = "stderr"
- m.Timestamp = ts
- return m
- }
- var buf bytes.Buffer
- assert.NilError(b, marshalMessage(msg(), nil, &buf))
- b.SetBytes(int64(buf.Len()))
- b.ResetTimer()
- chError := make(chan error)
- go func() {
- for i := 0; i < b.N; i++ {
- if err := jsonlogger.Log(msg()); err != nil {
- chError <- err
- }
- }
- if err := jsonlogger.Close(); err != nil {
- chError <- err
- }
- }()
- lw := jsonlogger.(*JSONFileLogger).ReadLogs(logger.ReadConfig{Follow: true})
- for {
- select {
- case _, ok := <-lw.Msg:
- if !ok {
- return
- }
- case err := <-chError:
- b.Fatal(err)
- }
- }
- }
- func TestEncodeDecode(t *testing.T) {
- t.Parallel()
- m1 := &logger.Message{Line: []byte("hello 1"), Timestamp: time.Now(), Source: "stdout"}
- m2 := &logger.Message{Line: []byte("hello 2"), Timestamp: time.Now(), Source: "stdout"}
- m3 := &logger.Message{Line: []byte("hello 3"), Timestamp: time.Now(), Source: "stdout"}
- buf := bytes.NewBuffer(nil)
- assert.Assert(t, marshalMessage(m1, nil, buf))
- assert.Assert(t, marshalMessage(m2, nil, buf))
- assert.Assert(t, marshalMessage(m3, nil, buf))
- dec := decodeFunc(buf)
- defer dec.Close()
- msg, err := dec.Decode()
- assert.NilError(t, err)
- assert.Assert(t, string(msg.Line) == "hello 1\n", string(msg.Line))
- msg, err = dec.Decode()
- assert.NilError(t, err)
- assert.Assert(t, string(msg.Line) == "hello 2\n")
- msg, err = dec.Decode()
- assert.NilError(t, err)
- assert.Assert(t, string(msg.Line) == "hello 3\n")
- _, err = dec.Decode()
- assert.Assert(t, err == io.EOF)
- }
- func TestReadLogs(t *testing.T) {
- t.Parallel()
- r := loggertest.Reader{
- Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
- dir := t.TempDir()
- info.LogPath = filepath.Join(dir, info.ContainerID+".log")
- return func(t *testing.T) logger.Logger {
- l, err := New(info)
- assert.NilError(t, err)
- return l
- }
- },
- }
- t.Run("Tail", r.TestTail)
- t.Run("Follow", r.TestFollow)
- }
- func TestTailLogsWithRotation(t *testing.T) {
- t.Parallel()
- compress := func(cmprs bool) {
- t.Run(fmt.Sprintf("compress=%v", cmprs), func(t *testing.T) {
- t.Parallel()
- (&loggertest.Reader{
- Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
- info.Config = map[string]string{
- "compress": strconv.FormatBool(cmprs),
- "max-size": "1b",
- "max-file": "10",
- }
- dir := t.TempDir()
- t.Cleanup(func() {
- t.Logf("%s:\n%s", t.Name(), dirStringer{dir})
- })
- info.LogPath = filepath.Join(dir, info.ContainerID+".log")
- return func(t *testing.T) logger.Logger {
- l, err := New(info)
- assert.NilError(t, err)
- return l
- }
- },
- }).TestTail(t)
- })
- }
- compress(true)
- compress(false)
- }
- func TestFollowLogsWithRotation(t *testing.T) {
- t.Parallel()
- compress := func(cmprs bool) {
- t.Run(fmt.Sprintf("compress=%v", cmprs), func(t *testing.T) {
- t.Parallel()
- (&loggertest.Reader{
- Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
- // The log follower can fall behind and drop logs if there are too many
- // rotations in a short time. If that was to happen, loggertest would fail the
- // test. Configure the logger so that there will be only one rotation with the
- // set of logs that loggertest writes.
- info.Config = map[string]string{
- "compress": strconv.FormatBool(cmprs),
- "max-size": "4096b",
- "max-file": "3",
- }
- dir := t.TempDir()
- t.Cleanup(func() {
- t.Logf("%s:\n%s", t.Name(), dirStringer{dir})
- })
- info.LogPath = filepath.Join(dir, info.ContainerID+".log")
- return func(t *testing.T) logger.Logger {
- l, err := New(info)
- assert.NilError(t, err)
- return l
- }
- },
- }).TestFollow(t)
- })
- }
- compress(true)
- compress(false)
- }
- type dirStringer struct {
- d string
- }
- func (d dirStringer) String() string {
- ls, err := os.ReadDir(d.d)
- if err != nil {
- return ""
- }
- buf := bytes.NewBuffer(nil)
- tw := tabwriter.NewWriter(buf, 1, 8, 1, '\t', 0)
- buf.WriteString("\n")
- btw := bufio.NewWriter(tw)
- for _, entry := range ls {
- fi, err := entry.Info()
- if err != nil {
- return ""
- }
- btw.WriteString(fmt.Sprintf("%s\t%s\t%dB\t%s\n", fi.Name(), fi.Mode(), fi.Size(), fi.ModTime()))
- }
- btw.Flush()
- tw.Flush()
- return buf.String()
- }
|