local_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package local
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "strconv"
  9. "testing"
  10. "time"
  11. "github.com/docker/docker/api/types/backend"
  12. "github.com/docker/docker/api/types/plugins/logdriver"
  13. "github.com/docker/docker/daemon/logger"
  14. "github.com/docker/docker/daemon/logger/loggertest"
  15. protoio "github.com/gogo/protobuf/io"
  16. "gotest.tools/v3/assert"
  17. is "gotest.tools/v3/assert/cmp"
  18. )
  19. func TestWriteLog(t *testing.T) {
  20. t.Parallel()
  21. dir, err := os.MkdirTemp("", t.Name())
  22. assert.NilError(t, err)
  23. defer os.RemoveAll(dir)
  24. logPath := filepath.Join(dir, "test.log")
  25. l, err := New(logger.Info{LogPath: logPath})
  26. assert.NilError(t, err)
  27. defer l.Close()
  28. m1 := logger.Message{Source: "stdout", Timestamp: time.Now().Add(-1 * 30 * time.Minute), Line: []byte("message 1")}
  29. m2 := logger.Message{Source: "stdout", Timestamp: time.Now().Add(-1 * 20 * time.Minute), Line: []byte("message 2"), PLogMetaData: &backend.PartialLogMetaData{Last: true, ID: "0001", Ordinal: 1}}
  30. m3 := logger.Message{Source: "stderr", Timestamp: time.Now().Add(-1 * 10 * time.Minute), Line: []byte("message 3")}
  31. // copy the log message because the underying log writer resets the log message and returns it to a buffer pool
  32. err = l.Log(copyLogMessage(&m1))
  33. assert.NilError(t, err)
  34. err = l.Log(copyLogMessage(&m2))
  35. assert.NilError(t, err)
  36. err = l.Log(copyLogMessage(&m3))
  37. assert.NilError(t, err)
  38. f, err := os.Open(logPath)
  39. assert.NilError(t, err)
  40. defer f.Close()
  41. dec := protoio.NewUint32DelimitedReader(f, binary.BigEndian, 1e6)
  42. var (
  43. proto logdriver.LogEntry
  44. testProto logdriver.LogEntry
  45. partial logdriver.PartialLogEntryMetadata
  46. )
  47. lenBuf := make([]byte, encodeBinaryLen)
  48. seekMsgLen := func() {
  49. io.ReadFull(f, lenBuf)
  50. }
  51. err = dec.ReadMsg(&proto)
  52. assert.NilError(t, err)
  53. messageToProto(&m1, &testProto, &partial)
  54. assert.Check(t, is.DeepEqual(testProto, proto), "expected:\n%+v\ngot:\n%+v", testProto, proto)
  55. seekMsgLen()
  56. err = dec.ReadMsg(&proto)
  57. assert.NilError(t, err)
  58. messageToProto(&m2, &testProto, &partial)
  59. assert.Check(t, is.DeepEqual(testProto, proto))
  60. seekMsgLen()
  61. err = dec.ReadMsg(&proto)
  62. assert.NilError(t, err)
  63. messageToProto(&m3, &testProto, &partial)
  64. assert.Check(t, is.DeepEqual(testProto, proto), "expected:\n%+v\ngot:\n%+v", testProto, proto)
  65. }
  66. func TestReadLog(t *testing.T) {
  67. r := loggertest.Reader{
  68. Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
  69. dir := t.TempDir()
  70. info.LogPath = filepath.Join(dir, info.ContainerID+".log")
  71. return func(t *testing.T) logger.Logger {
  72. l, err := New(info)
  73. assert.NilError(t, err)
  74. return l
  75. }
  76. },
  77. }
  78. t.Run("Tail", r.TestTail)
  79. t.Run("Follow", r.TestFollow)
  80. }
  81. func BenchmarkLogWrite(b *testing.B) {
  82. f, err := os.CreateTemp("", b.Name())
  83. assert.Assert(b, err)
  84. defer os.Remove(f.Name())
  85. f.Close()
  86. local, err := New(logger.Info{LogPath: f.Name()})
  87. assert.Assert(b, err)
  88. defer local.Close()
  89. t := time.Now().UTC()
  90. for _, data := range [][]byte{
  91. []byte(""),
  92. []byte("a short string"),
  93. bytes.Repeat([]byte("a long string"), 100),
  94. bytes.Repeat([]byte("a really long string"), 10000),
  95. } {
  96. b.Run(strconv.Itoa(len(data)), func(b *testing.B) {
  97. entry := &logdriver.LogEntry{Line: data, Source: "stdout", TimeNano: t.UnixNano()}
  98. b.SetBytes(int64(entry.Size() + encodeBinaryLen + encodeBinaryLen))
  99. b.ResetTimer()
  100. for i := 0; i < b.N; i++ {
  101. msg := logger.NewMessage()
  102. msg.Line = data
  103. msg.Timestamp = t
  104. msg.Source = "stdout"
  105. if err := local.Log(msg); err != nil {
  106. b.Fatal(err)
  107. }
  108. }
  109. })
  110. }
  111. }
  112. func copyLogMessage(src *logger.Message) *logger.Message {
  113. dst := logger.NewMessage()
  114. dst.Source = src.Source
  115. dst.Timestamp = src.Timestamp
  116. dst.Attrs = src.Attrs
  117. dst.Err = src.Err
  118. dst.Line = append(dst.Line, src.Line...)
  119. if src.PLogMetaData != nil {
  120. lmd := *src.PLogMetaData
  121. dst.PLogMetaData = &lmd
  122. }
  123. return dst
  124. }