Please take a look. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go File utils/tailer/tailer.go (right): https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode41 utils/tailer/tailer.go:41: // Writer. The reading beginns the specified number of matching lines On 2013/12/10 15:14:25, rog wrote: > s/beginns/begins/ Done. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode43 utils/tailer/tailer.go:43: func NewStandardTailer(readSeeker io.ReadSeeker, writer io.Writer, lines int, filter TailerFilterFunc) *Tailer { On 2013/12/10 15:14:25, rog wrote: > Given that this function is going to be the one that everyone calls, I think I'd > name it NewTailer, but do we actually need to expose buffer size and poll > interval publicly except to the tailer tests? Done. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode126 utils/tailer/tailer.go:126: readBuffer := make([]byte, t.bufsize) On 2013/12/10 15:14:25, rog wrote: > This seems rather complex to me - I don't fully trust myself to vet the logic. Used it, even if I have the same troubles following your array logic and the needed debugging. Thankfully the comments helped to follow the idea. And at least it has less lines. ;) Thx. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode198 utils/tailer/tailer.go:198: // Reached beginnig of data. On 2013/12/10 15:14:25, rog wrote: > s/beginnig/beginning/ Not needed anymore due to new function. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode212 utils/tailer/tailer.go:212: buffer, err := t.reader.ReadBytes(delimiter) On 2013/12/10 15:14:25, rog wrote: > ReadBytes can't return ErrBufferFull. > I think you want to use ReadSlice. > Also, if the first call succeeds, we should just return the slice that we got > from ReadSlice - that way in the usual case that the line is shorter than the > bufio buffer we can avoid any allocation. Done. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode226 utils/tailer/tailer.go:226: if len(line) == 0 || line[len(line)-1] == delimiter { On 2013/12/10 15:14:25, rog wrote: > This can't happen. (from the docs: "returns err != nil if and only if the > returned data does not end in delim") Done. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode234 utils/tailer/tailer.go:234: t.readSeeker.Seek(offset, os.SEEK_END) On 2013/12/10 15:14:25, rog wrote: > This is racy. We can't seek from the end because the end might be constantly > changing. I think we need to keep track of where we're reading in the file and > seek back to the absolute offset of the start of the partial line. Done. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode247 utils/tailer/tailer.go:247: return false On 2013/12/10 15:14:25, rog wrote: > Why? Yeah, too much automatic filtering here. The receiver of the data should decide. Removed it. https://codereview.appspot.com/36540043/diff/40001/utils/tailer/tailer.go#newcode252 utils/tailer/tailer.go:252: return t.filter(line) On 2013/12/10 15:14:25, rog wrote: > Consider trimming \r?\n from the end of the line before calling filter? Why? https://codereview.appspot.com/36540043/