Skip to content

Commit 4070356

Browse files
authored
Any file changes that occurred before InotifyFileWatcher was started but after the preceding EOF would not be detected (#1)
1 parent 9254734 commit 4070356

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

util/util.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@ type Logger struct {
1717

1818
var LOGGER = &Logger{log.New(os.Stderr, "", log.LstdFlags)}
1919

20-
// fatal is like panic except it displays only the current goroutine's stack.
20+
// Fatal is like panic except it displays only the current goroutine's stack.
2121
func Fatal(format string, v ...interface{}) {
2222
// https://github.com/nxadm/log/blob/master/log.go#L45
2323
LOGGER.Output(2, fmt.Sprintf("FATAL -- "+format, v...)+"\n"+string(debug.Stack()))
2424
os.Exit(1)
2525
}
2626

27-
// partitionString partitions the string into chunks of given size,
27+
// Error logs an error message with the current goroutine stack and returns. It doesn't quit.
28+
func Error(format string, v ...interface{}) {
29+
LOGGER.Output(2, fmt.Sprintf("ERROR -- "+format, v...)+"\n"+string(debug.Stack()))
30+
}
31+
32+
// PartitionString partitions the string into chunks of given size,
2833
// with the last chunk of variable size.
2934
func PartitionString(s string, chunkSize int) []string {
3035
if chunkSize <= 0 {

watch/inotify.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
"github.com/nxadm/tail/util"
1313

14-
"github.com/fsnotify/fsnotify"
14+
"github.com/fsnotify/fsnotify"
1515
"gopkg.in/tomb.v1"
1616
)
1717

@@ -79,6 +79,13 @@ func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChange
7979

8080
events := Events(fw.Filename)
8181

82+
// Check to see the file hasn't been modified already before the watcher started
83+
fi, deleted := fw.checkAndNotifyIfModifiedInBetween(changes)
84+
if deleted {
85+
return
86+
}
87+
fw.Size = fi.Size()
88+
8289
for {
8390
prevSize := fw.Size
8491

@@ -134,3 +141,28 @@ func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChange
134141

135142
return changes, nil
136143
}
144+
145+
func (fw *InotifyFileWatcher) checkAndNotifyIfModifiedInBetween(changes *FileChanges) (os.FileInfo, bool) {
146+
fi, err := os.Stat(fw.Filename)
147+
if err != nil {
148+
if !os.IsNotExist(err) {
149+
util.Error("Failed to stat file %v: %v", fw.Filename, err)
150+
// Treat it as a deleted file as we cannot read it anyway.
151+
}
152+
_ = RemoveWatch(fw.Filename)
153+
changes.NotifyDeleted()
154+
return nil, true
155+
}
156+
157+
if fw.Size > fi.Size() { // old file size was larger than now => truncated
158+
changes.NotifyTruncated()
159+
} else if fw.Size != fi.Size() {
160+
changes.NotifyModified()
161+
}
162+
// there is a corner case of file that was truncated and replaced with exact same amount of bytes, which would
163+
// result in no notification. However any subsequent writes will capture that
164+
// If the file isn't expected to be written to often and those events cannot be missed, recommend using Polling watcher
165+
// instead of inotify
166+
167+
return fi, false
168+
}

0 commit comments

Comments
 (0)