Class: EventMachine::FileTail

Inherits:
Object
  • Object
show all
Defined in:
lib/em/filetail.rb

Overview

Tail a file.

Example

class Tailer < EventMachine::FileTail
  def receive_data(data)
    puts "Got #{data.length} bytes"
  end

  # Optional
  def eof
    puts "Got EOF!"
    # If you want to stop
    stop
  end
end

# Now add it to EM
EM.run do
  EM.file_tail("/var/log/messages", Tailer)
end

# Or this way:
EM.run do
  Tailer.new("/var/log/messages")
end

See also: EventMachine::FileTail#receive_data

Defined Under Namespace

Classes: FileWatcher

Constant Summary collapse

CHUNKSIZE =

Maximum size to read at a time from a single file.

65536
FORCE_ENCODING =

MAXSLEEP = 2

!! (defined? Encoding)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, startpos = -1,, &block) ⇒ FileTail

Returns a new instance of FileTail.



72
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
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/em/filetail.rb', line 72

def initialize(path, startpos=-1, &block)
  @path = path
  @logger = Logger.new(STDERR)
  @logger.level = ($DEBUG and Logger::DEBUG or Logger::WARN)
  @logger.debug("Tailing #{path} starting at position #{startpos}")

  @file = nil
  @want_eof_handling = false
  @want_read = false
  @want_reopen = false
  @reopen_on_eof = false
  @symlink_timer = nil
  @missing_file_check_timer = nil
  @read_timer = nil
  @symlink_target = nil
  @symlink_stat = nil

  @symlink_check_interval = 1
  @missing_file_check_interval = 1

  

  if @filestat.directory?
    on_exception Errno::EISDIR.new(@path)
  end

  if block_given?
    @handler = block
    @buffer = BufferedTokenizer.new
  end

  EventMachine::next_tick do
    open
    next unless @file

    if (startpos == -1)
      @position = @file.sysseek(0, IO::SEEK_END)
      # TODO(sissel): if we don't have inotify or kqueue, should we
      # schedule a next read, here?
      # Is there a race condition between setting the file position and
      # watching given the two together are not atomic?
    else
      @position = @file.sysseek(startpos, IO::SEEK_SET)
      schedule_next_read
    end
    watch
  end # EventMachine::next_tick
end

Instance Attribute Details

#closedObject (readonly)

If this tail is closed



51
52
53
# File 'lib/em/filetail.rb', line 51

def closed
  @closed
end

#missing_file_check_intervalObject

Check interval for looking for a file if we are tailing it and it has gone missing.



59
60
61
# File 'lib/em/filetail.rb', line 59

def missing_file_check_interval
  @missing_file_check_interval
end

#pathObject (readonly)

The path of the file being tailed



45
46
47
# File 'lib/em/filetail.rb', line 45

def path
  @path
end

#positionObject (readonly)

The current file read position



48
49
50
# File 'lib/em/filetail.rb', line 48

def position
  @position
end

Check interval when checking symlinks for changes. This is only useful when you are actually tailing symlinks.



55
56
57
# File 'lib/em/filetail.rb', line 55

def symlink_check_interval
  @symlink_check_interval
end

Instance Method Details

#closeObject



208
209
210
211
212
213
214
215
216
217
218
# File 'lib/em/filetail.rb', line 208

def close
  @closed = true
  @want_read = false
  EM.schedule do
    @watch.stop_watching if @watch
    EventMachine::cancel_timer(@read_timer) if @read_timer
    @symlink_timer.cancel if @symlink_timer
    @missing_file_check_timer.cancel if @missing_file_check_timer
    @file.close if @file
  end
end

#closed?Boolean

Returns:

  • (Boolean)


222
223
224
# File 'lib/em/filetail.rb', line 222

def closed?
  @closed
end

#eofObject



162
163
164
165
# File 'lib/em/filetail.rb', line 162

def eof
  @logger.debug { 'EOF' }
  # do nothing, subclassers should implement this.
end

#on_exception(exception) ⇒ Object

def receive_data



151
152
153
154
# File 'lib/em/filetail.rb', line 151

def on_exception(exception)
  @logger.error("Exception raised. Using default handler in #{self.class.name}")
  raise exception
end

#receive_data(data) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/em/filetail.rb', line 139

def receive_data(data)
  if @handler # FileTail.new called with a block
    @buffer.extract(data).each do |line|
      @handler.call(self, line)
    end
  else
    on_exception NotImplementedError.new("#{self.class.name}#receive_data is not "\
      "implemented. Did you forget to implement this in your subclass or "\
      "module?")
  end
end