From f40860c5f3d3575629d4a932207e866c1fea625d Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Tue, 13 Feb 2018 15:03:56 -0500 Subject: [PATCH] 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 --- daemon/logger/loggerutils/logfile.go | 8 +++++-- integration/container/logs_test.go | 33 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 integration/container/logs_test.go diff --git a/daemon/logger/loggerutils/logfile.go b/daemon/logger/loggerutils/logfile.go index ff7a3323f9..a9d9d633db 100644 --- a/daemon/logger/loggerutils/logfile.go +++ b/daemon/logger/loggerutils/logfile.go @@ -192,8 +192,12 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher) for _, f := range files { seekers = append(seekers, f) } - seekers = append(seekers, currentChunk) - tailFile(multireader.MultiReadSeeker(seekers...), watcher, w.createDecoder, config) + if currentChunk.Size() > 0 { + seekers = append(seekers, currentChunk) + } + if len(seekers) > 0 { + tailFile(multireader.MultiReadSeeker(seekers...), watcher, w.createDecoder, config) + } } w.mu.RLock() diff --git a/integration/container/logs_test.go b/integration/container/logs_test.go new file mode 100644 index 0000000000..1157da14b8 --- /dev/null +++ b/integration/container/logs_test.go @@ -0,0 +1,33 @@ +package container + +import ( + "context" + "io/ioutil" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/integration/internal/container" + "github.com/docker/docker/integration/internal/request" + "github.com/docker/docker/pkg/stdcopy" + "github.com/stretchr/testify/assert" +) + +// Regression test for #35370 +// Makes sure that when following we don't get an EOF error when there are no logs +func TestLogsFollowTailEmpty(t *testing.T) { + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + id := container.Run(t, ctx, client, container.WithCmd("sleep", "100000")) + defer client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true}) + + logs, err := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"}) + if logs != nil { + defer logs.Close() + } + assert.NoError(t, err) + + _, err = stdcopy.StdCopy(ioutil.Discard, ioutil.Discard, logs) + assert.NoError(t, err) +}