read_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package jsonfilelog // import "github.com/docker/docker/daemon/logger/jsonfilelog"
  2. import (
  3. "bufio"
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "testing"
  11. "text/tabwriter"
  12. "time"
  13. "github.com/docker/docker/daemon/logger"
  14. "github.com/docker/docker/daemon/logger/loggertest"
  15. "gotest.tools/v3/assert"
  16. )
  17. func BenchmarkJSONFileLoggerReadLogs(b *testing.B) {
  18. tmp := b.TempDir()
  19. jsonlogger, err := New(logger.Info{
  20. ContainerID: "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657",
  21. LogPath: filepath.Join(tmp, "container.log"),
  22. Config: map[string]string{
  23. "labels": "first,second",
  24. },
  25. ContainerLabels: map[string]string{
  26. "first": "label_value",
  27. "second": "label_foo",
  28. },
  29. })
  30. assert.NilError(b, err)
  31. defer jsonlogger.Close()
  32. const line = "Line that thinks that it is log line from docker\n"
  33. ts := time.Date(2007, 1, 2, 3, 4, 5, 6, time.UTC)
  34. msg := func() *logger.Message {
  35. m := logger.NewMessage()
  36. m.Line = append(m.Line, line...)
  37. m.Source = "stderr"
  38. m.Timestamp = ts
  39. return m
  40. }
  41. var buf bytes.Buffer
  42. assert.NilError(b, marshalMessage(msg(), nil, &buf))
  43. b.SetBytes(int64(buf.Len()))
  44. b.ResetTimer()
  45. chError := make(chan error)
  46. go func() {
  47. for i := 0; i < b.N; i++ {
  48. if err := jsonlogger.Log(msg()); err != nil {
  49. chError <- err
  50. }
  51. }
  52. if err := jsonlogger.Close(); err != nil {
  53. chError <- err
  54. }
  55. }()
  56. lw := jsonlogger.(*JSONFileLogger).ReadLogs(logger.ReadConfig{Follow: true})
  57. for {
  58. select {
  59. case _, ok := <-lw.Msg:
  60. if !ok {
  61. return
  62. }
  63. case err := <-chError:
  64. b.Fatal(err)
  65. }
  66. }
  67. }
  68. func TestEncodeDecode(t *testing.T) {
  69. t.Parallel()
  70. m1 := &logger.Message{Line: []byte("hello 1"), Timestamp: time.Now(), Source: "stdout"}
  71. m2 := &logger.Message{Line: []byte("hello 2"), Timestamp: time.Now(), Source: "stdout"}
  72. m3 := &logger.Message{Line: []byte("hello 3"), Timestamp: time.Now(), Source: "stdout"}
  73. buf := bytes.NewBuffer(nil)
  74. assert.Assert(t, marshalMessage(m1, nil, buf))
  75. assert.Assert(t, marshalMessage(m2, nil, buf))
  76. assert.Assert(t, marshalMessage(m3, nil, buf))
  77. dec := decodeFunc(buf)
  78. defer dec.Close()
  79. msg, err := dec.Decode()
  80. assert.NilError(t, err)
  81. assert.Assert(t, string(msg.Line) == "hello 1\n", string(msg.Line))
  82. msg, err = dec.Decode()
  83. assert.NilError(t, err)
  84. assert.Assert(t, string(msg.Line) == "hello 2\n")
  85. msg, err = dec.Decode()
  86. assert.NilError(t, err)
  87. assert.Assert(t, string(msg.Line) == "hello 3\n")
  88. _, err = dec.Decode()
  89. assert.Assert(t, err == io.EOF)
  90. }
  91. func TestReadLogs(t *testing.T) {
  92. t.Parallel()
  93. r := loggertest.Reader{
  94. Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
  95. dir := t.TempDir()
  96. info.LogPath = filepath.Join(dir, info.ContainerID+".log")
  97. return func(t *testing.T) logger.Logger {
  98. l, err := New(info)
  99. assert.NilError(t, err)
  100. return l
  101. }
  102. },
  103. }
  104. t.Run("Tail", r.TestTail)
  105. t.Run("Follow", r.TestFollow)
  106. }
  107. func TestTailLogsWithRotation(t *testing.T) {
  108. t.Parallel()
  109. compress := func(cmprs bool) {
  110. t.Run(fmt.Sprintf("compress=%v", cmprs), func(t *testing.T) {
  111. t.Parallel()
  112. (&loggertest.Reader{
  113. Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
  114. info.Config = map[string]string{
  115. "compress": strconv.FormatBool(cmprs),
  116. "max-size": "1b",
  117. "max-file": "10",
  118. }
  119. dir := t.TempDir()
  120. t.Cleanup(func() {
  121. t.Logf("%s:\n%s", t.Name(), dirStringer{dir})
  122. })
  123. info.LogPath = filepath.Join(dir, info.ContainerID+".log")
  124. return func(t *testing.T) logger.Logger {
  125. l, err := New(info)
  126. assert.NilError(t, err)
  127. return l
  128. }
  129. },
  130. }).TestTail(t)
  131. })
  132. }
  133. compress(true)
  134. compress(false)
  135. }
  136. func TestFollowLogsWithRotation(t *testing.T) {
  137. t.Parallel()
  138. compress := func(cmprs bool) {
  139. t.Run(fmt.Sprintf("compress=%v", cmprs), func(t *testing.T) {
  140. t.Parallel()
  141. (&loggertest.Reader{
  142. Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
  143. // The log follower can fall behind and drop logs if there are too many
  144. // rotations in a short time. If that was to happen, loggertest would fail the
  145. // test. Configure the logger so that there will be only one rotation with the
  146. // set of logs that loggertest writes.
  147. info.Config = map[string]string{
  148. "compress": strconv.FormatBool(cmprs),
  149. "max-size": "4096b",
  150. "max-file": "3",
  151. }
  152. dir := t.TempDir()
  153. t.Cleanup(func() {
  154. t.Logf("%s:\n%s", t.Name(), dirStringer{dir})
  155. })
  156. info.LogPath = filepath.Join(dir, info.ContainerID+".log")
  157. return func(t *testing.T) logger.Logger {
  158. l, err := New(info)
  159. assert.NilError(t, err)
  160. return l
  161. }
  162. },
  163. }).TestFollow(t)
  164. })
  165. }
  166. compress(true)
  167. compress(false)
  168. }
  169. type dirStringer struct {
  170. d string
  171. }
  172. func (d dirStringer) String() string {
  173. ls, err := os.ReadDir(d.d)
  174. if err != nil {
  175. return ""
  176. }
  177. buf := bytes.NewBuffer(nil)
  178. tw := tabwriter.NewWriter(buf, 1, 8, 1, '\t', 0)
  179. buf.WriteString("\n")
  180. btw := bufio.NewWriter(tw)
  181. for _, entry := range ls {
  182. fi, err := entry.Info()
  183. if err != nil {
  184. return ""
  185. }
  186. btw.WriteString(fmt.Sprintf("%s\t%s\t%dB\t%s\n", fi.Name(), fi.Mode(), fi.Size(), fi.ModTime()))
  187. }
  188. btw.Flush()
  189. tw.Flush()
  190. return buf.String()
  191. }