Learn how to monitor file system changes with Clay's flexible watcher package
The Watcher package provides a simple and flexible way to watch for file system changes in Go applications. It recursively watches directories and can filter events based on file patterns.
go get github.com/go-go-golems/clay/pkg/watcher
package main
import (
"context"
"fmt"
"github.com/go-go-golems/clay/pkg/watcher"
)
func main() {
w := watcher.NewWatcher(
watcher.WithPaths("./path/to/watch"),
watcher.WithMask("**/*.txt"),
watcher.WithWriteCallback(func(path string) error {
fmt.Printf("File written: %s\n", path)
return nil
}),
watcher.WithRemoveCallback(func(path string) error {
fmt.Printf("File removed: %s\n", path)
return nil
}),
)
ctx := context.Background()
if err := w.Run(ctx); err != nil {
fmt.Printf("Watcher error: %v\n", err)
}
}
The Watcher package can recursively watch directories for changes:
w := watcher.NewWatcher(
watcher.WithPaths("./path/to/watch"),
)
This feature allows you to monitor an entire directory tree for changes, automatically including new subdirectories as they are created.
The Watcher can efficiently watch individual files by monitoring their parent directories:
w := watcher.NewWatcher(
watcher.WithPaths(
"./config/app.yaml",
"./config/db.yaml",
),
)
When watching individual files:
This is more efficient than watching individual files directly, especially on systems with inotify limits.
You can filter events based on file patterns using doublestar masks:
w := watcher.NewWatcher(
watcher.WithPaths("./path/to/watch"),
watcher.WithMask("**/*.txt"),
)
This allows you to focus on specific file types or patterns, ignoring changes to files that don't match the specified mask.
The package provides separate callbacks for write and remove events:
w := watcher.NewWatcher(
watcher.WithWriteCallback(func(path string) error {
fmt.Printf("File written: %s\n", path)
return nil
}),
watcher.WithRemoveCallback(func(path string) error {
fmt.Printf("File removed: %s\n", path)
return nil
}),
)
These callbacks allow you to define custom behavior when files are written to or removed from the watched directories.
You can configure how the watcher handles errors:
w := watcher.NewWatcher(
watcher.WithBreakOnError(true),
)
This option allows you to decide whether the watcher should stop on the first error encountered or continue running despite errors.
The package uses the functional options pattern for easy and flexible configuration:
w := watcher.NewWatcher(
watcher.WithPaths("./path1", "./path2"),
watcher.WithMask("**/*.go", "**/*.txt"),
watcher.WithWriteCallback(writeHandler),
watcher.WithRemoveCallback(removeHandler),
watcher.WithBreakOnError(false),
)
This approach allows for clear and concise setup of the watcher with multiple options.
The watcher runs with a context, allowing for graceful shutdown:
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err := w.Run(ctx); err != nil {
log.Printf("Watcher error: %v\n", err)
}
This feature enables easy integration with Go's context package for managing the watcher's lifecycle.
file_logger.go:package main
import (
"context"
"fmt"
"github.com/go-go-golems/clay/pkg/watcher"
"os"
"os/signal"
"syscall"
)
func main() {
w := watcher.NewWatcher(
watcher.WithPaths("./logs"),
watcher.WithMask("**/*.log"),
watcher.WithWriteCallback(logFileChange),
watcher.WithRemoveCallback(logFileRemoval),
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
cancel()
}()
if err := w.Run(ctx); err != nil && err != context.Canceled {
fmt.Printf("Watcher error: %v\n", err)
}
}
func logFileChange(path string) error {
fmt.Printf("File changed: %s\n", path)
return nil
}
func logFileRemoval(path string) error {
fmt.Printf("File removed: %s\n", path)
return nil
}
Create a logs directory in the same folder as your Go file.
Run the program:
go run file_logger.go
logs directory to see the watcher in action.This example demonstrates how to use the Watcher package to monitor a specific directory for changes to log files, logging any modifications or removals to the console.