in plugins/inputs/logfile/tail/tail.go [329:441]
func (tail *Tail) tailFileSync() {
defer tail.Done()
defer tail.close()
if !tail.MustExist {
// deferred first open.
err := tail.Reopen(true)
if err != nil {
if err != tomb.ErrDying {
tail.Kill(err)
}
return
}
}
// openReader should be invoked before seekTo
tail.openReader()
// Seek to requested location on first open of the file.
if tail.Location != nil {
err := tail.seekTo(*tail.Location)
tail.Logger.Debugf("Seeked %s - %+v\n", tail.Filename, tail.Location)
if err != nil {
tail.Killf("Seek error on %s: %s", tail.Filename, err)
return
}
}
if err := tail.watchChanges(); err != nil {
tail.Killf("Error watching for changes on %s: %s", tail.Filename, err)
return
}
var backupOffset int64
// Read line by line.
for {
// do not set backupOffset in named pipes
if !tail.Pipe {
backupOffset = tail.curOffset
}
line, err := tail.readLine()
// Process `line` even if err is EOF.
if err == nil {
cooloff := !tail.sendLine(line, tail.curOffset)
if cooloff {
// Wait a second before seeking till the end of
// file when rate limit is reached.
msg := "Too much log activity; waiting a second before resuming tailing"
tail.Lines <- &Line{msg, time.Now(), errors.New(msg), tail.curOffset}
select {
case <-time.After(time.Second):
case <-tail.Dying():
return
}
if err := tail.seekEnd(); err != nil {
tail.Kill(err)
return
}
}
} else if err == io.EOF {
if !tail.Follow {
if line != "" {
tail.sendLine(line, tail.curOffset)
}
return
}
if tail.Follow && line != "" {
// this has the potential to never return the last line if
// it's not followed by a newline; seems a fair trade here
err := tail.seekTo(SeekInfo{Offset: backupOffset, Whence: 0})
if err != nil {
tail.Kill(err)
return
}
}
// When EOF is reached, wait for more data to become
// available. Wait strategy is based on the `tail.watcher`
// implementation (inotify or polling).
err := tail.waitForChanges()
if err != nil {
if err == ErrDeletedNotReOpen {
close(tail.FileDeletedCh)
for {
line, errReadLine := tail.readLine()
if errReadLine == nil {
tail.sendLine(line, tail.curOffset)
} else {
return
}
}
} else if err != ErrStop {
tail.Kill(err)
}
return
}
} else {
// non-EOF error
tail.Killf("Error reading %s: %s", tail.Filename, err)
return
}
select {
case <-tail.Dying():
if tail.Err() == errStopAtEOF {
continue
}
return
default:
}
}
}