daemon/logger: drain readers when logger is closed

The LogFile follower would stop immediately upon the producer closing.
The close signal would race the file watcher; if a message were to be
logged and the logger immediately closed, the follower could miss that
last message if the close signal (formerly ProducerGone) was to win the
race. Add logic to perform one more round of reading when the producer
is closed to catch up on any final logs.

Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
Cory Snider 2022-03-02 17:33:39 -05:00
parent 906b979b88
commit 3844d1a3d1
3 changed files with 11 additions and 5 deletions

View file

@ -21,6 +21,7 @@ type follow struct {
fileWatcher filenotify.FileWatcher
logWatcher *logger.LogWatcher
producerGone <-chan struct{}
draining bool
notifyRotate, notifyEvict chan interface{}
oldSize int64
retries int
@ -99,7 +100,14 @@ func (fl *follow) waitRead() error {
}
return err
case <-fl.producerGone:
return errDone
// There may be messages written out which the fileWatcher has
// not yet notified us about.
if fl.draining {
return errDone
}
fl.draining = true
fl.dec.Reset(fl.file)
return nil
case <-fl.logWatcher.WatchConsumerGone():
return errDone
}

View file

@ -440,11 +440,10 @@ func (w *LogFile) readLogsLocked(config logger.ReadConfig, watcher *logger.LogWa
w.mu.RLock()
}
if !config.Follow || w.closed {
w.mu.RUnlock()
w.mu.RUnlock()
if !config.Follow {
return
}
w.mu.RUnlock()
notifyRotate := w.notifyReaders.SubscribeTopic(func(i interface{}) bool {
_, ok := i.(struct{})

View file

@ -179,7 +179,6 @@ func TestFollowLogsProducerGone(t *testing.T) {
t.Logf("logDecode() closed after sending %d messages\n", sent)
return io.EOF
default:
t.Fatal("logDecode() called after closing!")
return io.EOF
}
}}