Skip to content

Commit

Permalink
Doc cleanup and extension (#22)
Browse files Browse the repository at this point in the history
* update and complete documentation
* small linter fixes
  • Loading branch information
nxadm authored Feb 7, 2021
1 parent 7d325f5 commit 2c1f619
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 50 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
39 changes: 25 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -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).
5 changes: 3 additions & 2 deletions cmd/gotail/gotail.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -36,15 +37,15 @@ 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)
for _, filename := range flag.Args() {
go tailFile(filename, config, done)
}

for _, _ = range flag.Args() {
for range flag.Args() {
<-done
}
}
Expand Down
1 change: 1 addition & 0 deletions examples/01-tailAndPrint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"fmt"

"github.com/nxadm/tail"
)

Expand Down
6 changes: 2 additions & 4 deletions examples/02-closeAndReopen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ package main

import (
"fmt"
"github.com/nxadm/tail"
"time"

"github.com/nxadm/tail"
)

var logFile = "/var/log/syslog"
Expand Down Expand Up @@ -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 {
Expand All @@ -46,6 +46,4 @@ func main() {
for line := range t.Lines {
fmt.Println(line.Text)
}


}
72 changes: 43 additions & 29 deletions tail.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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.")
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down
6 changes: 6 additions & 0 deletions tail_posix.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// +build !windows

package tail
Expand All @@ -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)
}
55 changes: 55 additions & 0 deletions tail_test.go
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -7,6 +8,7 @@
package tail

import (
"fmt"
_ "fmt"
"io"
"io/ioutil"
Expand All @@ -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)
Expand Down
9 changes: 8 additions & 1 deletion tail_windows.go
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions util/util.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
1 change: 1 addition & 0 deletions watch/filechanges.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
package watch

type FileChanges struct {
Expand Down
1 change: 1 addition & 0 deletions watch/inotify.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
1 change: 1 addition & 0 deletions watch/inotify_tracker.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
Loading

0 comments on commit 2c1f619

Please sign in to comment.