runtime: FileSystemWatcher not getting rename events
I’ve got a worker service in a .NET Core 3.1 app that uses a FileSystemWatcher
to monitor PostgreSQL logfiles. However, it never receives events for the logfiles themselves. If I set the watcher to include subdirectories, it receives events for temporary files being updated, renamed, and deleted, but never for the log files (*.log and *.csv). I know from running ls -l
over and over that the logfiles are in fact being updated as they constantly increase in size. I also used procmon to see that the .csv file is being written to about twice per second using WriteFile
(in Windows).
Here’s how I’m using my watcher:
type LogFileWatcherOptions() =
member val DataDir = "" with get,set
member val LogFormat = "" with get,set
type LogFileWatcher(logger:ILogger<LogFileWatcher>, optionsMonitor:IOptionsMonitor<LogFileWatcherOptions>) =
inherit BackgroundService()
let handleFileChanged (fsea:FileSystemEventArgs) =
sprintf "%s changed: %O" fsea.FullPath fsea.ChangeType
|> logger.LogTrace
let handlePathCreated (fsea:FileSystemEventArgs) =
sprintf "%s created: %O" fsea.FullPath fsea.ChangeType
|> logger.LogTrace
let handlePathRenamed (rea:RenamedEventArgs) =
sprintf "%s renamed to %s (%O)" rea.OldFullPath rea.FullPath rea.ChangeType
|> logger.LogTrace
let handlePathDeleted (fsea:FileSystemEventArgs) =
sprintf "%s deleted (%O)" fsea.FullPath fsea.ChangeType
|> logger.LogTrace
let configureWatcher path format =
sprintf "configuring watcher with path: '%s' and format: '%s'" path format
|> logger.LogTrace
if not (Directory.Exists(path)) then
failwithf "data directory does not exist: %s" path
let watcher = new FileSystemWatcher()
watcher.Path <- path
watcher.IncludeSubdirectories <- true
watcher.Filter <- "*.csv"
watcher.NotifyFilter <- watcher.NotifyFilter ||| NotifyFilters.LastAccess
watcher.NotifyFilter <- watcher.NotifyFilter ||| NotifyFilters.Size
watcher.Changed.Add(handleFileChanged)
watcher.Created.Add(handlePathCreated)
watcher.Renamed.Add(handlePathRenamed)
watcher.Deleted.Add(handlePathDeleted)
watcher
let _options = optionsMonitor.CurrentValue
let _watcher = configureWatcher _options.DataDir _options.LogFormat
override __.Dispose() =
_watcher.Dispose()
base.Dispose()
override __.ExecuteAsync(stopToken) =
async {
logger.LogTrace "enabling filewatcher events..."
_watcher.EnableRaisingEvents <- true
while not stopToken.IsCancellationRequested do
do! Async.Sleep 500
logger.LogTrace "cancelling..."
_watcher.EnableRaisingEvents <- false
}
|> Async.StartAsTask
:> Task
Is it possible that PostgreSQL is writing to these logs in a way that the underlying implementation of FileSystemWatcher
is unable to detect?
Update: I tested this on Windows, too, and the same thing holds true there.
About this issue
- Original URL
- State: open
- Created 4 years ago
- Comments: 22 (12 by maintainers)
If multiple files are being changed at once (or quicky) you may be running into https://github.com/dotnet/runtime/issues/30846. Actual events are cached and distributed by separate OS daemon as well as the logic to pair events was broken at .Net layer. There is at least one more outstanding bug where available OS API does not allow to disambiguate events properly in all cases.
It may be work or putting together standalone repro @aggieben where you watch as well as manipulate watched files. And perhaps give it try with 5.0 preview.
I also tried adding an error handler as you suggested, but it doesn’t receive any events.