Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions tail.go
Original file line number Diff line number Diff line change
Expand Up @@ -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...)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may be best to make readLine return a slice of lines by splitting read lines per Config.MaxLineSize, as otherwise there is no limit on how much buf can grow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@masahide sorry - it looks like i overlooked something. two months ago, i noted above that the buf variable can grow unbounded, as the for loop doesn't split it per the MaxLineSize setting and return a slice of lines. did you make any code changes for this? i don't see it in the current diff.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try View full changes.

    if !isPrefix || tail.MaxLineSize > 0 {
        return line, err
    }

for loop is not performed if MaxLineSize is greater than or equal to zero.
Does this have a problem?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that "the diff display" is wrong by "git push -f."

}
return buf, err
}

func (tail *Tail) tailFileSync() {
Expand Down Expand Up @@ -199,7 +208,7 @@ func (tail *Tail) tailFileSync() {
}
}

tail.reader = bufio.NewReader(tail.file)
tail.reader = tail.newReader()

// Read line by line.
for {
Expand Down Expand Up @@ -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)
Expand All @@ -293,14 +302,22 @@ 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
}
panic("unreachable")
}

func (tail *Tail) newReader() *bufio.Reader {
if tail.MaxLineSize > 0 {
return bufio.NewReaderSize(tail.file, tail.MaxLineSize+2)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it contains the buffer newlines code, add 2 bytes of CR/LF.

} 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 {
Expand Down
30 changes: 30 additions & 0 deletions tail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
_ "fmt"
"io/ioutil"
"os"
"strings"
"testing"
"time"
)
Expand Down Expand Up @@ -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")
Expand Down