Module: File::Tail
- Included in:
- Logfile, FileTailGroupTest, FileTailTest
- Defined in:
- lib/file/tail.rb,
lib/file/tail/group.rb,
lib/file/tail/line_extension.rb,
lib/file/tail/logfile.rb,
lib/file/tail/tailer.rb,
lib/file/tail/version.rb
Overview
This module can be included in your own File subclasses or used to extend files you want to tail.
Defined Under Namespace
Modules: LineExtension Classes: BreakException, DeletedException, Group, Logfile, ReopenException, ReturnException, TailException, Tailer
Constant Summary collapse
- VERSION =
File::Tail version
'1.4.0'- VERSION_ARRAY =
:nodoc:
VERSION.split('.').map(&:to_i)
- VERSION_MAJOR =
:nodoc:
VERSION_ARRAY[0]
- VERSION_MINOR =
:nodoc:
VERSION_ARRAY[1]
- VERSION_BUILD =
:nodoc:
VERSION_ARRAY[2]
Instance Attribute Summary collapse
-
#break_if_eof ⇒ Object
If this attribute is set to a true value, File::Fail’s tail method raises a BreakException if the end of the file is reached.
-
#default_bufsize ⇒ Object
Default buffer size, that is used while going backward from a file’s end.
-
#interval ⇒ Object
The start value of the sleep interval.
-
#line_separator ⇒ Object
Override the default line separator.
-
#max_interval ⇒ Object
The maximum interval File::Tail sleeps, before it tries to take some action like reading the next few lines or reopening the file.
-
#reopen_deleted ⇒ Object
If this attribute is set to a true value, File::Tail persists on reopening a deleted file waiting
max_intervalseconds between the attempts. -
#reopen_suspicious ⇒ Object
If this attribute is set to a true value, File::Tail attempts to reopen it’s tailed file after
suspicious_intervalseconds of silence. -
#return_if_eof ⇒ Object
If this attribute is set to a true value, File::Fail’s tail method just returns if the end of the file is reached.
-
#suspicious_interval ⇒ Object
This attribute is the interval in seconds before File::Tail gets suspicious that something has happened to it’s tailed file and an attempt to reopen it is made.
Instance Method Summary collapse
-
#after_reopen(&block) ⇒ Object
The callback is called with self as an argument after a reopen has occurred.
-
#backward(n = 0, bufsize = nil) ⇒ Object
Rewind the last
nlines of this file, starting from the end. - #debug? ⇒ Boolean private
-
#forward(n = 0) ⇒ Object
Skip the first
nlines of this file. - #output_debug_information ⇒ Object private
- #preset_attributes ⇒ Object private
- #read_line(&block) ⇒ Object private
- #reopen_file(mode) ⇒ Object private
- #restat ⇒ Object private
- #sleep_interval ⇒ Object private
-
#tail(n = nil, &block) ⇒ Object
This method tails this file and yields to the given block for every new line that is read.
Instance Attribute Details
#break_if_eof ⇒ Object
If this attribute is set to a true value, File::Fail’s tail method raises a BreakException if the end of the file is reached.
86 87 88 |
# File 'lib/file/tail.rb', line 86 def break_if_eof @break_if_eof end |
#default_bufsize ⇒ Object
Default buffer size, that is used while going backward from a file’s end. This defaults to nil, which means that File::Tail attempts to derive this value from the filesystem block size.
95 96 97 |
# File 'lib/file/tail.rb', line 95 def default_bufsize @default_bufsize end |
#interval ⇒ Object
The start value of the sleep interval. This value goes against max_interval if the tailed file is silent for a sufficient time.
54 55 56 |
# File 'lib/file/tail.rb', line 54 def interval @interval end |
#line_separator ⇒ Object
Override the default line separator
98 99 100 |
# File 'lib/file/tail.rb', line 98 def line_separator @line_separator end |
#max_interval ⇒ Object
The maximum interval File::Tail sleeps, before it tries to take some action like reading the next few lines or reopening the file.
49 50 51 |
# File 'lib/file/tail.rb', line 49 def max_interval @max_interval end |
#reopen_deleted ⇒ Object
If this attribute is set to a true value, File::Tail persists on reopening a deleted file waiting max_interval seconds between the attempts. This is useful if logfiles are moved away while rotation occurs but are recreated at the same place after a while. It defaults to true.
61 62 63 |
# File 'lib/file/tail.rb', line 61 def reopen_deleted @reopen_deleted end |
#reopen_suspicious ⇒ Object
If this attribute is set to a true value, File::Tail attempts to reopen it’s tailed file after suspicious_interval seconds of silence.
66 67 68 |
# File 'lib/file/tail.rb', line 66 def reopen_suspicious @reopen_suspicious end |
#return_if_eof ⇒ Object
If this attribute is set to a true value, File::Fail’s tail method just returns if the end of the file is reached.
90 91 92 |
# File 'lib/file/tail.rb', line 90 def return_if_eof @return_if_eof end |
#suspicious_interval ⇒ Object
This attribute is the interval in seconds before File::Tail gets suspicious that something has happened to it’s tailed file and an attempt to reopen it is made.
If the attribute reopen_suspicious is set to a non true value, suspicious_interval is meaningless. It defaults to 60 seconds.
82 83 84 |
# File 'lib/file/tail.rb', line 82 def suspicious_interval @suspicious_interval end |
Instance Method Details
#after_reopen(&block) ⇒ Object
The callback is called with self as an argument after a reopen has occurred. This allows a tailing script to find out, if a logfile has been rotated.
71 72 73 |
# File 'lib/file/tail.rb', line 71 def after_reopen(&block) @after_reopen = block end |
#backward(n = 0, bufsize = nil) ⇒ Object
Rewind the last n lines of this file, starting from the end. The default is to start tailing directly from the end of the file.
The additional argument bufsize is used to determine the buffer size that is used to step through the file backwards. It defaults to the block size of the filesystem this file belongs to or 8192 bytes if this cannot be determined.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/file/tail.rb', line 121 def backward(n = 0, bufsize = nil) preset_attributes unless defined? @lines if n <= 0 seek(0, File::SEEK_END) return self end bufsize ||= default_bufsize || stat.blksize || 8192 size = stat.size begin if bufsize < size seek(0, File::SEEK_END) while n > 0 and tell > 0 do seek(-bufsize, File::SEEK_CUR) buffer = read(bufsize) n -= buffer.count(@line_separator) seek(-bufsize, File::SEEK_CUR) end else rewind buffer = read(size) n -= buffer.count(@line_separator) rewind end rescue Errno::EINVAL size = tell retry end pos = -1 while n < 0 # forward if we are too far back pos = buffer.index(@line_separator, pos + 1) n += 1 end seek(pos + 1, File::SEEK_CUR) self end |
#debug? ⇒ Boolean (private)
306 307 308 |
# File 'lib/file/tail.rb', line 306 def debug? ENV['FILE_TAIL_DEBUG'].to_i == 1 end |
#forward(n = 0) ⇒ Object
Skip the first n lines of this file. The default is to don’t skip any lines at all and start at the beginning of this file.
102 103 104 105 106 107 108 109 110 |
# File 'lib/file/tail.rb', line 102 def forward(n = 0) preset_attributes unless defined? @lines rewind while n > 0 and not eof? readline(@line_separator) n -= 1 end self end |
#output_debug_information ⇒ Object (private)
294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/file/tail.rb', line 294 def output_debug_information debug? or return STDERR.puts({ :path => path, :lines => @lines, :interval => @interval, :no_read => @no_read, :n => @n, }.inspect) self end |
#preset_attributes ⇒ Object (private)
225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/file/tail.rb', line 225 def preset_attributes @reopen_deleted = true unless defined? @reopen_deleted @reopen_suspicious = true unless defined? @reopen_suspicious @break_if_eof = false unless defined? @break_if_eof @return_if_eof = false unless defined? @return_if_eof @max_interval ||= 10 @line_separator ||= $/ @interval ||= @max_interval @suspicious_interval ||= 60 @lines = 0 @no_read = 0 @stat = nil end |
#read_line(&block) ⇒ Object (private)
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/file/tail.rb', line 198 def read_line(&block) if @n until @n == 0 block.call readline(@line_separator) @lines += 1 @no_read = 0 @n -= 1 output_debug_information end raise ReturnException else block.call readline(@line_separator) @lines += 1 @no_read = 0 output_debug_information end rescue EOFError seek(0, File::SEEK_CUR) raise ReopenException if @reopen_suspicious and @no_read > @suspicious_interval raise BreakException if @break_if_eof raise ReturnException if @return_if_eof sleep_interval rescue Errno::ENOENT, Errno::ESTALE, Errno::EBADF raise ReopenException end |
#reopen_file(mode) ⇒ Object (private)
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/file/tail.rb', line 276 def reopen_file(mode) debug? and $stdout.print "Reopening '#{path}', mode = #{mode}.\n" @no_read = 0 reopen(path) if mode == :bottom backward elsif mode == :top forward end rescue Errno::ESTALE, Errno::ENOENT if @reopen_deleted sleep @max_interval retry else raise DeletedException end end |
#restat ⇒ Object (private)
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/file/tail.rb', line 239 def restat stat = File.stat(path) if @stat if stat.ino != @stat.ino or stat.dev != @stat.dev @stat = nil raise ReopenException.new(:top) # File ino/dev has changed, start from top end if stat.size < @stat.size @stat = nil raise ReopenException.new(:top) # File shrunk, start from top end end @stat = stat rescue Errno::ENOENT raise ReopenException.new(:top) # File was missing, maybe it has been rotated, start from top rescue Errno::ESTALE raise ReopenException # File is stale let's try opening again with same mo end |
#sleep_interval ⇒ Object (private)
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/file/tail.rb', line 258 def sleep_interval if @lines > 0 # estimate how much time we will spend on waiting for next line @interval = (@interval.to_f / @lines) @lines = 0 else # exponential backoff if logfile is quiet @interval *= 2 end if @interval > @max_interval # max. wait @max_interval @interval = @max_interval end output_debug_information sleep @interval @no_read += @interval end |
#tail(n = nil, &block) ⇒ Object
This method tails this file and yields to the given block for every new line that is read. If no block is given an array of those lines is returned instead. (In this case it’s better to use a reasonable value for n or set the return_if_eof or break_if_eof attribute to a true value to stop the method call from blocking.)
If the argument n is given, only the next n lines are read and the method call returns. Otherwise this method call doesn’t return, but yields to block for every new line read from this file for ever.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/file/tail.rb', line 169 def tail(n = nil, &block) # :yields: line @n = n result = [] array_result = false unless block block = lambda { |line| result << line } array_result = true end preset_attributes unless defined? @lines loop do begin restat read_line(&block) redo rescue ReopenException => e until eof? || @n == 0 block.call readline(@line_separator) @n -= 1 if @n end reopen_file(e.mode) @after_reopen.call self if defined? @after_reopen rescue ReturnException return array_result ? result : nil end end end |