diff --git a/tail.go b/tail.go index c4ecd54..07f7aed 100644 --- a/tail.go +++ b/tail.go @@ -17,13 +17,14 @@ type Line struct { Time time.Time } +// Tail configuration type Config struct { - Location int // -n - Follow bool // -f - ReOpen bool // -F - MustExist bool // if false, wait for the file to exist before beginning to tail. - Poll bool // if true, do not use inotify but use polling - MaxLineSize int // if > 0, limit the line size (rest of the line would be returned as next lines) + Location int // Tail from last N lines (tail -n) + Follow bool // Continue looking for new lines (tail -f) + ReOpen bool // Reopen recreated files (tail -F) + MustExist bool // Fail early if the file does not exist + Poll bool // Poll for file changes instead of using inotify + MaxLineSize int // If non-zero, split longer lines into multiple lines } type Tail struct { @@ -38,10 +39,10 @@ type Tail struct { tomb.Tomb // provides: Done, Kill, Dying } -// TailFile channels the lines of a logfile along with timestamp. If -// end is true, channel only newly added lines. If retry is true, tail -// the file name (not descriptor) and retry on file open/read errors. -// func TailFile(filename string, maxlinesize int, end bool, retry bool, useinotify bool) (*Tail, error) { +// TailFile begins tailing the file with the specified +// configuration. Output stream is made available via the `Tail.Lines` +// channel. To handle errors during tailing, invoke the `Wait` method +// after finishing reading from the `Lines` channel. func TailFile(filename string, config Config) (*Tail, error) { if !(config.Location == 0 || config.Location == -1) { panic("only 0/-1 values are supported for Location.") diff --git a/watch.go b/watch.go index fbb7568..fba7441 100644 --- a/watch.go +++ b/watch.go @@ -1,6 +1,5 @@ // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. -// TODO: avoid creating two instances of the fsnotify.Watcher struct package tail import ( @@ -10,12 +9,18 @@ import ( "time" ) +// FileWatcher monitors file-level events. type FileWatcher interface { + // BlockUntilExists blocks until the missing file comes into + // existence. If the file already exists, block until it is recreated. BlockUntilExists() error + + // ChangeEvents returns a channel of events corresponding to the + // times the file is ready to be read. ChangeEvents() chan bool } -// FileWatcher monitors file-level events +// InotifyFileWatcher uses inotify to monitor file changes. type InotifyFileWatcher struct { Filename string } @@ -25,8 +30,6 @@ func NewInotifyFileWatcher(filename string) *InotifyFileWatcher { return fw } -// BlockUntilExists blocks until the file comes into existence. If the -// file already exists, then block until it is created again. func (fw *InotifyFileWatcher) BlockUntilExists() error { w, err := fsnotify.NewWatcher() if err != nil { @@ -47,7 +50,6 @@ func (fw *InotifyFileWatcher) BlockUntilExists() error { return nil } -// ChangeEvents returns a channel that gets updated when the file is ready to be read. func (fw *InotifyFileWatcher) ChangeEvents() chan bool { w, err := fsnotify.NewWatcher() if err != nil { @@ -86,7 +88,7 @@ func (fw *InotifyFileWatcher) ChangeEvents() chan bool { return ch } -// FileWatcher monitors file-level events +// PollingFileWatcher polls the file for changes. type PollingFileWatcher struct { Filename string } @@ -96,14 +98,11 @@ func NewPollingFileWatcher(filename string) *PollingFileWatcher { return fw } -// BlockUntilExists blocks until the file comes into existence. If the -// file already exists, then block until it is created again. func (fw *PollingFileWatcher) BlockUntilExists() error { panic("not implemented") return nil } -// ChangeEvents returns a channel that gets updated when the file is ready to be read. func (fw *PollingFileWatcher) ChangeEvents() chan bool { ch := make(chan bool) stop := make(chan bool) @@ -122,7 +121,8 @@ func (fw *PollingFileWatcher) ChangeEvents() chan bool { fi, err := os.Stat(fw.Filename) if err != nil { if os.IsNotExist(err) { - // below goroutine (every2Seconds) will catch up eventually and stop us. + // below goroutine (every2Seconds) will catch up + // eventually and stop us. continue } panic(err)