From f779cfc5d8b8f0686c3849a3bd4ab0480675180d Mon Sep 17 00:00:00 2001 From: Burke Libbey Date: Thu, 28 May 2015 16:59:25 -0400 Subject: [PATCH] Use bufio.Reader instead of bufio.Scanner for logger.Copier When using a scanner, log lines over 64K will crash the Copier with bufio.ErrTooLong. Subsequently, the ioutils.bufReader will grow without bound as the logs are no longer being flushed to disk. Signed-off-by: Burke Libbey --- daemon/logger/copier.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/daemon/logger/copier.go b/daemon/logger/copier.go index 462e42346d..6fe2b00755 100644 --- a/daemon/logger/copier.go +++ b/daemon/logger/copier.go @@ -2,6 +2,7 @@ package logger import ( "bufio" + "bytes" "io" "sync" "time" @@ -40,14 +41,27 @@ func (c *Copier) Run() { func (c *Copier) copySrc(name string, src io.Reader) { defer c.copyJobs.Done() - scanner := bufio.NewScanner(src) - for scanner.Scan() { - if err := c.dst.Log(&Message{ContainerID: c.cid, Line: scanner.Bytes(), Source: name, Timestamp: time.Now().UTC()}); err != nil { - logrus.Errorf("Failed to log msg %q for logger %s: %s", scanner.Bytes(), c.dst.Name(), err) + reader := bufio.NewReader(src) + + for { + line, err := reader.ReadBytes('\n') + line = bytes.TrimSuffix(line, []byte{'\n'}) + + // ReadBytes can return full or partial output even when it failed. + // e.g. it can return a full entry and EOF. + if err == nil || len(line) > 0 { + if logErr := c.dst.Log(&Message{ContainerID: c.cid, Line: line, Source: name, Timestamp: time.Now().UTC()}); logErr != nil { + logrus.Errorf("Failed to log msg %q for logger %s: %s", line, c.dst.Name(), logErr) + } } - } - if err := scanner.Err(); err != nil { - logrus.Errorf("Error scanning log stream: %s", err) + + if err != nil { + if err != io.EOF { + logrus.Errorf("Error scanning log stream: %s", err) + } + return + } + } }