class FileWatch::Ext::TailBase

Constants

OPEN_WARN_INTERVAL

how often (in seconds) we @logger.warn a failed file open, per path.

Attributes

logger[RW]

Public Class Methods

new(opts={}) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 22
def initialize(opts={})
  @iswindows = ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil)

  if opts[:logger]
    @logger = opts[:logger]
  else
    @logger = Logger.new(STDERR)
    @logger.level = Logger::INFO
  end
  @files = {}
  @lastwarn = Hash.new { |h, k| h[k] = 0 }
  @watch = FileWatch::Watch.new
  @watch.logger = @logger
  @sincedb = {}
  @sincedb_last_write = 0
  @statcache = {}
  @opts = {
    :sincedb_write_interval => 10,
    :stat_interval => 1,
    :discover_interval => 5,
    :exclude => [],
    :start_new_files_at => :end,
    :progressdb => false,
    :eof_close => false,
  }.merge(opts)
  if !@opts.include?(:sincedb_path)
    @opts[:sincedb_path] = File.join(ENV["HOME"], ".sincedb") if ENV.include?("HOME")
    @opts[:sincedb_path] = ENV["SINCEDB_PATH"] if ENV.include?("SINCEDB_PATH")
  end
  if !@opts.include?(:sincedb_path)
    raise NoSinceDBPathGiven.new("No HOME or SINCEDB_PATH set in environment. I need one of these set so I can keep track of the files I am following.")
  end
  @watch.exclude(@opts[:exclude])

  _sincedb_open
end

Public Instance Methods

logger=(logger) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 60
def logger=(logger)
  @logger = logger
  @watch.logger = logger
end
quit() click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 185
def quit
  @watch.quit
end
sincedb_write(reason=nil) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 103
def sincedb_write(reason=nil)
  @logger.debug("caller requested sincedb write (#{reason})")
  _sincedb_write
end
subscribe(&block) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 71
def subscribe(&block)
  # to be overwritten
end
tail(path) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 66
def tail(path)
  @watch.watch(path)
end

Protected Instance Methods

_check_sincedb(eof, path, &block) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 91
def _check_sincedb(eof, path, &block)
  now = Time.now.to_i
  delta = now - @sincedb_last_write
  if eof || delta >= @opts[:sincedb_write_interval]
    @logger.debug("writing sincedb (delta since last write = #{delta})") if @logger.debug?
    _sincedb_write
    _progressdb_write(path, eof, &block) if @opts[:progressdb]
    @sincedb_last_write = now
  end
end
_open_file(path, event) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 76
def _open_file(path, event)
  # to be overwritten
end
_progressdb_delete(path) { |path, line, :progressdb_del| ... } click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 176
def _progressdb_delete(path, &block)
  inode = @statcache[path]
  meta = @sincedb[inode]

  line = [inode, meta[:size], meta[:pos]].flatten.join(" ")
  yield(path, line, :progressdb_del)
end
_progressdb_write(path, eof) { |path, line, :progressdb| ... } click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 158
def _progressdb_write(path, eof, &block)
  if eof
    inode = @statcache[path]
    meta = @sincedb[@statcache[path]]
    line = [inode, meta[:size], meta[:pos]].flatten.join(" ")
    yield(path, line, :progressdb)
  else
    @statcache.each do |path, inode|
      meta = @sincedb[inode]
      if meta[:size] != meta[:pos]
        line = [inode, meta[:size], meta[:pos]].flatten.join(" ")
        yield(path, line, :progressdb)
      end
    end
  end
end
_read_file(path, &block) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 81
def _read_file(path, &block)
  # to be overwritten
end
_sincedb_delete(path) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 151
def _sincedb_delete(path)
  inode = @statcache[path]
  @sincedb.delete(inode)
  _sincedb_write
end
_sincedb_open() click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 109
def _sincedb_open
  path = @opts[:sincedb_path]
  begin
    db = File.open(path)
  rescue
    @logger.debug("_sincedb_open: #{path}: #{$!}")
    return
  end

  @logger.debug("_sincedb_open: reading from #{path}")
  db.each do |line|
    ino, dev_major, dev_minor, size, pos = line.split(" ", 5)
    inode = [ino, dev_major.to_i, dev_minor.to_i]
    @logger.debug("_sincedb_open: setting #{inode.inspect} to #{pos.to_i}")
    @sincedb[inode] = {:size => size.to_i, :pos => pos.to_i}
  end
end
_sincedb_write() click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 128
def _sincedb_write
  path = @opts[:sincedb_path]
  tmp = "#{path}.new"
  begin
    db = File.open(tmp, "w")
  rescue => e
    @logger.warn("_sincedb_write failed: #{tmp}: #{e}")
    return
  end

  @sincedb.each do |inode, meta|
    db.puts([inode, meta[:size], meta[:pos]].flatten.join(" "))
  end
  db.close

  begin
    File.rename(tmp, path)
  rescue => e
    @logger.warn("_sincedb_write rename/sync failed: #{tmp} -> #{path}: #{e}")
  end
end

Private Instance Methods

_close_file(path) click to toggle source
# File lib/filewatch/ext/tailbase.rb, line 86
def _close_file(path)
  @files[path].close
end