Codebase list golang-github-influxdata-tail / 7fa62e9
Import upstream version 1.0.0+git20210707.b283181 Debian Janitor 2 years ago
7 changed file(s) with 211 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
0 {
1 "ImportPath": "github.com/hpcloud/tail",
2 "GoVersion": "go1.5.1",
3 "Deps": [
4 {
5 "ImportPath": "gopkg.in/fsnotify.v1",
6 "Comment": "v1.2.1",
7 "Rev": "7be54206639f256967dd82fa767397ba5f8f48f5"
8 },
9 {
10 "ImportPath": "gopkg.in/tomb.v1",
11 "Rev": "c131134a1947e9afd9cecfe11f4c6dff0732ae58"
12 }
13 ]
14 }
0 This directory tree is generated automatically by godep.
1
2 Please do not edit.
3
4 See https://github.com/tools/godep for more information.
0 module github.com/influxdata/tail
1
2 go 1.13
3
4 require (
5 gopkg.in/fsnotify.v1 v1.2.1
6 gopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947
7 )
0 github.com/influxdata/tail v1.0.0 h1:RGikfjB/b5C/YP3p47YD48eE0WSsJyAVbBHNpoTHdX0=
1 github.com/influxdata/tail v1.0.0/go.mod h1:xTFF2SILpIYc5N+Srb0d5qpx7d+f733nBrbasb13DtQ=
2 gopkg.in/fsnotify.v1 v1.2.1 h1:x2hwAFVlj5ptNfCIgr3KRZm9IQcKDCWJbQDO7QxUXOo=
3 gopkg.in/fsnotify.v1 v1.2.1/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
4 gopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947 h1:aNEcl02ps/eZaBJi2LycKl0jPsUryySSSgrCxieZRYA=
5 gopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
5656 // Config is used to specify how a file must be tailed.
5757 type Config struct {
5858 // File-specifc
59 Location *SeekInfo // Seek to this location before tailing
60 ReOpen bool // Reopen recreated files (tail -F)
61 MustExist bool // Fail early if the file does not exist
62 Poll bool // Poll for file changes instead of using inotify
63 Pipe bool // Is a named pipe (mkfifo)
64 RateLimiter *ratelimiter.LeakyBucket
59 Location *SeekInfo // Seek to this location before tailing
60 ReOpen bool // Reopen recreated files (tail -F)
61 MustExist bool // Fail early if the file does not exist
62 Poll bool // Poll for file changes instead of using inotify
63 Pipe bool // Is a named pipe (mkfifo)
64 RateLimiter *ratelimiter.LeakyBucket
65 OpenReaderFunc func(rd io.Reader) io.Reader
6566
6667 // Generic IO
6768 Follow bool // Continue looking for new lines (tail -f)
395396
396397 func (tail *Tail) openReader() {
397398 tail.lk.Lock()
399 var rd io.Reader = tail.file
400 if tail.OpenReaderFunc != nil {
401 rd = tail.OpenReaderFunc(rd)
402 }
403
398404 if tail.MaxLineSize > 0 {
399405 // add 2 to account for newline characters
400 tail.reader = bufio.NewReaderSize(tail.file, tail.MaxLineSize+2)
406 tail.reader = bufio.NewReaderSize(rd, tail.MaxLineSize+2)
401407 } else {
402 tail.reader = bufio.NewReader(tail.file)
408 tail.reader = bufio.NewReader(rd)
403409 }
404410 tail.lk.Unlock()
405411 }
4848 }
4949
5050 changes := NewFileChanges()
51 var prevModTime time.Time
51 prevModTime := origFi.ModTime()
5252
5353 // XXX: use tomb.Tomb to cleanly manage these goroutines. replace
5454 // the fatal (below) with tomb's Kill.
0 package watch
1
2 import (
3 "errors"
4 "fmt"
5 "gopkg.in/tomb.v1"
6 "io/ioutil"
7 "os"
8 "os/exec"
9 "path/filepath"
10 "runtime"
11 "sync"
12 "testing"
13 "time"
14 )
15
16 func TestWatchNotify(t *testing.T) {
17 testCases := []struct {
18 name string
19 poll bool
20 }{
21 {"Test watch inotify", false},
22 {"Test watch poll", true},
23 }
24 for _, test := range testCases {
25 t.Run(test.name, func(t *testing.T) {
26 tmpDir, err := ioutil.TempDir("", "watch-")
27 if err != nil {
28 t.Fatal(err)
29 }
30 defer os.RemoveAll(tmpDir)
31 filePath := filepath.Join(tmpDir, "a")
32 // create file
33 file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0777)
34 if err != nil {
35 t.Fatal(err)
36 }
37 err = file.Close()
38 if err != nil {
39 t.Fatal(err)
40 }
41
42 var wg sync.WaitGroup
43 var werr error
44 changes := 0
45 chanClose := make(chan struct{})
46 go func() {
47 wg.Add(1)
48 changes, werr = watchFile(filePath, test.poll, chanClose)
49 wg.Done()
50 }()
51
52 writeToFile(t, filePath, "hello", true)
53 <-time.After(time.Second)
54 writeToFile(t, filePath, "world", true)
55 <-time.After(time.Second)
56 writeToFile(t, filePath, "end", false)
57 <-time.After(time.Second)
58 //err = os.Remove(filePath)
59 //if err != nil {
60 // t.Fatal(err)
61 //}
62 rmFile(t, filePath)
63 chanClose <- struct{}{}
64 wg.Wait()
65 close(chanClose)
66
67 if werr != nil {
68 t.Fatal(werr)
69 }
70 // ideally, there should be 4 changes (2xmodified,1xtruncaed and 1xdeleted)
71 // but, notifications from fsnotify are usually 2 (2xmodify) and 3x from poll (2xmodify, 1xtruncated)
72 if changes < 1 || changes > 4 {
73 t.Errorf("Invalid changes count: %d\n", changes)
74 }
75 })
76 }
77 }
78
79 func writeToFile(t *testing.T, path, content string, append bool) {
80 t.Helper()
81 redir := ">"
82 if append {
83 redir = ">>"
84 }
85 //var cmd *exec.Cmd
86 var out []byte
87 var err error
88 line := `echo ` + content + " " + redir + path + ``
89 if runtime.GOOS == "windows" {
90 out, err = exec.Command("cmd", "/c", line).Output()
91 //cmd = exec.Command("cmd", "/c", line)
92 } else {
93 //cmd = exec.Command("sh", "-c", line)
94 out, err = exec.Command("sh", "-c", line).Output()
95 }
96 //fmt.Println(cmd.String())
97 //err := cmd.Run()
98 if len(out) > 2 {
99 fmt.Println("output:", string(out))
100 }
101 if err != nil {
102 if ee, ok := err.(*exec.ExitError); ok {
103 fmt.Println("Stderr:", string(ee.Stderr))
104 }
105 t.Fatal(err)
106 }
107 }
108
109 func rmFile(t *testing.T, path string) {
110 t.Helper()
111 var cmd *exec.Cmd
112 if runtime.GOOS == "windows" {
113 cmd = exec.Command("cmd", "/c", "del", path)
114 } else {
115 cmd = exec.Command("rm", path)
116 }
117
118 err := cmd.Run()
119 if err != nil {
120 t.Fatal(err)
121 }
122 }
123
124 func watchFile(path string, poll bool, close <-chan struct{}) (int, error) {
125 changesCount := 0
126 var mytomb tomb.Tomb
127 var watcher FileWatcher
128 if poll {
129 watcher = NewPollingFileWatcher(path)
130 } else {
131 watcher = NewInotifyFileWatcher(path)
132 }
133
134 for {
135 changes, err := watcher.ChangeEvents(&mytomb, 0)
136 if err != nil {
137 return -1, err
138 }
139 select {
140 case <-changes.Modified:
141 fmt.Println("Modified")
142 changesCount++
143 case <-changes.Deleted:
144 fmt.Println("Deleted")
145 <-time.After(time.Second)
146 if _, err := os.Stat(path); err == nil {
147 changesCount++
148 }
149 case <-changes.Truncated:
150 fmt.Println("Truncated")
151 changesCount++
152 case <-mytomb.Dying():
153 return -1, errors.New("dying")
154 case <-close:
155 goto end
156 }
157 }
158 end:
159 mytomb.Done()
160 return changesCount, nil
161 }