diff --git a/daemon/logger/journald/journald.go b/daemon/logger/journald/journald.go index 04ae84b6d9..9865a273c5 100644 --- a/daemon/logger/journald/journald.go +++ b/daemon/logger/journald/journald.go @@ -18,12 +18,13 @@ import ( const name = "journald" type journald struct { + mu sync.Mutex vars map[string]string // additional variables and values to send to the journal along with the log message readers readerList + closed bool } type readerList struct { - mu sync.Mutex readers map[*logger.LogWatcher]*logger.LogWatcher } diff --git a/daemon/logger/journald/read.go b/daemon/logger/journald/read.go index 9b896e0dc7..9ecc3b521d 100644 --- a/daemon/logger/journald/read.go +++ b/daemon/logger/journald/read.go @@ -161,11 +161,12 @@ import ( ) func (s *journald) Close() error { - s.readers.mu.Lock() + s.mu.Lock() + s.closed = true for reader := range s.readers.readers { reader.Close() } - s.readers.mu.Unlock() + s.mu.Unlock() return nil } @@ -245,9 +246,16 @@ drain: } func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.ReadConfig, j *C.sd_journal, pfd [2]C.int, cursor *C.char) *C.char { - s.readers.mu.Lock() + s.mu.Lock() s.readers.readers[logWatcher] = logWatcher - s.readers.mu.Unlock() + if s.closed { + // the journald Logger is closed, presumably because the container has been + // reset. So we shouldn't follow, because we'll never be woken up. But we + // should make one more drainJournal call to be sure we've got all the logs. + // Close pfd[1] so that one drainJournal happens, then cleanup, then return. + C.close(pfd[1]) + } + s.mu.Unlock() newCursor := make(chan *C.char) @@ -274,22 +282,22 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re // Clean up. C.close(pfd[0]) - s.readers.mu.Lock() + s.mu.Lock() delete(s.readers.readers, logWatcher) - s.readers.mu.Unlock() + s.mu.Unlock() close(logWatcher.Msg) newCursor <- cursor }() // Wait until we're told to stop. select { + case cursor = <-newCursor: case <-logWatcher.WatchClose(): // Notify the other goroutine that its work is done. C.close(pfd[1]) + cursor = <-newCursor } - cursor = <-newCursor - return cursor } diff --git a/daemon/logger/jsonfilelog/jsonfilelog.go b/daemon/logger/jsonfilelog/jsonfilelog.go index 5ad701a0d7..797644e669 100644 --- a/daemon/logger/jsonfilelog/jsonfilelog.go +++ b/daemon/logger/jsonfilelog/jsonfilelog.go @@ -27,6 +27,7 @@ type JSONFileLogger struct { mu sync.Mutex readers map[*logger.LogWatcher]struct{} // stores the active log followers extra []byte // json-encoded extra attributes + closed bool } func init() { @@ -142,6 +143,7 @@ func (l *JSONFileLogger) LogPath() string { // Close closes underlying file and signals all readers to stop. func (l *JSONFileLogger) Close() error { l.mu.Lock() + l.closed = true err := l.writer.Close() for r := range l.readers { r.Close() diff --git a/daemon/logger/jsonfilelog/read.go b/daemon/logger/jsonfilelog/read.go index 30d533fc1f..9f282eafbb 100644 --- a/daemon/logger/jsonfilelog/read.go +++ b/daemon/logger/jsonfilelog/read.go @@ -88,10 +88,7 @@ func (l *JSONFileLogger) readLogs(logWatcher *logger.LogWatcher, config logger.R } } - if !config.Follow { - if err := latestFile.Close(); err != nil { - logrus.Errorf("Error closing file: %v", err) - } + if !config.Follow || l.closed { l.mu.Unlock() return } @@ -100,17 +97,18 @@ func (l *JSONFileLogger) readLogs(logWatcher *logger.LogWatcher, config logger.R latestFile.Seek(0, os.SEEK_END) } + notifyRotate := l.writer.NotifyRotate() + defer l.writer.NotifyRotateEvict(notifyRotate) + l.readers[logWatcher] = struct{}{} + l.mu.Unlock() - notifyRotate := l.writer.NotifyRotate() followLogs(latestFile, logWatcher, notifyRotate, config.Since) l.mu.Lock() delete(l.readers, logWatcher) l.mu.Unlock() - - l.writer.NotifyRotateEvict(notifyRotate) } func tailFile(f io.ReadSeeker, logWatcher *logger.LogWatcher, tail int, since time.Time) { diff --git a/daemon/logs.go b/daemon/logs.go index 3d59fb3e72..96e1b8a491 100644 --- a/daemon/logs.go +++ b/daemon/logs.go @@ -62,7 +62,7 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c return nil, logger.ErrReadLogsNotSupported } - follow := config.Follow && container.IsRunning() + follow := config.Follow && !cLogCreated tailLines, err := strconv.Atoi(config.Tail) if err != nil { tailLines = -1