Class: FileWatch::Tail

Inherits:
Object
  • Object
show all
Defined in:
lib/filewatch/tail.rb

Defined Under Namespace

Classes: NoSinceDBPathGiven

Constant Summary collapse

OPEN_WARN_INTERVAL =

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

ENV["FILEWATCH_OPEN_WARN_INTERVAL"] ?
ENV["FILEWATCH_OPEN_WARN_INTERVAL"].to_i : 300

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Tail

Returns a new instance of Tail.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/filewatch/tail.rb', line 24

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 }
  @buffers = {}
  @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,
    :delimiter => "\n"
  }.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

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.



19
20
21
# File 'lib/filewatch/tail.rb', line 19

def logger
  @logger
end

Instance Method Details

#close_file(path) ⇒ Object

close_file(path) is to be used by external code when it knows that it is completely done with a file. Other files or folders may still be being watched. Caution, once unwatched, a file can’t be watched again unless a new instance of this class begins watching again. The sysadmin should rename, move or delete the file.



257
258
259
260
261
262
263
# File 'lib/filewatch/tail.rb', line 257

def close_file(path)
  @watch.unwatch(path)
  file = @files.delete(path)
  return if file.nil?
  _sincedb_write
  file.close
end

#quitObject

quit is a sort-of finalizer, it should be called for clean up before the instance is disposed of.



243
244
245
246
247
248
# File 'lib/filewatch/tail.rb', line 243

def quit
  _sincedb_write
  @watch.quit
  @files.each {|path, file| file.close }
  @files.clear
end

#sincedb_record_uid(path, stat) ⇒ Object



110
111
112
113
114
# File 'lib/filewatch/tail.rb', line 110

def sincedb_record_uid(path, stat)
  inode = @watch.inode(path,stat)
  @statcache[path] = inode
  return inode
end

#sincedb_write(reason = nil) ⇒ Object



203
204
205
206
# File 'lib/filewatch/tail.rb', line 203

def sincedb_write(reason=nil)
  @logger.debug? && @logger.debug("caller requested sincedb write (#{reason})")
  _sincedb_write
end

#subscribe(&block) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/filewatch/tail.rb', line 73

def subscribe(&block)
  # subscribe(stat_interval = 1, discover_interval = 5, &block)
  @watch.subscribe(@opts[:stat_interval],
                   @opts[:discover_interval]) do |event, path|
    case event
    when :create, :create_initial
      if @files.member?(path)
        @logger.debug? && @logger.debug("#{event} for #{path}: already exists in @files")
        next
      end
      if _open_file(path, event)
        _read_file(path, &block)
      end
    when :modify
      if !@files.member?(path)
        @logger.debug? && @logger.debug(":modify for #{path}, does not exist in @files")
        if _open_file(path, event)
          _read_file(path, &block)
        end
      else
        _read_file(path, &block)
      end
    when :delete
      @logger.debug? && @logger.debug(":delete for #{path}, deleted from @files")
      if @files[path]
        _read_file(path, &block)
        @files[path].close
      end
      @files.delete(path)
      @statcache.delete(path)
    else
      @logger.warn("unknown event type #{event} for #{path}")
    end
  end # @watch.subscribe
end

#tail(path) ⇒ Object



68
69
70
# File 'lib/filewatch/tail.rb', line 68

def tail(path)
  @watch.watch(path)
end