tail.Location is now the most customizable

as it is now a tuple; (offset, whence) from os.Seek
This commit is contained in:
Sridhar Ratnakumar 2013-08-09 14:53:37 -07:00
parent 8d9c6e4ce1
commit faf14146e7
2 changed files with 24 additions and 23 deletions

View File

@ -9,9 +9,10 @@ import (
"os" "os"
) )
func args2config() tail.Config { func args2config() (tail.Config, int64) {
config := tail.Config{Follow: true} config := tail.Config{Follow: true}
flag.Int64Var(&config.Location, "n", 0, "tail from the last Nth location") n := int64(0)
flag.Int64Var(&n, "n", 0, "tail from the last Nth location")
flag.BoolVar(&config.Follow, "f", false, "wait for additional data to be appended to the file") flag.BoolVar(&config.Follow, "f", false, "wait for additional data to be appended to the file")
flag.BoolVar(&config.ReOpen, "F", false, "follow, and track file rename/rotation") flag.BoolVar(&config.ReOpen, "F", false, "follow, and track file rename/rotation")
flag.BoolVar(&config.Poll, "p", false, "use polling, instead of inotify") flag.BoolVar(&config.Poll, "p", false, "use polling, instead of inotify")
@ -19,16 +20,20 @@ func args2config() tail.Config {
if config.ReOpen { if config.ReOpen {
config.Follow = true config.Follow = true
} }
return config return config, n
} }
func main() { func main() {
config := args2config() config, n := args2config()
if flag.NFlag() < 1 { if flag.NFlag() < 1 {
fmt.Println("need one or more files as arguments") fmt.Println("need one or more files as arguments")
os.Exit(1) os.Exit(1)
} }
if n != 0 {
config.Location = &tail.SeekInfo{-n, os.SEEK_END}
}
done := make(chan bool) done := make(chan bool)
for _, filename := range flag.Args() { for _, filename := range flag.Args() {
go tailFile(filename, config, done) go tailFile(filename, config, done)

34
tail.go
View File

@ -24,17 +24,20 @@ type Line struct {
// log line itself. // log line itself.
} }
type SeekInfo struct {
Offset int64
Whence int // os.SEEK_*
}
// Config is used to specify how a file must be tailed. // Config is used to specify how a file must be tailed.
type Config struct { type Config struct {
Location int64 // For positive location, tail after first N Location *SeekInfo // Seek before tailing
// lines; for negative, tail from last N lines; Follow bool // Continue looking for new lines (tail -f)
// for zero, tail from end. If -1, do not seek. ReOpen bool // Reopen recreated files (tail -F)
Follow bool // Continue looking for new lines (tail -f) MustExist bool // Fail early if the file does not exist
ReOpen bool // Reopen recreated files (tail -F) Poll bool // Poll for file changes instead of using inotify
MustExist bool // Fail early if the file does not exist MaxLineSize int // If non-zero, split longer lines into multiple lines
Poll bool // Poll for file changes instead of using inotify LimitRate int64 // If non-zero, limit the rate of read log lines
MaxLineSize int // If non-zero, split longer lines into multiple lines
LimitRate int64 // If non-zero, limit the rate of read log lines
// by this much per second. // by this much per second.
} }
@ -141,16 +144,9 @@ func (tail *Tail) tailFileSync() {
} }
// Seek to requested location on first open of the file. // Seek to requested location on first open of the file.
if tail.Location != -1 { if tail.Location != nil {
var err error _, err := tail.file.Seek(tail.Location.Offset, tail.Location.Whence)
switch { // log.Printf("Seeked %s - %+v\n", tail.Filename, tail.Location)
case tail.Location <= 0:
// Seek relative to file end
_, err = tail.file.Seek(tail.Location, os.SEEK_END)
default:
// Seek from file beginning
_, err = tail.file.Seek(tail.Location, os.SEEK_SET)
}
if err != nil { if err != nil {
tail.Killf("Seek error on %s: %s", tail.Filename, err) tail.Killf("Seek error on %s: %s", tail.Filename, err)
return return