Browse code

Ensure reader position is at the end after tailing

After tailing a file, if the number of lines requested is > the number
of lines in the file, this would cause a json unmarshalling error to
occur when we later try to go follow the file.
So brute force set it to the end if any tailing occurred.

There is potential that there could be some missing log messages if logs
are being written very quickly, however I was not able to make this
happen even with `while true; do echo hello; done`, so this is probably
acceptable.

While testing this I also found a panic in LogWatcher.Close can be
called twice due to a race. Fix channel close to only close when there
has been no signal to the channel.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2015/08/01 05:49:07
Showing 2 changed files
... ...
@@ -267,7 +267,8 @@ func (l *JSONFileLogger) readLogs(logWatcher *logger.LogWatcher, config logger.R
267 267
 	if !config.Follow {
268 268
 		return
269 269
 	}
270
-	if config.Tail == 0 {
270
+
271
+	if config.Tail >= 0 {
271 272
 		latestFile.Seek(0, os.SEEK_END)
272 273
 	}
273 274
 
... ...
@@ -9,6 +9,7 @@ package logger
9 9
 
10 10
 import (
11 11
 	"errors"
12
+	"sync"
12 13
 	"time"
13 14
 
14 15
 	"github.com/docker/docker/pkg/timeutils"
... ...
@@ -58,6 +59,7 @@ type LogWatcher struct {
58 58
 	// For sending error messages that occur while while reading logs.
59 59
 	Err           chan error
60 60
 	closeNotifier chan struct{}
61
+	closeOnce     sync.Once
61 62
 }
62 63
 
63 64
 // NewLogWatcher returns a new LogWatcher.
... ...
@@ -71,7 +73,12 @@ func NewLogWatcher() *LogWatcher {
71 71
 
72 72
 // Close notifies the underlying log reader to stop.
73 73
 func (w *LogWatcher) Close() {
74
-	close(w.closeNotifier)
74
+	// only close if not already closed
75
+	select {
76
+	case <-w.closeNotifier:
77
+	default:
78
+		close(w.closeNotifier)
79
+	}
75 80
 }
76 81
 
77 82
 // WatchClose returns a channel receiver that receives notification