Skip to content

Commit d6093c0

Browse files
committed
Tailer: add option to start tailing at specified seek offset
1 parent 691b510 commit d6093c0

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

tailer/fileTailer.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,39 @@ func (f *fileTailer) Errors() chan Error {
4444
return f.errors
4545
}
4646

47+
func getSeekArgs(readall bool) (bool, int64, int) {
48+
if readall {
49+
return false, 0, 0
50+
} else {
51+
return true, 0, io.SeekEnd
52+
}
53+
}
54+
4755
func RunFseventFileTailer(path string, readall bool, failOnMissingFile bool, logger simpleLogger) Tailer {
48-
return runFileTailer(path, readall, failOnMissingFile, logger, NewFseventWatcher)
56+
seek, offset, whence := getSeekArgs(readall)
57+
return runFileTailer(path, failOnMissingFile, logger, seek, offset, whence, NewFseventWatcher)
58+
}
59+
60+
func RunFseventFileTailerWithSeek(path string, failOnMissingFile bool, logger simpleLogger, offset int64, whence int) Tailer {
61+
return runFileTailer(path, failOnMissingFile, logger, true, offset, whence, NewFseventWatcher)
4962
}
5063

5164
func RunPollingFileTailer(path string, readall bool, failOnMissingFile bool, pollIntervall time.Duration, logger simpleLogger) Tailer {
65+
seek, offset, whence := getSeekArgs(readall)
66+
makeWatcher := func(abspath string, _ *File) (Watcher, error) {
67+
return NewPollingWatcher(abspath, pollIntervall)
68+
}
69+
return runFileTailer(path, failOnMissingFile, logger, seek, offset, whence, makeWatcher)
70+
}
71+
72+
func RunPollingFileTailerWithSeek(path string, failOnMissingFile bool, pollIntervall time.Duration, logger simpleLogger, offset int64, whence int) Tailer {
5273
makeWatcher := func(abspath string, _ *File) (Watcher, error) {
5374
return NewPollingWatcher(abspath, pollIntervall)
5475
}
55-
return runFileTailer(path, readall, failOnMissingFile, logger, makeWatcher)
76+
return runFileTailer(path, failOnMissingFile, logger, true, offset, whence, makeWatcher)
5677
}
5778

58-
func runFileTailer(path string, readall bool, failOnMissingFile bool, logger simpleLogger, makeWatcher func(string, *File) (Watcher, error)) Tailer {
79+
func runFileTailer(path string, failOnMissingFile bool, logger simpleLogger, seek bool, seekOffset int64, seekWhence int, makeWatcher func(string, *File) (Watcher, error)) Tailer {
5980
if logger == nil {
6081
logger = &nilLogger{}
6182
}
@@ -71,7 +92,7 @@ func runFileTailer(path string, readall bool, failOnMissingFile bool, logger sim
7192
closed: false,
7293
}
7394

74-
file, abspath, err := openLogfile(path, readall, failOnMissingFile) // file may be nil if failOnMissingFile is false and the file doesn't exist yet.
95+
file, abspath, err := openLogfile(path, failOnMissingFile, seek, seekOffset, seekWhence) // file may be nil if failOnMissingFile is false and the file doesn't exist yet.
7596
if err != nil {
7697
go func(err error) {
7798
writeError(errors, done, err, "failed to initialize file system watcher for %v", path)
@@ -173,7 +194,7 @@ func runFileTailer(path string, readall bool, failOnMissingFile bool, logger sim
173194
}
174195

175196
// may return *File == nil if the file does not exist and failOnMissingFile == false
176-
func openLogfile(path string, readall bool, failOnMissingFile bool) (*File, string, error) {
197+
func openLogfile(path string, failOnMissingFile bool, seek bool, seekOffset int64, seekWhence int) (*File, string, error) {
177198
abspath, err := filepath.Abs(path)
178199
if err != nil {
179200
return nil, "", err
@@ -182,8 +203,8 @@ func openLogfile(path string, readall bool, failOnMissingFile bool) (*File, stri
182203
if err != nil && (failOnMissingFile || !os.IsNotExist(err)) {
183204
return nil, "", err
184205
}
185-
if !readall && file != nil {
186-
_, err = file.Seek(0, io.SeekEnd)
206+
if seek && file != nil {
207+
_, err = file.Seek(seekOffset, seekWhence)
187208
if err != nil {
188209
if file != nil {
189210
file.Close()

tailer/fileTailer_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package tailer
1616

1717
import (
1818
"fmt"
19+
"io"
1920
"io/ioutil"
2021
"os"
2122
"os/user"
@@ -211,6 +212,34 @@ func TestFileMissingOnStartup(t *testing.T) {
211212
expect(t, log, tail.Lines(), "test line 2", 1*time.Second)
212213
}
213214

215+
func TestFileSeek(t *testing.T) {
216+
const logfileName = "grok_exporter_seek_logfile.log"
217+
log := NewTestRunLogger(400)
218+
tmpDir := mkTmpDirOrFail(t)
219+
defer cleanUp(t, tmpDir)
220+
var logfile = fmt.Sprintf("%s%c%s", tmpDir, os.PathSeparator, logfileName)
221+
222+
logFileWriter := newLogFileWriter(t, logfile, closeFileAfterEachLine)
223+
logFileWriter.writeLine(t, log, "test line 1")
224+
logFileWriter.writeLine(t, log, "test line 2")
225+
226+
tail := RunFseventFileTailerWithSeek(logfile, true, log, 12, io.SeekStart)
227+
defer tail.Close()
228+
229+
// We don't expect errors. However, start a go-routine listening on
230+
// the tailer's errorChannel in case something goes wrong.
231+
go func() {
232+
for err := range tail.Errors() {
233+
t.Errorf("Tailer failed: %v", err.Error()) // Cannot call t.Fatalf() in other goroutine.
234+
}
235+
}()
236+
237+
expect(t, log, tail.Lines(), "test line 2", 1*time.Second)
238+
239+
logFileWriter.writeLine(t, log, "test line 3")
240+
expect(t, log, tail.Lines(), "test line 3", 1*time.Second)
241+
}
242+
214243
func TestShutdownDuringSyscall(t *testing.T) {
215244
runTestShutdown(t, "shutdown while the watcher is hanging in the blocking kevent() or syscall.Read() call")
216245
}

0 commit comments

Comments
 (0)