notify GoDoc Build Status Build status Coverage Status

Filesystem event notification library on steroids. (under active development)



~ $ go get -u

Projects using notify

Expand ▾ Collapse ▴



    Package notify implements access to filesystem events.

    Notify is a high-level abstraction over filesystem watchers like inotify, kqueue, FSEvents, FEN or ReadDirectoryChangesW. Watcher implementations are split into two groups: ones that natively support recursive notifications (FSEvents and ReadDirectoryChangesW) and ones that do not (inotify, kqueue, FEN). For more details see watcher and recursiveWatcher interfaces in watcher.go source file.

    On top of filesystem watchers notify maintains a watchpoint tree, which provides a strategy for creating and closing filesystem watches and dispatching filesystem events to user channels.

    An event set is just an event list joint using bitwise OR operator into a single event value. Both the platform-independent (see Constants) and specific events can be used. Refer to the event_*.go source files for information about the available events.

    A filesystem watch or just a watch is platform-specific entity which represents a single path registered for notifications for specific event set. Setting a watch means using platform-specific API calls for creating / initializing said watch. For each watcher the API call is:

    - FSEvents: FSEventStreamCreate
    - inotify:  notify_add_watch
    - kqueue:   kevent
    - ReadDirectoryChangesW: CreateFile+ReadDirectoryChangesW
    - FEN:      port_get

    To rewatch means to either shrink or expand an event set that was previously registered during watch operation for particular filesystem watch.

    A watchpoint is a list of user channel and event set pairs for particular path (watchpoint tree's node). A single watchpoint can contain multiple different user channels registered to listen for one or more events. A single user channel can be registered in one or more watchpoints, recursive and non-recursive ones as well.




    View Source
    const (
    	Create = osSpecificCreate
    	Remove = osSpecificRemove
    	Write  = osSpecificWrite
    	Rename = osSpecificRename
    	// All is handful alias for all platform-independent event values.
    	All = Create | Remove | Write | Rename

      Create, Remove, Write and Rename are the only event values guaranteed to be present on all platforms.

      View Source
      const (
      	InAccess       = Event(unix.IN_ACCESS)        // File was accessed
      	InModify       = Event(unix.IN_MODIFY)        // File was modified
      	InAttrib       = Event(unix.IN_ATTRIB)        // Metadata changed
      	InCloseWrite   = Event(unix.IN_CLOSE_WRITE)   // Writtable file was closed
      	InCloseNowrite = Event(unix.IN_CLOSE_NOWRITE) // Unwrittable file closed
      	InOpen         = Event(unix.IN_OPEN)          // File was opened
      	InMovedFrom    = Event(unix.IN_MOVED_FROM)    // File was moved from X
      	InMovedTo      = Event(unix.IN_MOVED_TO)      // File was moved to Y
      	InCreate       = Event(unix.IN_CREATE)        // Subfile was created
      	InDelete       = Event(unix.IN_DELETE)        // Subfile was deleted
      	InDeleteSelf   = Event(unix.IN_DELETE_SELF)   // Self was deleted
      	InMoveSelf     = Event(unix.IN_MOVE_SELF)     // Self was moved

        Inotify specific masks are legal, implemented events that are guaranteed to work with notify package on linux-based systems.


        This section is empty.


        func Stop

        func Stop(c chan<- EventInfo)

          Stop removes all watchpoints registered for c. All underlying watches are also removed, for which c was the last channel listening for events.

          Stop does not close c. When Stop returns, it is guaranteed that c will receive no more signals.


            This example shows why it is important to not create leaks by stoping a channel when it's no longer being used.


            func Watch

            func Watch(path string, c chan<- EventInfo, events ...Event) error

            Watch sets up a watchpoint on path listening for events given by the events argument.

            File or directory given by the path must exist, otherwise Watch will fail with non-nil error. Notify resolves, for its internal purpose, any symlinks the provided path may contain, so it may fail if the symlinks form a cycle. It does so, since not all watcher implementations treat passed paths as-is. E.g. FSEvents reports a real path for every event, setting a watchpoint on /tmp will report events with paths rooted at /private/tmp etc.

            The c almost always is a buffered channel. Watch will not block sending to c - the caller must ensure that c has sufficient buffer space to keep up with the expected event rate.

            It is allowed to pass the same channel multiple times with different event list or different paths. Calling Watch with different event lists for a single watchpoint expands its event set. The only way to shrink it, is to call Stop on its channel.

            Calling Watch with empty event list does expand nor shrink watchpoint's event set. If c is the first channel to listen for events on the given path, Watch will seamlessly create a watch on the filesystem.

            Notify dispatches copies of single filesystem event to all channels registered for each path. If a single filesystem event contains multiple coalesced events, each of them is dispatched separately. E.g. the following filesystem change:

            ~ $ echo Hello > Notify.txt

            dispatches two events - notify.Create and notify.Write. However, it may depend on the underlying watcher implementation whether OS reports both of them.

            Windows and recursive watches

            If a directory which path was used to create recursive watch under Windows gets deleted, the OS will not report such event. It is advised to keep in mind this limitation while setting recursive watchpoints for your application, e.g. use persistent paths like %userprofile% or watch additionally parent directory of a recursive watchpoint in order to receive delete events for it.


              This is a basic example showing how to work with notify.Watch function.

              Example (Linux)

                This example shows how to watch changes made on file-system by text editor when saving a file. Usually, either InCloseWrite or InMovedTo (when swapping with a temporary file) event is created.

                Example (LinuxMove)

                  This example shows how to use Sys() method from EventInfo interface to tie two separate events generated by rename(2) function.

                  Example (Recursive)

                    This example shows how to set up a recursive watchpoint.



                    type Event

                    type Event uint32

                      Event represents the type of filesystem action.

                      Number of available event values is dependent on the target system or the watcher implmenetation used (e.g. it's possible to use either kqueue or FSEvents on Darwin).

                      Please consult documentation for your target platform to see list of all available events.

                      func (Event) String

                      func (e Event) String() string

                        String implements fmt.Stringer interface.

                        type EventInfo

                        type EventInfo interface {
                        	Event() Event     // event value for the filesystem action
                        	Path() string     // real path of the file or directory
                        	Sys() interface{} // underlying data source (can return nil)

                        EventInfo describes an event reported by the underlying filesystem notification subsystem.

                        It always describes single event, even if the OS reported a coalesced action. Reported path is absolute and clean.

                        For non-recursive watchpoints its base is always equal to the path passed to corresponding Watch call.

                        The value of Sys if system-dependent and can be nil.


                        Under Darwin (FSEvents) Sys() always returns a non-nil *notify.FSEvent value, which is defined as:

                        type FSEvent struct {
                            Path  string // real path of the file or directory
                            ID    uint64 // ID of the event (FSEventStreamEventId)
                            Flags uint32 // joint FSEvents* flags (FSEventStreamEventFlags)

                        For possible values of Flags see Darwin godoc for notify or FSEvents documentation for FSEventStreamEventFlags constants:


                        Under Linux (inotify) Sys() always returns a non-nil *unix.InotifyEvent value, defined as:

                        type InotifyEvent struct {
                            Wd     int32    // Watch descriptor
                            Mask   uint32   // Mask describing event
                            Cookie uint32   // Unique cookie associating related events (for rename(2))
                            Len    uint32   // Size of name field
                            Name   [0]uint8 // Optional null-terminated name

                        More information about inotify masks and the usage of inotify_event structure can be found at:


                        Under Darwin, DragonFlyBSD, FreeBSD, NetBSD, OpenBSD (kqueue) Sys() always returns a non-nil *notify.Kevent value, which is defined as:

                        type Kevent struct {
                            Kevent *syscall.Kevent_t // Kevent is a kqueue specific structure
                            FI     os.FileInfo       // FI describes file/dir

                        More information about syscall.Kevent_t can be found at:


                        Under Windows (ReadDirectoryChangesW) Sys() always returns nil. The documentation of watcher's WinAPI function can be found at:




                          • Notify does not collect watchpoints, when underlying watches were removed by their os-specific watcher implementations. Instead users are advised to listen on persistent paths to have guarantee they receive events for the whole lifetime of their applications (to discuss see #69).

                            • Linux (inotify) does not support watcher behavior masks like InOneshot, InOnlydir etc. Instead users are advised to perform the filtering themselves (to discuss see #71).

                              • Notify was not tested for short path name support under Windows (ReadDirectoryChangesW).

                                • Windows (ReadDirectoryChangesW) cannot recognize which notification triggers FileActionModified event. (to discuss see #75).