class EventMachine::FileGlobWatch

A file glob pattern watcher for EventMachine.

If you are unfamiliar with globs, see Wikipedia: en.wikipedia.org/wiki/Glob_(programming)

Any glob supported by Dir#glob will work with this class.

This class will allow you to get notified whenever a file is created or deleted that matches your glob.

If you are subclassing, here are the methods you should implement:

file_found(path)
file_deleted(path)

See alsoe

Public Class Methods

new(glob, interval=60) click to toggle source

Watch a glob

  • glob - a string path or glob, such as “/var/log/*.log”

  • interval - number of seconds between scanning the glob for changes

# File lib/event_machine/tail/globwatcher.rb, line 36
def initialize(glob, interval=60)
  @glob = glob
  @files = Hash.new
  @watches = Hash.new
  @logger = Logger.new(STDOUT)
  @logger.level = ($DEBUG and Logger::DEBUG or Logger::WARN)
  @interval = interval
  start
end

Public Instance Methods

file_deleted(path) click to toggle source

This method is called when a file is deleted.

  • path - the string path of the file deleted

You must implement this in your subclass or module for it to work with EventMachine::watch_glob

# File lib/event_machine/tail/globwatcher.rb, line 91
def file_deleted(path)
  raise NotImplementedError.new("#{self.class.name}#file_deleted is not "\
    "implemented. Did you forget to implement this in your subclass or "\
    "module?")
end
file_found(path) click to toggle source

This method is called when a new file is found

  • path - the string path of the file found

You must implement this in your subclass or module for it to work with EventMachine::watch_glob

# File lib/event_machine/tail/globwatcher.rb, line 78
def file_found(path)
  raise NotImplementedError.new("#{self.class.name}#file_found is not "\
    "implemented. Did you forget to implement this in your subclass or "\
    "module?")
end
start() click to toggle source

This method may be called to start watching

# File lib/event_machine/tail/globwatcher.rb, line 56
def start
  # We periodically check here because it is easier than writing our own glob
  # parser (so we can smartly watch globs like /foo/*/bar*/*.log)
  #
  # Reasons to fix this -
  # This will likely perform badly on globs that result in a large number of
  # files.
  EM.next_tick do
    find_files
    @find_files_interval = EM.add_periodic_timer(@interval) do
      find_files
    end
  end # EM.next_tick
end
stop() click to toggle source

This method may be called to stop watching TODO(sissel): make 'stop' stop all active watches, too?

# File lib/event_machine/tail/globwatcher.rb, line 49
def stop
  @find_files_interval.cancel if @find_files_interval
end

Private Instance Methods

find_files() click to toggle source
# File lib/event_machine/tail/globwatcher.rb, line 98
def find_files
  @logger.info("Searching for files in #{@glob}")
  list = Dir.glob(@glob)

  known_files = @files.clone
  list.each do |path|
    fileinfo = FileInfo.new(path) rescue next
    # Skip files that have the same inode (renamed or hardlinked)
    known_files.delete(fileinfo.stat.ino)
    next if @files.include?(fileinfo.stat.ino)

    track(fileinfo)
    file_found(path)
  end

  # Report missing files.
  known_files.each do |inode, fileinfo|
    remove(fileinfo)
  end
end
remove(fileinfo) click to toggle source

Remove a file from being watched and notify file_deleted()

# File lib/event_machine/tail/globwatcher.rb, line 121
def remove(fileinfo)
  @files.delete(fileinfo.stat.ino)
  @watches.delete(fileinfo.path)
  file_deleted(fileinfo.path)
end
track(fileinfo) click to toggle source

Add a file to watch and notify file_found()

# File lib/event_machine/tail/globwatcher.rb, line 129
def track(fileinfo)
  @files[fileinfo.stat.ino] = fileinfo

  # If EventMachine::watch_file fails, that's ok, I guess.
  # We'll still find the file 'missing' from the next glob attempt.
  #begin
    # EM currently has a bug that only the first handler for a watch_file
    # on each file gets events. This causes globtails to never get data
    # since the glob is watching the file already.
    # Until we fix that, let's skip file watching here.
    #@watches[path] = EventMachine::watch_file(path, FileWatcher, self) do |path|
    #  remove(path)
    #end
  #rescue Errno::EACCES => e
    #@logger.warn(e)
  #end
end