Signed-off-by: Jim Minter <jminter@redhat.com>
Jim Minter authored on 2017/03/16 00:41:12... | ... |
@@ -18,12 +18,13 @@ import ( |
18 | 18 |
const name = "journald" |
19 | 19 |
|
20 | 20 |
type journald struct { |
21 |
+ mu sync.Mutex |
|
21 | 22 |
vars map[string]string // additional variables and values to send to the journal along with the log message |
22 | 23 |
readers readerList |
24 |
+ closed bool |
|
23 | 25 |
} |
24 | 26 |
|
25 | 27 |
type readerList struct { |
26 |
- mu sync.Mutex |
|
27 | 28 |
readers map[*logger.LogWatcher]*logger.LogWatcher |
28 | 29 |
} |
29 | 30 |
|
... | ... |
@@ -161,11 +161,12 @@ import ( |
161 | 161 |
) |
162 | 162 |
|
163 | 163 |
func (s *journald) Close() error { |
164 |
- s.readers.mu.Lock() |
|
164 |
+ s.mu.Lock() |
|
165 |
+ s.closed = true |
|
165 | 166 |
for reader := range s.readers.readers { |
166 | 167 |
reader.Close() |
167 | 168 |
} |
168 |
- s.readers.mu.Unlock() |
|
169 |
+ s.mu.Unlock() |
|
169 | 170 |
return nil |
170 | 171 |
} |
171 | 172 |
|
... | ... |
@@ -245,9 +246,16 @@ drain: |
245 | 245 |
} |
246 | 246 |
|
247 | 247 |
func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.ReadConfig, j *C.sd_journal, pfd [2]C.int, cursor *C.char) *C.char { |
248 |
- s.readers.mu.Lock() |
|
248 |
+ s.mu.Lock() |
|
249 | 249 |
s.readers.readers[logWatcher] = logWatcher |
250 |
- s.readers.mu.Unlock() |
|
250 |
+ if s.closed { |
|
251 |
+ // the journald Logger is closed, presumably because the container has been |
|
252 |
+ // reset. So we shouldn't follow, because we'll never be woken up. But we |
|
253 |
+ // should make one more drainJournal call to be sure we've got all the logs. |
|
254 |
+ // Close pfd[1] so that one drainJournal happens, then cleanup, then return. |
|
255 |
+ C.close(pfd[1]) |
|
256 |
+ } |
|
257 |
+ s.mu.Unlock() |
|
251 | 258 |
|
252 | 259 |
newCursor := make(chan *C.char) |
253 | 260 |
|
... | ... |
@@ -274,22 +282,22 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re |
274 | 274 |
|
275 | 275 |
// Clean up. |
276 | 276 |
C.close(pfd[0]) |
277 |
- s.readers.mu.Lock() |
|
277 |
+ s.mu.Lock() |
|
278 | 278 |
delete(s.readers.readers, logWatcher) |
279 |
- s.readers.mu.Unlock() |
|
279 |
+ s.mu.Unlock() |
|
280 | 280 |
close(logWatcher.Msg) |
281 | 281 |
newCursor <- cursor |
282 | 282 |
}() |
283 | 283 |
|
284 | 284 |
// Wait until we're told to stop. |
285 | 285 |
select { |
286 |
+ case cursor = <-newCursor: |
|
286 | 287 |
case <-logWatcher.WatchClose(): |
287 | 288 |
// Notify the other goroutine that its work is done. |
288 | 289 |
C.close(pfd[1]) |
290 |
+ cursor = <-newCursor |
|
289 | 291 |
} |
290 | 292 |
|
291 |
- cursor = <-newCursor |
|
292 |
- |
|
293 | 293 |
return cursor |
294 | 294 |
} |
295 | 295 |
|
... | ... |
@@ -27,6 +27,7 @@ type JSONFileLogger struct { |
27 | 27 |
mu sync.Mutex |
28 | 28 |
readers map[*logger.LogWatcher]struct{} // stores the active log followers |
29 | 29 |
extra []byte // json-encoded extra attributes |
30 |
+ closed bool |
|
30 | 31 |
} |
31 | 32 |
|
32 | 33 |
func init() { |
... | ... |
@@ -142,6 +143,7 @@ func (l *JSONFileLogger) LogPath() string { |
142 | 142 |
// Close closes underlying file and signals all readers to stop. |
143 | 143 |
func (l *JSONFileLogger) Close() error { |
144 | 144 |
l.mu.Lock() |
145 |
+ l.closed = true |
|
145 | 146 |
err := l.writer.Close() |
146 | 147 |
for r := range l.readers { |
147 | 148 |
r.Close() |
... | ... |
@@ -88,10 +88,7 @@ func (l *JSONFileLogger) readLogs(logWatcher *logger.LogWatcher, config logger.R |
88 | 88 |
} |
89 | 89 |
} |
90 | 90 |
|
91 |
- if !config.Follow { |
|
92 |
- if err := latestFile.Close(); err != nil { |
|
93 |
- logrus.Errorf("Error closing file: %v", err) |
|
94 |
- } |
|
91 |
+ if !config.Follow || l.closed { |
|
95 | 92 |
l.mu.Unlock() |
96 | 93 |
return |
97 | 94 |
} |
... | ... |
@@ -100,17 +97,18 @@ func (l *JSONFileLogger) readLogs(logWatcher *logger.LogWatcher, config logger.R |
100 | 100 |
latestFile.Seek(0, os.SEEK_END) |
101 | 101 |
} |
102 | 102 |
|
103 |
+ notifyRotate := l.writer.NotifyRotate() |
|
104 |
+ defer l.writer.NotifyRotateEvict(notifyRotate) |
|
105 |
+ |
|
103 | 106 |
l.readers[logWatcher] = struct{}{} |
107 |
+ |
|
104 | 108 |
l.mu.Unlock() |
105 | 109 |
|
106 |
- notifyRotate := l.writer.NotifyRotate() |
|
107 | 110 |
followLogs(latestFile, logWatcher, notifyRotate, config.Since) |
108 | 111 |
|
109 | 112 |
l.mu.Lock() |
110 | 113 |
delete(l.readers, logWatcher) |
111 | 114 |
l.mu.Unlock() |
112 |
- |
|
113 |
- l.writer.NotifyRotateEvict(notifyRotate) |
|
114 | 115 |
} |
115 | 116 |
|
116 | 117 |
func tailFile(f io.ReadSeeker, logWatcher *logger.LogWatcher, tail int, since time.Time) { |
... | ... |
@@ -62,7 +62,7 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c |
62 | 62 |
return nil, logger.ErrReadLogsNotSupported |
63 | 63 |
} |
64 | 64 |
|
65 |
- follow := config.Follow && container.IsRunning() |
|
65 |
+ follow := config.Follow && !cLogCreated |
|
66 | 66 |
tailLines, err := strconv.Atoi(config.Tail) |
67 | 67 |
if err != nil { |
68 | 68 |
tailLines = -1 |