Skip to content

Commit b390f2b

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

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-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 true, 0, io.SeekEnd
50+
} else {
51+
return false, 0, 0
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: 26 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,31 @@ 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+
225+
tail := RunFseventFileTailerWithSeek(logfile, true, log, 12, io.SeekStart)
226+
defer tail.Close()
227+
228+
// We don't expect errors. However, start a go-routine listening on
229+
// the tailer's errorChannel in case something goes wrong.
230+
go func() {
231+
for err := range tail.Errors() {
232+
t.Errorf("Tailer failed: %v", err.Error()) // Cannot call t.Fatalf() in other goroutine.
233+
}
234+
}()
235+
236+
logFileWriter.writeLine(t, log, "test line 2")
237+
expect(t, log, tail.Lines(), "test line 2", 1*time.Second)
238+
}
239+
214240
func TestShutdownDuringSyscall(t *testing.T) {
215241
runTestShutdown(t, "shutdown while the watcher is hanging in the blocking kevent() or syscall.Read() call")
216242
}

0 commit comments

Comments
 (0)