From ab659d907ff4fcadb238fc3a7ba34030090d0f94 Mon Sep 17 00:00:00 2001 From: want0011 Date: Thu, 4 Jul 2024 11:46:16 +0800 Subject: [PATCH] feat: fix file change(rename) line loss and duplication --- tail.go | 20 ++++++++++++++------ watch/inotify.go | 28 ++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/tail.go b/tail.go index c962599..9dca2c9 100644 --- a/tail.go +++ b/tail.go @@ -2,11 +2,11 @@ // 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. +// 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 ( @@ -21,10 +21,11 @@ import ( "sync" "time" + "gopkg.in/tomb.v1" + "github.com/nxadm/tail/ratelimiter" "github.com/nxadm/tail/util" "github.com/nxadm/tail/watch" - "gopkg.in/tomb.v1" ) var ( @@ -383,6 +384,13 @@ func (tail *Tail) waitForChanges() error { } } + // The write event should be handled first + select { + case <-tail.changes.Modified: + return nil + default: + } + select { case <-tail.changes.Modified: return nil diff --git a/watch/inotify.go b/watch/inotify.go index cbd11ad..5c27003 100644 --- a/watch/inotify.go +++ b/watch/inotify.go @@ -8,10 +8,11 @@ import ( "fmt" "os" "path/filepath" + "syscall" "github.com/nxadm/tail/util" - "github.com/fsnotify/fsnotify" + "github.com/fsnotify/fsnotify" "gopkg.in/tomb.v1" ) @@ -19,10 +20,12 @@ import ( type InotifyFileWatcher struct { Filename string Size int64 + // inodeId record cur watch file id + inodeId uint64 } func NewInotifyFileWatcher(filename string) *InotifyFileWatcher { - fw := &InotifyFileWatcher{filepath.Clean(filename), 0} + fw := &InotifyFileWatcher{filepath.Clean(filename), 0, 0} return fw } @@ -74,6 +77,12 @@ func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChange changes := NewFileChanges() fw.Size = pos + var stat syscall.Stat_t + // record file inodeId + err = syscall.Stat(fw.Filename, &stat) + if err == nil { + fw.inodeId = stat.Ino + } go func() { @@ -122,10 +131,21 @@ func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChange } fw.Size = fi.Size() + // No matter what, it is necessary to notify a write event. + changes.NotifyModified() + if prevSize > 0 && prevSize > fw.Size { + // file change; if file inodeId changed, notify delete event + if fw.inodeId > 0 && fi.Sys() != nil { + if statT, fok := fi.Sys().(*syscall.Stat_t); fok { + if statT.Ino != fw.inodeId { + RemoveWatch(fw.Filename) + changes.NotifyDeleted() + return + } + } + } changes.NotifyTruncated() - } else { - changes.NotifyModified() } prevSize = fw.Size }