Browse code

Fix log tail with empty logs

When tailing a container log, if the log file is empty it will cause the
log stream to abort with an unexpected `EOF`.
Note that this only applies to the "current" log file as rotated files
cannot be empty.

This fix just skips adding the "current" file the log tail if it is
empty.

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

Brian Goff authored on 2018/02/14 05:03:56
Showing 2 changed files
... ...
@@ -192,8 +192,12 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
192 192
 		for _, f := range files {
193 193
 			seekers = append(seekers, f)
194 194
 		}
195
-		seekers = append(seekers, currentChunk)
196
-		tailFile(multireader.MultiReadSeeker(seekers...), watcher, w.createDecoder, config)
195
+		if currentChunk.Size() > 0 {
196
+			seekers = append(seekers, currentChunk)
197
+		}
198
+		if len(seekers) > 0 {
199
+			tailFile(multireader.MultiReadSeeker(seekers...), watcher, w.createDecoder, config)
200
+		}
197 201
 	}
198 202
 
199 203
 	w.mu.RLock()
200 204
new file mode 100644
... ...
@@ -0,0 +1,33 @@
0
+package container
1
+
2
+import (
3
+	"context"
4
+	"io/ioutil"
5
+	"testing"
6
+
7
+	"github.com/docker/docker/api/types"
8
+	"github.com/docker/docker/integration/internal/container"
9
+	"github.com/docker/docker/integration/internal/request"
10
+	"github.com/docker/docker/pkg/stdcopy"
11
+	"github.com/stretchr/testify/assert"
12
+)
13
+
14
+// Regression test for #35370
15
+// Makes sure that when following we don't get an EOF error when there are no logs
16
+func TestLogsFollowTailEmpty(t *testing.T) {
17
+	defer setupTest(t)()
18
+	client := request.NewAPIClient(t)
19
+	ctx := context.Background()
20
+
21
+	id := container.Run(t, ctx, client, container.WithCmd("sleep", "100000"))
22
+	defer client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true})
23
+
24
+	logs, err := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"})
25
+	if logs != nil {
26
+		defer logs.Close()
27
+	}
28
+	assert.NoError(t, err)
29
+
30
+	_, err = stdcopy.StdCopy(ioutil.Discard, ioutil.Discard, logs)
31
+	assert.NoError(t, err)
32
+}