Skip to content

Commit 2c1f619

Browse files
authored
Doc cleanup and extension (#22)
* update and complete documentation * small linter fixes
1 parent 7d325f5 commit 2c1f619

File tree

16 files changed

+154
-50
lines changed

16 files changed

+154
-50
lines changed

CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Version v1.4.7
2+
* Documentation update and cleanup release.
3+
* Small linter cleanups.
4+
15
# Version v1.4.6
26

37
* Document the usage of Cleanup when re-reading a file (thanks to @lesovsky) for issue #18.

README.md

+25-14
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
11
![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)
22

3-
This project is an active, drop-in replacement for the
4-
[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at
5-
[hpcloud](https://github.com/hpcloud/tail). This fork adds support for go
6-
modules, updates the dependencies, adds features and fixes bugs. Go 1.9 is the
7-
oldest compiler release supported.
3+
# tail functionality in Go
84

9-
# Go package for tail-ing files
5+
nxadm/tail provides a Go library that emulates the features of the BSD `tail`
6+
program. The library comes with full support for truncation/move detection as
7+
it is designed to work with log rotation tools. The library works on all
8+
operating systems supported by Go, including POSIX systems like Linux and
9+
*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
1010

11-
A Go package striving to emulate the features of the BSD `tail` program.
11+
A simple example:
1212

1313
```Go
14-
t, err := tail.TailFile("/var/log/nginx.log", tail.Config{Follow: true})
14+
// Create a tail
15+
t, err := tail.TailFile(
16+
"/var/log/nginx.log", tail.Config{Follow: true, ReOpen: true})
1517
if err != nil {
1618
panic(err)
1719
}
1820

21+
// Print the text of each received line
1922
for line := range t.Lines {
2023
fmt.Println(line.Text)
2124
}
2225
```
2326

24-
See [API documentation](http://godoc.org/github.com/nxadm/tail).
25-
26-
## Log rotation
27-
28-
Tail comes with full support for truncation/move detection as it is
29-
designed to work with log rotation tools.
27+
See [API documentation](https://pkg.go.dev/github.com/nxadm/tail).
3028

3129
## Installing
3230

3331
go get github.com/nxadm/tail/...
32+
33+
## History
34+
35+
This project is an active, drop-in replacement for the
36+
[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at
37+
[hpcloud](https://github.com/hpcloud/tail). Next to
38+
[addressing open issues/PRs of the original project](https://github.com/nxadm/tail/issues/6),
39+
nxadm/tail continues the development by keeping up to date with the Go toolchain
40+
(e.g. go modules) and dependencies, completing the documentation, adding features
41+
and fixing bugs.
42+
43+
## Examples
44+
Examples, e.g. used to debug an issue, are kept in the [examples directory](/examples).

cmd/gotail/gotail.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
23
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
34

@@ -36,15 +37,15 @@ func main() {
3637
}
3738

3839
if n != 0 {
39-
config.Location = &tail.SeekInfo{-n, io.SeekEnd}
40+
config.Location = &tail.SeekInfo{Offset: -n, Whence: io.SeekEnd}
4041
}
4142

4243
done := make(chan bool)
4344
for _, filename := range flag.Args() {
4445
go tailFile(filename, config, done)
4546
}
4647

47-
for _, _ = range flag.Args() {
48+
for range flag.Args() {
4849
<-done
4950
}
5051
}

examples/01-tailAndPrint/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package main
66

77
import (
88
"fmt"
9+
910
"github.com/nxadm/tail"
1011
)
1112

examples/02-closeAndReopen/main.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ package main
55

66
import (
77
"fmt"
8-
"github.com/nxadm/tail"
98
"time"
9+
10+
"github.com/nxadm/tail"
1011
)
1112

1213
var logFile = "/var/log/syslog"
@@ -35,7 +36,6 @@ func main() {
3536
// As the documentation states: "This function is meant to be invoked from a process's exit handler".
3637
//t.Cleanup()
3738

38-
3939
// Reopen the file and print it
4040
t, err = tail.TailFile(logFile, tail.Config{Follow: true})
4141
if err != nil {
@@ -46,6 +46,4 @@ func main() {
4646
for line := range t.Lines {
4747
fmt.Println(line.Text)
4848
}
49-
50-
5149
}

tail.go

+43-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
23
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
34

5+
//nxadm/tail provides a Go library that emulates the features of the BSD `tail`
6+
//program. The library comes with full support for truncation/move detection as
7+
//it is designed to work with log rotation tools. The library works on all
8+
//operating systems supported by Go, including POSIX systems like Linux and
9+
//*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
410
package tail
511

612
import (
@@ -22,26 +28,31 @@ import (
2228
)
2329

2430
var (
31+
// ErrStop is returned when the tail of a file has been marked to be stopped.
2532
ErrStop = errors.New("tail should now stop")
2633
)
2734

2835
type Line struct {
29-
Text string
30-
Num int
31-
SeekInfo SeekInfo
32-
Time time.Time
33-
Err error // Error from tail
36+
Text string // The contents of the file
37+
Num int // The line number
38+
SeekInfo SeekInfo // SeekInfo
39+
Time time.Time // Present time
40+
Err error // Error from tail
3441
}
3542

36-
// NewLine returns a Line with present time.
43+
// Deprecated: this function is no longer used internally and it has little of no
44+
// use in the API. As such, it will be removed from the API in a future major
45+
// release.
46+
//
47+
// NewLine returns a * pointer to a Line struct.
3748
func NewLine(text string, lineNum int) *Line {
3849
return &Line{text, lineNum, SeekInfo{}, time.Now(), nil}
3950
}
4051

41-
// SeekInfo represents arguments to `io.Seek`
52+
// SeekInfo represents arguments to io.Seek. See: https://golang.org/pkg/io/#SectionReader.Seek
4253
type SeekInfo struct {
4354
Offset int64
44-
Whence int // io.Seek*
55+
Whence int
4556
}
4657

4758
type logger interface {
@@ -59,26 +70,28 @@ type logger interface {
5970
// Config is used to specify how a file must be tailed.
6071
type Config struct {
6172
// File-specifc
62-
Location *SeekInfo // Seek to this location before tailing
63-
ReOpen bool // Reopen recreated files (tail -F)
64-
MustExist bool // Fail early if the file does not exist
65-
Poll bool // Poll for file changes instead of using inotify
66-
Pipe bool // Is a named pipe (mkfifo)
67-
RateLimiter *ratelimiter.LeakyBucket
73+
Location *SeekInfo // Tail from this location. If nil, start at the beginning of the file
74+
ReOpen bool // Reopen recreated files (tail -F)
75+
MustExist bool // Fail early if the file does not exist
76+
Poll bool // Poll for file changes instead of using the default inotify
77+
Pipe bool // The file is a named pipe (mkfifo)
6878

6979
// Generic IO
7080
Follow bool // Continue looking for new lines (tail -f)
7181
MaxLineSize int // If non-zero, split longer lines into multiple lines
7282

73-
// Logger, when nil, is set to tail.DefaultLogger
74-
// To disable logging: set field to tail.DiscardingLogger
83+
// Optionally, use a ratelimiter (e.g. created by the ratelimiter/NewLeakyBucket function)
84+
RateLimiter *ratelimiter.LeakyBucket
85+
86+
// Optionally use a Logger. When nil, the Logger is set to tail.DefaultLogger.
87+
// To disable logging, set it to tail.DiscardingLogger
7588
Logger logger
7689
}
7790

7891
type Tail struct {
79-
Filename string
80-
Lines chan *Line
81-
Config
92+
Filename string // The filename
93+
Lines chan *Line // A consumable channel of *Line
94+
Config // Tail.Configuration
8295

8396
file *os.File
8497
reader *bufio.Reader
@@ -93,16 +106,17 @@ type Tail struct {
93106
}
94107

95108
var (
96-
// DefaultLogger is used when Config.Logger == nil
109+
// DefaultLogger logs to os.Stderr and it is used when Config.Logger == nil
97110
DefaultLogger = log.New(os.Stderr, "", log.LstdFlags)
98111
// DiscardingLogger can be used to disable logging output
99112
DiscardingLogger = log.New(ioutil.Discard, "", 0)
100113
)
101114

102-
// TailFile begins tailing the file. Output stream is made available
103-
// via the `Tail.Lines` channel. To handle errors during tailing,
104-
// invoke the `Wait` or `Err` method after finishing reading from the
105-
// `Lines` channel.
115+
// TailFile begins tailing the file. And returns a pointer to a Tail struct
116+
// and an error. An output stream is made available via the Tail.Lines
117+
// channel (e.g. to be looped and printed). To handle errors during tailing,
118+
// after finishing reading from the Lines channel, invoke the `Wait` or `Err`
119+
// method on the returned *Tail.
106120
func TailFile(filename string, config Config) (*Tail, error) {
107121
if config.ReOpen && !config.Follow {
108122
util.Fatal("cannot set ReOpen without Follow.")
@@ -138,10 +152,9 @@ func TailFile(filename string, config Config) (*Tail, error) {
138152
return t, nil
139153
}
140154

141-
// Tell returns the file's current position, like stdio's ftell().
142-
// But this value is not very accurate.
143-
// One line from the chan(tail.Lines) may have been read,
144-
// so it may have lost one line.
155+
// Tell returns the file's current position, like stdio's ftell() and an error.
156+
// Beware that this value may not be completely accurate because one line from
157+
// the chan(tail.Lines) may have been read already.
145158
func (tail *Tail) Tell() (offset int64, err error) {
146159
if tail.file == nil {
147160
return
@@ -167,7 +180,8 @@ func (tail *Tail) Stop() error {
167180
return tail.Wait()
168181
}
169182

170-
// StopAtEOF stops tailing as soon as the end of the file is reached.
183+
// StopAtEOF stops tailing as soon as the end of the file is reached. The function
184+
// returns an error,
171185
func (tail *Tail) StopAtEOF() error {
172186
tail.Kill(errStopAtEOF)
173187
return tail.Wait()

tail_posix.go

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// +build !windows
23

34
package tail
@@ -6,6 +7,11 @@ import (
67
"os"
78
)
89

10+
// Deprecated: this function is only useful internally and, as such,
11+
// it will be removed from the API in a future major release.
12+
//
13+
// OpenFile proxies a os.Open call for a file so it can be correctly tailed
14+
// on POSIX and non-POSIX OSes like MS Windows.
915
func OpenFile(name string) (file *os.File, err error) {
1016
return os.Open(name)
1117
}

tail_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
23
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
34

@@ -7,6 +8,7 @@
78
package tail
89

910
import (
11+
"fmt"
1012
_ "fmt"
1113
"io"
1214
"io/ioutil"
@@ -27,6 +29,59 @@ func init() {
2729
}
2830
}
2931

32+
func TestTailFile(t *testing.T) {
33+
t.SkipNow()
34+
}
35+
36+
func ExampleTailFile_1() {
37+
// Keep tracking a file even when recreated.
38+
// Write a test file (ignoring error checking)
39+
40+
// /var/log/messages is typically continuously written and rotated daily.
41+
testFileName := "/var/log/messages"
42+
// ReOpen when truncated, wait for new input when EOL is reached
43+
tailedFile, err := TailFile(testFileName, Config{ReOpen: true, Follow: true})
44+
if err != nil {
45+
panic(err)
46+
}
47+
48+
for line := range tailedFile.Lines {
49+
fmt.Println(line.Text)
50+
}
51+
// Prints all the lines in the logfile and keeps printing new input
52+
}
53+
54+
func ExampleTailFile_2() {
55+
// Tail a file until the EOF and exit.
56+
57+
// Write a test file (ignoring error checking)
58+
testFileName := ".test/TailFail.txt"
59+
file, err := os.Create(testFileName)
60+
if err != nil {
61+
panic(err)
62+
}
63+
_, err = file.WriteString("a\nb\nc\n")
64+
if err != nil {
65+
panic(err)
66+
}
67+
file.Close()
68+
defer os.Remove(testFileName)
69+
70+
// Just tail a file using the defaults.
71+
tailedFile, err := TailFile(testFileName, Config{})
72+
if err != nil {
73+
panic(err)
74+
}
75+
76+
for line := range tailedFile.Lines {
77+
fmt.Println(line.Text)
78+
}
79+
// Output:
80+
//a
81+
//b
82+
//c
83+
}
84+
3085
func TestMain(m *testing.M) {
3186
// Use a smaller poll duration for faster test runs. Keep it below
3287
// 100ms (which value is used as common delays for tests)

tail_windows.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// +build windows
23

34
package tail
45

56
import (
6-
"github.com/nxadm/tail/winfile"
77
"os"
8+
9+
"github.com/nxadm/tail/winfile"
810
)
911

12+
// Deprecated: this function is only useful internally and, as such,
13+
// it will be removed from the API in a future major release.
14+
//
15+
// OpenFile proxies a os.Open call for a file so it can be correctly tailed
16+
// on POSIX and non-POSIX OSes like MS Windows.
1017
func OpenFile(name string) (file *os.File, err error) {
1118
return winfile.OpenFile(name, os.O_RDONLY, 0)
1219
}

util/util.go

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
23
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
34

watch/filechanges.go

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
package watch
23

34
type FileChanges struct {

watch/inotify.go

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
23
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
34

watch/inotify_tracker.go

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
12
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
23
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
34

0 commit comments

Comments
 (0)