fix(daemon): deduplicate file and git ref change log messages
The daemon.log was showing duplicate log messages: - 'File change detected' appeared 4x for a single file change - 'Git ref change detected' appeared 2x for a single ref update Root cause: - fsnotify generates multiple events (Write, Create, Chmod) for single file ops - Both parent directory and file watchers can trigger for the same change - Multiple git ref files may be updated simultaneously Fix: - Add log deduplication with 500ms window (matching debouncer window) - Track last log time for file changes and git ref changes separately - Only log if enough time has passed since last log of same type - Still trigger debouncer for every event (functionality unchanged) This reduces log noise while maintaining full functionality.
This commit is contained in:
@@ -30,6 +30,11 @@ type FileWatcher struct {
|
|||||||
lastHeadExists bool
|
lastHeadExists bool
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
wg sync.WaitGroup // Track goroutines for graceful shutdown (bd-jo38)
|
wg sync.WaitGroup // Track goroutines for graceful shutdown (bd-jo38)
|
||||||
|
// Log deduplication: track last log times to avoid duplicate messages
|
||||||
|
lastFileLogTime time.Time
|
||||||
|
lastGitRefLogTime time.Time
|
||||||
|
logDedupeWindow time.Duration
|
||||||
|
logMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileWatcher creates a file watcher for the given JSONL path.
|
// NewFileWatcher creates a file watcher for the given JSONL path.
|
||||||
@@ -41,6 +46,7 @@ func NewFileWatcher(jsonlPath string, onChanged func()) (*FileWatcher, error) {
|
|||||||
parentDir: filepath.Dir(jsonlPath),
|
parentDir: filepath.Dir(jsonlPath),
|
||||||
debouncer: NewDebouncer(500*time.Millisecond, onChanged),
|
debouncer: NewDebouncer(500*time.Millisecond, onChanged),
|
||||||
pollInterval: 5 * time.Second,
|
pollInterval: 5 * time.Second,
|
||||||
|
logDedupeWindow: 500 * time.Millisecond, // Deduplicate logs within this window
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get initial file state for polling fallback
|
// Get initial file state for polling fallback
|
||||||
@@ -120,6 +126,30 @@ func NewFileWatcher(jsonlPath string, onChanged func()) (*FileWatcher, error) {
|
|||||||
return fw, nil
|
return fw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shouldLogFileChange returns true if enough time has passed since last file change log
|
||||||
|
func (fw *FileWatcher) shouldLogFileChange() bool {
|
||||||
|
fw.logMu.Lock()
|
||||||
|
defer fw.logMu.Unlock()
|
||||||
|
now := time.Now()
|
||||||
|
if now.Sub(fw.lastFileLogTime) >= fw.logDedupeWindow {
|
||||||
|
fw.lastFileLogTime = now
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldLogGitRefChange returns true if enough time has passed since last git ref change log
|
||||||
|
func (fw *FileWatcher) shouldLogGitRefChange() bool {
|
||||||
|
fw.logMu.Lock()
|
||||||
|
defer fw.logMu.Unlock()
|
||||||
|
now := time.Now()
|
||||||
|
if now.Sub(fw.lastGitRefLogTime) >= fw.logDedupeWindow {
|
||||||
|
fw.lastGitRefLogTime = now
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Start begins monitoring filesystem events or polling.
|
// Start begins monitoring filesystem events or polling.
|
||||||
// Runs in background goroutine until context is canceled.
|
// Runs in background goroutine until context is canceled.
|
||||||
// Should only be called once per FileWatcher instance.
|
// Should only be called once per FileWatcher instance.
|
||||||
@@ -156,7 +186,9 @@ func (fw *FileWatcher) Start(ctx context.Context, log daemonLogger) {
|
|||||||
|
|
||||||
// Handle JSONL write/chmod events
|
// Handle JSONL write/chmod events
|
||||||
if event.Name == fw.jsonlPath && event.Op&(fsnotify.Write|fsnotify.Create|fsnotify.Chmod) != 0 {
|
if event.Name == fw.jsonlPath && event.Op&(fsnotify.Write|fsnotify.Create|fsnotify.Chmod) != 0 {
|
||||||
log.log("File change detected: %s (op: %v)", event.Name, event.Op)
|
if fw.shouldLogFileChange() {
|
||||||
|
log.log("File change detected: %s", event.Name)
|
||||||
|
}
|
||||||
fw.debouncer.Trigger()
|
fw.debouncer.Trigger()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -179,7 +211,9 @@ func (fw *FileWatcher) Start(ctx context.Context, log daemonLogger) {
|
|||||||
|
|
||||||
// Handle git ref changes (only events under gitRefsPath)
|
// Handle git ref changes (only events under gitRefsPath)
|
||||||
if event.Op&fsnotify.Write != 0 && strings.HasPrefix(event.Name, fw.gitRefsPath) {
|
if event.Op&fsnotify.Write != 0 && strings.HasPrefix(event.Name, fw.gitRefsPath) {
|
||||||
|
if fw.shouldLogGitRefChange() {
|
||||||
log.log("Git ref change detected: %s", event.Name)
|
log.log("Git ref change detected: %s", event.Name)
|
||||||
|
}
|
||||||
fw.debouncer.Trigger()
|
fw.debouncer.Trigger()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user