diff --git a/tail.go b/tail.go index fbf3129..fe19e27 100644 --- a/tail.go +++ b/tail.go @@ -170,8 +170,17 @@ func (tail *Tail) reopen() error { } func (tail *Tail) readLine() ([]byte, error) { - line, _, err := tail.reader.ReadLine() - return line, err + line, isPrefix, err := tail.reader.ReadLine() + if !isPrefix || tail.MaxLineSize > 0 { + return line, err + } + + buf := append([]byte(nil), line...) + for isPrefix && err == nil { + line, isPrefix, err = tail.reader.ReadLine() + buf = append(buf, line...) + } + return buf, err } func (tail *Tail) tailFileSync() { @@ -199,7 +208,7 @@ func (tail *Tail) tailFileSync() { } } - tail.reader = bufio.NewReader(tail.file) + tail.reader = tail.newReader() // Read line by line. for { @@ -280,7 +289,7 @@ func (tail *Tail) waitForChanges() error { return err } tail.Logger.Printf("Successfully reopened %s", tail.Filename) - tail.reader = bufio.NewReader(tail.file) + tail.reader = tail.newReader() return nil } else { tail.Logger.Printf("Stopping tail as file no longer exists: %s", tail.Filename) @@ -293,7 +302,7 @@ func (tail *Tail) waitForChanges() error { return err } tail.Logger.Printf("Successfully reopened truncated %s", tail.Filename) - tail.reader = bufio.NewReader(tail.file) + tail.reader = tail.newReader() return nil case <-tail.Dying(): return ErrStop @@ -301,6 +310,14 @@ func (tail *Tail) waitForChanges() error { panic("unreachable") } +func (tail *Tail) newReader() *bufio.Reader { + if tail.MaxLineSize > 0 { + return bufio.NewReaderSize(tail.file, tail.MaxLineSize+2) + } else { + return bufio.NewReader(tail.file) + } +} + // sendLine sends the line(s) to Lines channel, splitting longer lines // if necessary. Return false if rate limit is reached. func (tail *Tail) sendLine(line []byte) bool { diff --git a/tail_test.go b/tail_test.go index df47237..c212c0c 100644 --- a/tail_test.go +++ b/tail_test.go @@ -10,6 +10,7 @@ import ( _ "fmt" "io/ioutil" "os" + "strings" "testing" "time" ) @@ -66,6 +67,35 @@ func TestMaxLineSize(_t *testing.T) { Cleanup() } +func TestOver4096ByteLine(_t *testing.T) { + t := NewTailTest("Over4096ByteLine", _t) + testString := strings.Repeat("a", 4097) + t.CreateFile("test.txt", "test\n"+testString+"\nhello\nworld\n") + tail := t.StartTail("test.txt", Config{Follow: true, Location: nil}) + go t.VerifyTailOutput(tail, []string{"test", testString, "hello", "world"}) + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + t.RemoveFile("test.txt") + tail.Stop() + Cleanup() +} +func TestOver4096ByteLineWithSetMaxLineSize(_t *testing.T) { + t := NewTailTest("Over4096ByteLineMaxLineSize", _t) + testString := strings.Repeat("a", 4097) + t.CreateFile("test.txt", "test\r\n"+testString+"\r\nhello\r\nworld\r\n") + tail := t.StartTail("test.txt", Config{Follow: true, Location: nil, MaxLineSize: 4097}) + go t.VerifyTailOutput(tail, []string{"test", testString, "hello", "world"}) + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + t.RemoveFile("test.txt") + tail.Stop() + Cleanup() +} + func TestLocationFull(_t *testing.T) { t := NewTailTest("location-full", _t) t.CreateFile("test.txt", "hello\nworld\n")