Skip to content

About

File/Directory watching and logging using linux's inotify syscall.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fwt - File Watcher Tool

A lightweight, zero-dependency Linux file watcher daemon built on inotify. Watches files and directories for filesystem events and optionally executes commands when specific events occur.

Build

Requires Go 1.21 or later.

git clone <repo-url> && cd File-Watcher
go build -o fwt .

This produces a single binary fwt.

Quickstart

Watch a directory and print events to the terminal:

./fwt start /path/to/watch

In a separate terminal, query the daemon:

./fwt summary    # state + recent events
./fwt entries    # list watched paths
./fwt stop       # shut down the daemon

Usage

fwt start

Launch the watcher daemon.

fwt start [flags] <path> [<path> ...]
Flag Default Description
--path-file Path to a JSON pathfile (see below)
--log-level info Log level: debug, info, warn, error
--log-file Write JSON logs to this file
--no-terminal false Suppress terminal output

Examples:

# Watch two directories
./fwt start /home/user/src /home/user/docs

# Watch from a pathfile with triggers
./fwt start --path-file watches.json

# Run as a quiet background logger
./fwt start --path-file watches.json \
    --log-file /var/log/fwt.log \
    --log-level warn \
    --no-terminal &

fwt summary

Print the current daemon state: active watches, open files, and recent events.

./fwt summary

fwt entries

List all currently watched paths with their trigger rules.

./fwt entries

fwt update

Add or remove watches on a running daemon. Accepts the same pathfile schema as start, plus individual --add / --remove flags.

fwt update [flags]
Flag Description
--path-file JSON pathfile with add/remove entries
--add Single path to add
--remove Single path to remove
--trigger Trigger action for the added path (e.g. IN_MODIFY)
--cmd Command to run when the trigger fires

Examples:

# Add a path with a trigger
./fwt update --add /tmp/inbox \
    --trigger IN_CREATE \
    --cmd "echo new file"

# Remove a path
./fwt update --remove /tmp/inbox

# Bulk update from a pathfile
./fwt update --path-file changes.json

fwt stop

Gracefully shut down the running daemon.

./fwt stop

Pathfile format

Both start and update accept the same JSON schema. Each entry has an optional command field that is either "add" (default when omitted) or "remove".

{
    "watches": [
        {
            "path": "/home/user/src",
            "command": "add",
            "trigger_action": "IN_MODIFY",
            "execute_cmd": "make build"
        },
        {
            "path": "/home/user/logs",
            "command": "add"
        },
        {
            "path": "/tmp/old-watch",
            "command": "remove"
        }
    ]
}
Field Required Description
path yes Absolute or relative path to watch
command no "add" (default) or "remove"
trigger_action no Inotify event name (e.g. IN_MODIFY)
execute_cmd no Shell command to run on trigger

When used with fwt start, entries with command: "remove" are ignored (there is nothing to remove at startup). When used with fwt update, both add and remove entries are processed.

Supported trigger actions

Any standard inotify event name, with or without the IN_ prefix:

ACCESS, MODIFY, ATTRIB, CLOSE_WRITE, CLOSE_NOWRITE,
OPEN, MOVED_FROM, MOVED_TO, CREATE, DELETE,
DELETE_SELF, MOVE_SELF, ALL_EVENTS

Running tests

go test ./... -v

The test suite includes unit tests for the protocol layer and state management, plus integration tests that spin up a full server, exercise all client commands, create/delete/rename files, and verify event tracking.

Architecture

fwt is a single binary that acts as both server and client, communicating over a Unix domain socket (/tmp/fwt.sock).

fwt start        fwt summary / entries / update / stop
    |                       |
    v                       v
 [Server]  <--- UDS --->  [Client]
    |
    +-- Watcher (inotify event loop)
    +-- Listener (UDS request handler)
    +-- State (shared, mutex-protected)
    +-- Logger (file + terminal)
  • Watcher: Wraps a non-blocking inotify fd with os.NewFile for Go runtime poller integration. Recursively watches subdirectories. Detects renames by correlating MOVED_FROM / MOVED_TO cookies.
  • Listener: Accepts JSON requests over UDS and dispatches to State and Watcher.
  • State: All mutable data (watches, events, open files, pending renames) protected by a single sync.RWMutex.
  • Logger: Leveled, thread-safe logging to both terminal (colored) and file (JSON lines).

Known limitations

Recursive execution is possible. If a triggered command writes to a path that is itself being watched (directly or via a parent directory), the write will generate a new event, which will trigger the command again, creating an infinite loop. There is currently no built-in debouncing or loop detection.

To avoid this:

  • Make sure triggered commands do not write to watched directories.
  • Redirect command output to a path outside the watched tree (e.g. to /dev/null or a dedicated log directory that is not watched).
  • If using --log-file, ensure the log file is not inside a watched directory.

About

File/Directory watching and logging using linux's inotify syscall.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages