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  }