From 2c1f619db59b14e9a8ad5ddc60c262e551b528a7 Mon Sep 17 00:00:00 2001 From: nxadm Date: Sun, 7 Feb 2021 17:01:30 +0100 Subject: [PATCH] Doc cleanup and extension (#22) * update and complete documentation * small linter fixes --- CHANGES.md | 4 ++ README.md | 39 ++++++++++------ cmd/gotail/gotail.go | 5 ++- examples/01-tailAndPrint/main.go | 1 + examples/02-closeAndReopen/main.go | 6 +-- tail.go | 72 ++++++++++++++++++------------ tail_posix.go | 6 +++ tail_test.go | 55 +++++++++++++++++++++++ tail_windows.go | 9 +++- util/util.go | 1 + watch/filechanges.go | 1 + watch/inotify.go | 1 + watch/inotify_tracker.go | 1 + watch/polling.go | 1 + watch/watch.go | 1 + winfile/winfile.go | 1 + 16 files changed, 154 insertions(+), 50 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e188794..33a501e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +# Version v1.4.7 +* Documentation update and cleanup release. +* Small linter cleanups. + # Version v1.4.6 * Document the usage of Cleanup when re-reading a file (thanks to @lesovsky) for issue #18. diff --git a/README.md b/README.md index 53767ed..f47939c 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,44 @@ ![ci](https://github.com/nxadm/tail/workflows/ci/badge.svg)[![Go Reference](https://pkg.go.dev/badge/github.com/nxadm/tail.svg)](https://pkg.go.dev/github.com/nxadm/tail) -This project is an active, drop-in replacement for the -[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at -[hpcloud](https://github.com/hpcloud/tail). This fork adds support for go -modules, updates the dependencies, adds features and fixes bugs. Go 1.9 is the -oldest compiler release supported. +# tail functionality in Go -# Go package for tail-ing files +nxadm/tail provides a Go library that emulates the features of the BSD `tail` +program. The library comes with full support for truncation/move detection as +it is designed to work with log rotation tools. The library works on all +operating systems supported by Go, including POSIX systems like Linux and +*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported. -A Go package striving to emulate the features of the BSD `tail` program. +A simple example: ```Go -t, err := tail.TailFile("/var/log/nginx.log", tail.Config{Follow: true}) +// Create a tail +t, err := tail.TailFile( + "/var/log/nginx.log", tail.Config{Follow: true, ReOpen: true}) if err != nil { panic(err) } +// Print the text of each received line for line := range t.Lines { fmt.Println(line.Text) } ``` -See [API documentation](http://godoc.org/github.com/nxadm/tail). - -## Log rotation - -Tail comes with full support for truncation/move detection as it is -designed to work with log rotation tools. +See [API documentation](https://pkg.go.dev/github.com/nxadm/tail). ## Installing go get github.com/nxadm/tail/... + +## History + +This project is an active, drop-in replacement for the +[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at +[hpcloud](https://github.com/hpcloud/tail). Next to +[addressing open issues/PRs of the original project](https://github.com/nxadm/tail/issues/6), +nxadm/tail continues the development by keeping up to date with the Go toolchain +(e.g. go modules) and dependencies, completing the documentation, adding features +and fixing bugs. + +## Examples +Examples, e.g. used to debug an issue, are kept in the [examples directory](/examples). \ No newline at end of file diff --git a/cmd/gotail/gotail.go b/cmd/gotail/gotail.go index 0ad68c6..a7fa248 100644 --- a/cmd/gotail/gotail.go +++ b/cmd/gotail/gotail.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. @@ -36,7 +37,7 @@ func main() { } if n != 0 { - config.Location = &tail.SeekInfo{-n, io.SeekEnd} + config.Location = &tail.SeekInfo{Offset: -n, Whence: io.SeekEnd} } done := make(chan bool) @@ -44,7 +45,7 @@ func main() { go tailFile(filename, config, done) } - for _, _ = range flag.Args() { + for range flag.Args() { <-done } } diff --git a/examples/01-tailAndPrint/main.go b/examples/01-tailAndPrint/main.go index 36e611d..c4d07e9 100644 --- a/examples/01-tailAndPrint/main.go +++ b/examples/01-tailAndPrint/main.go @@ -6,6 +6,7 @@ package main import ( "fmt" + "github.com/nxadm/tail" ) diff --git a/examples/02-closeAndReopen/main.go b/examples/02-closeAndReopen/main.go index aceaef6..ed49bcd 100644 --- a/examples/02-closeAndReopen/main.go +++ b/examples/02-closeAndReopen/main.go @@ -5,8 +5,9 @@ package main import ( "fmt" - "github.com/nxadm/tail" "time" + + "github.com/nxadm/tail" ) var logFile = "/var/log/syslog" @@ -35,7 +36,6 @@ func main() { // As the documentation states: "This function is meant to be invoked from a process's exit handler". //t.Cleanup() - // Reopen the file and print it t, err = tail.TailFile(logFile, tail.Config{Follow: true}) if err != nil { @@ -46,6 +46,4 @@ func main() { for line := range t.Lines { fmt.Println(line.Text) } - - } diff --git a/tail.go b/tail.go index 7fbba8d..37ea441 100644 --- a/tail.go +++ b/tail.go @@ -1,6 +1,12 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. +//nxadm/tail provides a Go library that emulates the features of the BSD `tail` +//program. The library comes with full support for truncation/move detection as +//it is designed to work with log rotation tools. The library works on all +//operating systems supported by Go, including POSIX systems like Linux and +//*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported. package tail import ( @@ -22,26 +28,31 @@ import ( ) var ( + // ErrStop is returned when the tail of a file has been marked to be stopped. ErrStop = errors.New("tail should now stop") ) type Line struct { - Text string - Num int - SeekInfo SeekInfo - Time time.Time - Err error // Error from tail + Text string // The contents of the file + Num int // The line number + SeekInfo SeekInfo // SeekInfo + Time time.Time // Present time + Err error // Error from tail } -// NewLine returns a Line with present time. +// Deprecated: this function is no longer used internally and it has little of no +// use in the API. As such, it will be removed from the API in a future major +// release. +// +// NewLine returns a * pointer to a Line struct. func NewLine(text string, lineNum int) *Line { return &Line{text, lineNum, SeekInfo{}, time.Now(), nil} } -// SeekInfo represents arguments to `io.Seek` +// SeekInfo represents arguments to io.Seek. See: https://golang.org/pkg/io/#SectionReader.Seek type SeekInfo struct { Offset int64 - Whence int // io.Seek* + Whence int } type logger interface { @@ -59,26 +70,28 @@ type logger interface { // Config is used to specify how a file must be tailed. type Config struct { // File-specifc - Location *SeekInfo // Seek to this location before tailing - 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 - Pipe bool // Is a named pipe (mkfifo) - RateLimiter *ratelimiter.LeakyBucket + Location *SeekInfo // Tail from this location. If nil, start at the beginning of the file + 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 the default inotify + Pipe bool // The file is a named pipe (mkfifo) // Generic IO Follow bool // Continue looking for new lines (tail -f) MaxLineSize int // If non-zero, split longer lines into multiple lines - // Logger, when nil, is set to tail.DefaultLogger - // To disable logging: set field to tail.DiscardingLogger + // Optionally, use a ratelimiter (e.g. created by the ratelimiter/NewLeakyBucket function) + RateLimiter *ratelimiter.LeakyBucket + + // Optionally use a Logger. When nil, the Logger is set to tail.DefaultLogger. + // To disable logging, set it to tail.DiscardingLogger Logger logger } type Tail struct { - Filename string - Lines chan *Line - Config + Filename string // The filename + Lines chan *Line // A consumable channel of *Line + Config // Tail.Configuration file *os.File reader *bufio.Reader @@ -93,16 +106,17 @@ type Tail struct { } var ( - // DefaultLogger is used when Config.Logger == nil + // DefaultLogger logs to os.Stderr and it is used when Config.Logger == nil DefaultLogger = log.New(os.Stderr, "", log.LstdFlags) // DiscardingLogger can be used to disable logging output DiscardingLogger = log.New(ioutil.Discard, "", 0) ) -// TailFile begins tailing the file. Output stream is made available -// via the `Tail.Lines` channel. To handle errors during tailing, -// invoke the `Wait` or `Err` method after finishing reading from the -// `Lines` channel. +// TailFile begins tailing the file. And returns a pointer to a Tail struct +// and an error. An output stream is made available via the Tail.Lines +// channel (e.g. to be looped and printed). To handle errors during tailing, +// after finishing reading from the Lines channel, invoke the `Wait` or `Err` +// method on the returned *Tail. func TailFile(filename string, config Config) (*Tail, error) { if config.ReOpen && !config.Follow { util.Fatal("cannot set ReOpen without Follow.") @@ -138,10 +152,9 @@ func TailFile(filename string, config Config) (*Tail, error) { return t, nil } -// Tell returns the file's current position, like stdio's ftell(). -// But this value is not very accurate. -// One line from the chan(tail.Lines) may have been read, -// so it may have lost one line. +// Tell returns the file's current position, like stdio's ftell() and an error. +// Beware that this value may not be completely accurate because one line from +// the chan(tail.Lines) may have been read already. func (tail *Tail) Tell() (offset int64, err error) { if tail.file == nil { return @@ -167,7 +180,8 @@ func (tail *Tail) Stop() error { return tail.Wait() } -// StopAtEOF stops tailing as soon as the end of the file is reached. +// StopAtEOF stops tailing as soon as the end of the file is reached. The function +// returns an error, func (tail *Tail) StopAtEOF() error { tail.Kill(errStopAtEOF) return tail.Wait() diff --git a/tail_posix.go b/tail_posix.go index 1b94520..23e071d 100644 --- a/tail_posix.go +++ b/tail_posix.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // +build !windows package tail @@ -6,6 +7,11 @@ import ( "os" ) +// Deprecated: this function is only useful internally and, as such, +// it will be removed from the API in a future major release. +// +// OpenFile proxies a os.Open call for a file so it can be correctly tailed +// on POSIX and non-POSIX OSes like MS Windows. func OpenFile(name string) (file *os.File, err error) { return os.Open(name) } diff --git a/tail_test.go b/tail_test.go index 06c25e6..62a4d78 100644 --- a/tail_test.go +++ b/tail_test.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. @@ -7,6 +8,7 @@ package tail import ( + "fmt" _ "fmt" "io" "io/ioutil" @@ -27,6 +29,59 @@ func init() { } } +func TestTailFile(t *testing.T) { + t.SkipNow() +} + +func ExampleTailFile_1() { + // Keep tracking a file even when recreated. + // Write a test file (ignoring error checking) + + // /var/log/messages is typically continuously written and rotated daily. + testFileName := "/var/log/messages" + // ReOpen when truncated, wait for new input when EOL is reached + tailedFile, err := TailFile(testFileName, Config{ReOpen: true, Follow: true}) + if err != nil { + panic(err) + } + + for line := range tailedFile.Lines { + fmt.Println(line.Text) + } + // Prints all the lines in the logfile and keeps printing new input +} + +func ExampleTailFile_2() { + // Tail a file until the EOF and exit. + + // Write a test file (ignoring error checking) + testFileName := ".test/TailFail.txt" + file, err := os.Create(testFileName) + if err != nil { + panic(err) + } + _, err = file.WriteString("a\nb\nc\n") + if err != nil { + panic(err) + } + file.Close() + defer os.Remove(testFileName) + + // Just tail a file using the defaults. + tailedFile, err := TailFile(testFileName, Config{}) + if err != nil { + panic(err) + } + + for line := range tailedFile.Lines { + fmt.Println(line.Text) + } + // Output: + //a + //b + //c +} + func TestMain(m *testing.M) { // Use a smaller poll duration for faster test runs. Keep it below // 100ms (which value is used as common delays for tests) diff --git a/tail_windows.go b/tail_windows.go index 4aaceea..da0d2f3 100644 --- a/tail_windows.go +++ b/tail_windows.go @@ -1,12 +1,19 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // +build windows package tail import ( - "github.com/nxadm/tail/winfile" "os" + + "github.com/nxadm/tail/winfile" ) +// Deprecated: this function is only useful internally and, as such, +// it will be removed from the API in a future major release. +// +// OpenFile proxies a os.Open call for a file so it can be correctly tailed +// on POSIX and non-POSIX OSes like MS Windows. func OpenFile(name string) (file *os.File, err error) { return winfile.OpenFile(name, os.O_RDONLY, 0) } diff --git a/util/util.go b/util/util.go index 2ba0ed7..b64caa2 100644 --- a/util/util.go +++ b/util/util.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. diff --git a/watch/filechanges.go b/watch/filechanges.go index f80aead..5b65f42 100644 --- a/watch/filechanges.go +++ b/watch/filechanges.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail package watch type FileChanges struct { diff --git a/watch/inotify.go b/watch/inotify.go index 4399218..cbd11ad 100644 --- a/watch/inotify.go +++ b/watch/inotify.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. diff --git a/watch/inotify_tracker.go b/watch/inotify_tracker.go index a94bcd4..cb9572a 100644 --- a/watch/inotify_tracker.go +++ b/watch/inotify_tracker.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. diff --git a/watch/polling.go b/watch/polling.go index fb17069..74e10aa 100644 --- a/watch/polling.go +++ b/watch/polling.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. diff --git a/watch/watch.go b/watch/watch.go index 2e1783e..2b51128 100644 --- a/watch/watch.go +++ b/watch/watch.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // Copyright (c) 2015 HPE Software Inc. All rights reserved. // Copyright (c) 2013 ActiveState Software Inc. All rights reserved. diff --git a/winfile/winfile.go b/winfile/winfile.go index aa7e7bc..4562ac7 100644 --- a/winfile/winfile.go +++ b/winfile/winfile.go @@ -1,3 +1,4 @@ +// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail // +build windows package winfile