Tail non-existent file: Lines channel closes when MustExist=false.
davidnewhall opened this issue · 3 comments
Describe the bug
Tailing files that do not exist causes the go channel to close almost immediately. I've also noticed that the go channel closes (sometimes) when a file rotates; I think that happens when the file does not get re-created right away. I hope i'm just missing something and there's a workaround to this issue, or maybe some obvious tactic I'm not seeing.
Also, calling .Stop()
on a closed tail
produces an error (on windows) that indicates it's trying to open the file:
Unable to open file C:\ProgramData\file.path: The process cannot access the file because it is being used by another process.
Maybe this is expected, and I'm going to avoid calling stop when the channel is closed, but my first iteration did not and I noticed this. Wanted to share.
Expected behavior
It's not clear why the go channel closes. Once it's closed, it cannot be reused. I would expect the channel not to be closed until .Stop()
is called.
To Reproduce
Try to tail a file that does not exist. The channel closes, and when you create the file there is no channel to read lines from.
package main
import (
"log"
"os"
"github.com/nxadm/tail"
)
func main() {
log := log.New(os.Stdout, "", 0)
t, err := tail.TailFile("/tmp/does.not.exist", tail.Config{
Follow: true,
ReOpen: true,
Logger: log,
})
if err != nil {
log.Println(err)
}
defer func() {
if err := t.Stop(); err != nil {
log.Println(err)
}
}()
for line := range t.Lines {
log.Println(line.Text)
}
log.Println("channel closed")
}
// Output:
// Waiting for /tmp/does.not.exist to appear...
// channel closed
// Failed to detect creation of /tmp/does.not.exist: bad file descriptor
(the last line is likely OS dependent, the above error is from macos x86)
System information
Happens on macos arm&x86 and windows x86 using v1.4.8.
Additional context
🤞
Similar behavior with pseudo log rotation.
2022/06/01 02:04:15 Re-opening moved/deleted file /tmp/foo ...
2022/06/01 02:04:15 Waiting for /tmp/foo to appear...
... channel closes.
Caused by
mv /tmp/foo /tmp/foo.1 ; echo foo > /tmp/foo
The above code gives me different behavior on macOS arm and again while running sudo.
ajn-im1:test david$ go run .
Waiting for /tmp/does.not.exist to appear...
channel closed
Failed to detect creation of /tmp/does.not.exist: permission denied
... channel closes
ajn-im1:test david$ sudo go run .
Waiting for /tmp/does.not.exist to appear...
... nothing ever happens, even if I create the file.
It appears that BlockUntilExists
in inotify.go never sees file events for files that do not exist. At least not on a Mac. The function never returns when running as root. It also seems that you can only add a watcher to a nonexistent file as root. Very strange behavior. If I enable polling, it finds the file and only prints the first line I tee
into it, then never prints anything else and never exits.
For what it's worth I also use the fsnotify library in another app that's widely used. It works reliably on every OS. The situations where it doesn't work well are Docker and Network mount (CIFS, generally). I use it to watch folder events specifically, never files, and never things that do not exist.
Most of this weird behavior went away when I gave iTerm full disk access. In fact, I can no longer reproduce the original problem; the app stays running, even when deleting and re-creating the file.
I'm still getting some strange behavior where the process just stops reporting lines, but I haven't been able to trace it down enough to know if it's my code or not. I'm going to close this since I cannot reproduce these issues under proper circumstances. Sorry and thanks!