github.com/moby/docker@v26.1.3+incompatible/daemon/logger/journald/read_test.go (about) 1 //go:build linux && cgo && !static_build && journald 2 3 package journald // import "github.com/docker/docker/daemon/logger/journald" 4 5 import ( 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/coreos/go-systemd/v22/journal" 11 "gotest.tools/v3/assert" 12 13 "github.com/docker/docker/daemon/logger" 14 "github.com/docker/docker/daemon/logger/journald/internal/fake" 15 "github.com/docker/docker/daemon/logger/loggertest" 16 ) 17 18 func TestLogRead(t *testing.T) { 19 r := loggertest.Reader{ 20 Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger { 21 journalDir := t.TempDir() 22 23 // Fill the journal with irrelevant events which the 24 // LogReader needs to filter out. 25 rotatedJournal := fake.NewT(t, journalDir+"/rotated.journal") 26 rotatedJournal.AssignEventTimestampFromSyslogTimestamp = true 27 l, err := new(logger.Info{ 28 ContainerID: "wrongone0001", 29 ContainerName: "fake", 30 }) 31 assert.NilError(t, err) 32 l.sendToJournal = rotatedJournal.Send 33 assert.NilError(t, l.Log(&logger.Message{Source: "stdout", Timestamp: time.Now().Add(-1 * 30 * time.Minute), Line: []byte("stdout of a different container in a rotated journal file")})) 34 assert.NilError(t, l.Log(&logger.Message{Source: "stderr", Timestamp: time.Now().Add(-1 * 30 * time.Minute), Line: []byte("stderr of a different container in a rotated journal file")})) 35 assert.NilError(t, rotatedJournal.Send("a log message from a totally different process in a rotated journal", journal.PriInfo, nil)) 36 37 activeJournal := fake.NewT(t, journalDir+"/fake.journal") 38 activeJournal.AssignEventTimestampFromSyslogTimestamp = true 39 l, err = new(logger.Info{ 40 ContainerID: "wrongone0002", 41 ContainerName: "fake", 42 }) 43 assert.NilError(t, err) 44 l.sendToJournal = activeJournal.Send 45 assert.NilError(t, l.Log(&logger.Message{Source: "stdout", Timestamp: time.Now().Add(-1 * 30 * time.Minute), Line: []byte("stdout of a different container in the active journal file")})) 46 assert.NilError(t, l.Log(&logger.Message{Source: "stderr", Timestamp: time.Now().Add(-1 * 30 * time.Minute), Line: []byte("stderr of a different container in the active journal file")})) 47 assert.NilError(t, rotatedJournal.Send("a log message from a totally different process in the active journal", journal.PriInfo, nil)) 48 49 return func(t *testing.T) logger.Logger { 50 l, err := new(info) 51 assert.NilError(t, err) 52 l.journalReadDir = journalDir 53 sl := &syncLogger{journald: l, waiters: map[uint64]chan<- struct{}{}} 54 55 s := make(chan sendit, 100) 56 t.Cleanup(func() { close(s) }) 57 go func() { 58 for m := range s { 59 <-m.after 60 activeJournal.Send(m.message, m.priority, m.vars) 61 sl.mu.Lock() 62 sl.sent++ 63 if notify, ok := sl.waiters[sl.sent]; ok { 64 delete(sl.waiters, sl.sent) 65 close(notify) 66 } 67 sl.mu.Unlock() 68 } 69 }() 70 71 l.sendToJournal = func(message string, priority journal.Priority, vars map[string]string) error { 72 sl.mu.Lock() 73 sl.queued++ 74 sl.mu.Unlock() 75 s <- sendit{ 76 message: message, 77 priority: priority, 78 vars: vars, 79 after: time.After(150 * time.Millisecond), 80 } 81 return nil 82 } 83 l.readSyncTimeout = 3 * time.Second 84 return sl 85 } 86 }, 87 } 88 t.Run("Tail", r.TestTail) 89 t.Run("Follow", r.TestFollow) 90 } 91 92 type sendit struct { 93 message string 94 priority journal.Priority 95 vars map[string]string 96 after <-chan time.Time 97 } 98 99 type syncLogger struct { 100 *journald 101 102 mu sync.Mutex 103 queued, sent uint64 104 waiters map[uint64]chan<- struct{} 105 } 106 107 func (l *syncLogger) Sync() error { 108 l.mu.Lock() 109 waitFor := l.queued 110 if l.sent >= l.queued { 111 l.mu.Unlock() 112 return nil 113 } 114 notify := make(chan struct{}) 115 l.waiters[waitFor] = notify 116 l.mu.Unlock() 117 <-notify 118 return nil 119 } 120 121 func (l *syncLogger) Close() error { 122 _ = l.Sync() 123 return l.journald.Close() 124 }