file-tail 0.1.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +10 -0
- data/Rakefile +21 -28
- data/VERSION +1 -1
- data/install.rb +7 -4
- data/lib/file/tail.rb +31 -28
- data/lib/file/tail/version.rb +10 -0
- data/tests/test_file-tail.rb +73 -0
- metadata +9 -7
data/CHANGES
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
2007-03-30 * 1.0.0 * Bugfix: David.Barzilay@swisscom.com reported, that file
|
2
|
+
tails may skip some log file lines, after rotating it. I
|
3
|
+
think, І fixed that problem.
|
4
|
+
I added a after_reopen callback as well, that is called
|
5
|
+
after reopening of the tailed file has occured.
|
6
|
+
* Removed rewind/wind methods even earlier than planned: I
|
7
|
+
placed the deprecation warning for rewind method in File
|
8
|
+
instead of File::Tail, which caused rewind to stop working
|
9
|
+
completely after loading file/tail. Duh! I blame vim's
|
10
|
+
matchit, because it jumped to the wrong end keyword.
|
1
11
|
2007-02-08 * 0.1.4 * Renamed rewind method to backward, and wind method to
|
2
12
|
forward, because someone already had the good idea to name
|
3
13
|
a method IO#rewind, which was overwritten by the mixed in
|
data/Rakefile
CHANGED
@@ -36,45 +36,19 @@ task :clean do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
spec = Gem::Specification.new do |s|
|
39
|
-
|
40
|
-
#### Basic information.
|
41
|
-
|
42
39
|
s.name = 'file-tail'
|
43
40
|
s.version = PKG_VERSION
|
44
41
|
s.summary = "File::Tail for Ruby"
|
45
42
|
s.description = "Library to tail files in Ruby"
|
46
43
|
|
47
|
-
#### Dependencies and requirements.
|
48
|
-
|
49
|
-
#s.add_dependency('log4r', '> 1.0.4')
|
50
|
-
#s.requirements << ""
|
51
|
-
|
52
44
|
s.files = PKG_FILES
|
53
45
|
|
54
|
-
|
55
|
-
|
56
|
-
#s.extensions << "ext/extconf.rb"
|
57
|
-
|
58
|
-
#### Load-time details: library and application (you will need one or both).
|
59
|
-
|
60
|
-
s.require_path = 'lib' # Use these for libraries.
|
61
|
-
#s.autorequire = 'file/tail'
|
62
|
-
|
63
|
-
#s.bindir = "bin" # Use these for applications.
|
64
|
-
#s.executables = ["bla.rb"]
|
65
|
-
#s.default_executable = "bla.rb"
|
66
|
-
|
67
|
-
#### Documentation and testing.
|
46
|
+
s.require_path = 'lib'
|
68
47
|
|
69
48
|
s.has_rdoc = true
|
70
|
-
|
71
|
-
s.rdoc_options <<
|
72
|
-
'--title' << 'File::Tail' <<
|
73
|
-
# '--line-numbers'
|
49
|
+
s.rdoc_options << '--title' << 'File::Tail' << '--line-numbers'
|
74
50
|
s.test_files << 'tests/test_file-tail.rb'
|
75
51
|
|
76
|
-
#### Author and project details.
|
77
|
-
|
78
52
|
s.author = "Florian Frank"
|
79
53
|
s.email = "flori@ping.de"
|
80
54
|
s.homepage = "http://file-tail.rubyforge.org"
|
@@ -86,4 +60,23 @@ Rake::GemPackageTask.new(spec) do |pkg|
|
|
86
60
|
pkg.package_files += PKG_FILES
|
87
61
|
end
|
88
62
|
|
63
|
+
desc m = "Writing version information for #{PKG_VERSION}"
|
64
|
+
task :version do
|
65
|
+
puts m
|
66
|
+
File.open(File.join('lib', 'file', 'tail', 'version.rb'), 'w') do |v|
|
67
|
+
v.puts <<EOT
|
68
|
+
class File
|
69
|
+
module Tail
|
70
|
+
# File::Tail version
|
71
|
+
VERSION = '#{PKG_VERSION}'
|
72
|
+
VERSION_ARRAY = VERSION.split(/\\./).map { |x| x.to_i } # :nodoc:
|
73
|
+
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
|
74
|
+
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
|
75
|
+
VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
|
76
|
+
end
|
77
|
+
end
|
78
|
+
EOT
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
89
82
|
task :release => [ :clean, :package ]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/install.rb
CHANGED
@@ -8,12 +8,15 @@ include Config
|
|
8
8
|
|
9
9
|
cd 'lib' do
|
10
10
|
libdir = CONFIG["sitelibdir"]
|
11
|
-
subdir = 'file'
|
12
|
-
filename = 'tail.rb'
|
13
11
|
|
14
|
-
dest = File.join(libdir,
|
12
|
+
dest = File.join(libdir, 'file')
|
15
13
|
mkdir_p(dest)
|
16
|
-
file = File.join('file',
|
14
|
+
file = File.join('file', 'tail.rb')
|
15
|
+
install(file, dest)
|
16
|
+
|
17
|
+
dest = File.join(dest, 'tail')
|
18
|
+
mkdir_p(dest)
|
19
|
+
file = File.join('file', 'tail', 'version.rb')
|
17
20
|
install(file, dest)
|
18
21
|
end
|
19
22
|
# vim: set et sw=2 ts=2:
|
data/lib/file/tail.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#
|
2
|
+
require 'file/tail/version'
|
2
3
|
# = File::Tail - Tailing files in Ruby
|
3
4
|
#
|
4
5
|
# == Description
|
@@ -92,8 +93,11 @@ class File
|
|
92
93
|
# in the logfile for 10 lines at the start. The buffersize
|
93
94
|
# for going backwards can be set with the
|
94
95
|
# * <code>:bufsiz => 8192</code> option.
|
95
|
-
#
|
96
|
-
# <code>:
|
96
|
+
# To define a callback, that will be called after a reopening occurs, use:
|
97
|
+
# * <code>:after_reopen => lambda { |file| p file }</code>
|
98
|
+
#
|
99
|
+
# Every attribute of File::Tail can be set with a <code>:attributename =>
|
100
|
+
# value</code> option.
|
97
101
|
def self.open(filename, opts = {}) # :yields: file
|
98
102
|
file = new filename
|
99
103
|
opts.each do |o, v|
|
@@ -111,6 +115,9 @@ class File
|
|
111
115
|
elsif forward = opts[:forward] || opts[:wind]
|
112
116
|
file.forward(forward)
|
113
117
|
end
|
118
|
+
if opts[:after_reopen]
|
119
|
+
file.after_reopen &opts[:after_reopen]
|
120
|
+
end
|
114
121
|
if block_given?
|
115
122
|
yield file
|
116
123
|
nil
|
@@ -187,6 +194,13 @@ class File
|
|
187
194
|
# <code>suspicious_interval</code> seconds of silence.
|
188
195
|
attr_accessor :reopen_suspicious
|
189
196
|
|
197
|
+
# The callback is called with _self_ as an argument after a reopen has
|
198
|
+
# occured. This allows a tailing script to find out, if a logfile has been
|
199
|
+
# rotated.
|
200
|
+
def after_reopen(&block)
|
201
|
+
@after_reopen = block
|
202
|
+
end
|
203
|
+
|
190
204
|
# This attribute is the invterval in seconds before File::Tail
|
191
205
|
# gets suspicious that something has happend to it's tailed file
|
192
206
|
# and an attempt to reopen it is made.
|
@@ -215,12 +229,6 @@ class File
|
|
215
229
|
self
|
216
230
|
end
|
217
231
|
|
218
|
-
# The wind method is deprecated, use forward instead.
|
219
|
-
def wind(*args)
|
220
|
-
warn "File::Tail#wind method is deprecated, use forward instead"
|
221
|
-
forward *args
|
222
|
-
end
|
223
|
-
|
224
232
|
# Rewind the last <code>n</code> lines of this file, starting
|
225
233
|
# from the end. The default is to start tailing directly from the
|
226
234
|
# end of the file.
|
@@ -279,6 +287,7 @@ class File
|
|
279
287
|
# call doesn't return, but yields to block for every new line read from
|
280
288
|
# this file for ever.
|
281
289
|
def tail(n = nil, &block) # :yields: line
|
290
|
+
@n = n
|
282
291
|
result = []
|
283
292
|
array_result = false
|
284
293
|
unless block
|
@@ -289,10 +298,15 @@ class File
|
|
289
298
|
loop do
|
290
299
|
begin
|
291
300
|
restat
|
292
|
-
read_line(
|
301
|
+
read_line(&block)
|
293
302
|
redo
|
294
303
|
rescue ReopenException => e
|
304
|
+
until eof? || @n == 0
|
305
|
+
block.call readline
|
306
|
+
@n -= 1 if @n
|
307
|
+
end
|
295
308
|
reopen_file(e.mode)
|
309
|
+
@after_reopen.call self if @after_reopen
|
296
310
|
rescue ReturnException
|
297
311
|
return array_result ? result : nil
|
298
312
|
end
|
@@ -301,12 +315,13 @@ class File
|
|
301
315
|
|
302
316
|
private
|
303
317
|
|
304
|
-
def read_line
|
305
|
-
if n
|
306
|
-
n
|
318
|
+
def read_line
|
319
|
+
if @n
|
320
|
+
until @n == 0
|
307
321
|
yield readline
|
308
322
|
@lines += 1
|
309
323
|
@no_read = 0
|
324
|
+
@n -= 1
|
310
325
|
debug
|
311
326
|
end
|
312
327
|
raise ReturnException
|
@@ -323,8 +338,7 @@ class File
|
|
323
338
|
raise BreakException if @break_if_eof
|
324
339
|
raise ReturnException if @return_if_eof
|
325
340
|
sleep_interval
|
326
|
-
rescue Errno::ENOENT
|
327
|
-
rescue Errno::ESTALE
|
341
|
+
rescue Errno::ENOENT, Errno::ESTALE
|
328
342
|
raise ReopenException
|
329
343
|
end
|
330
344
|
|
@@ -354,8 +368,7 @@ class File
|
|
354
368
|
else
|
355
369
|
@stat = stat
|
356
370
|
end
|
357
|
-
rescue Errno::ENOENT
|
358
|
-
rescue Errno::ESTALE
|
371
|
+
rescue Errno::ENOENT, Errno::ESTALE
|
359
372
|
raise ReopenException
|
360
373
|
end
|
361
374
|
|
@@ -384,8 +397,7 @@ class File
|
|
384
397
|
if mode == :bottom
|
385
398
|
backward
|
386
399
|
end
|
387
|
-
rescue Errno::ESTALE
|
388
|
-
rescue Errno::ENOENT
|
400
|
+
rescue Errno::ESTALE, Errno::ENOENT
|
389
401
|
if @reopen_deleted
|
390
402
|
sleep @max_interval
|
391
403
|
retry
|
@@ -400,20 +412,11 @@ class File
|
|
400
412
|
:lines => @lines,
|
401
413
|
:interval => @interval,
|
402
414
|
:no_read => @no_read,
|
415
|
+
:n => @n,
|
403
416
|
}
|
404
417
|
$stderr.print h.inspect, "\n"
|
405
418
|
end
|
406
419
|
end
|
407
|
-
|
408
|
-
# The rewind method is deprecated and will be removed soon, use backward
|
409
|
-
# instead. At the moment rewind accidentially overwrites the IO#rewind
|
410
|
-
# method, after the removal of the ol rewind mixin method, this will be no
|
411
|
-
# longer the case.
|
412
|
-
def rewind(*args)
|
413
|
-
warn "File::Tail#rewind method is deprecated and will be removed soon, "\
|
414
|
-
"use backward instead"
|
415
|
-
backward *args
|
416
|
-
end
|
417
420
|
end
|
418
421
|
|
419
422
|
if $0 == __FILE__
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class File
|
2
|
+
module Tail
|
3
|
+
# File::Tail version
|
4
|
+
VERSION = '0.1.5'
|
5
|
+
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
|
6
|
+
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
|
7
|
+
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
|
8
|
+
VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
|
9
|
+
end
|
10
|
+
end
|
data/tests/test_file-tail.rb
CHANGED
@@ -176,6 +176,8 @@ class TC_FileTail < Test::Unit::TestCase
|
|
176
176
|
def test_tail_remove
|
177
177
|
return if File::PATH_SEPARATOR == ';' # Grmpf! Windows...
|
178
178
|
@in.backward
|
179
|
+
reopened = false
|
180
|
+
@in.after_reopen { |f| reopened = true }
|
179
181
|
lines = []
|
180
182
|
threads = []
|
181
183
|
threads << appender = Thread.new do
|
@@ -198,6 +200,77 @@ class TC_FileTail < Test::Unit::TestCase
|
|
198
200
|
end
|
199
201
|
threads.collect { |t| t.wakeup and t.join }
|
200
202
|
assert_equal(10, lines.size)
|
203
|
+
assert reopened
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_tail_remove2
|
207
|
+
return if File::PATH_SEPARATOR == ';' # Grmpf! Windows...
|
208
|
+
@in.backward
|
209
|
+
reopened = false
|
210
|
+
@in.after_reopen { |f| reopened = true }
|
211
|
+
lines = []
|
212
|
+
threads = []
|
213
|
+
threads << appender = Thread.new do
|
214
|
+
Thread.stop
|
215
|
+
@out.close
|
216
|
+
File.unlink(@out.path)
|
217
|
+
@out = File.new(@in.path, "wb")
|
218
|
+
append(@out, 10)
|
219
|
+
sleep 1
|
220
|
+
append(@out, 10)
|
221
|
+
File.unlink(@out.path)
|
222
|
+
@out = File.new(@in.path, "wb")
|
223
|
+
append(@out, 10)
|
224
|
+
end
|
225
|
+
threads << Thread.new do
|
226
|
+
begin
|
227
|
+
timeout(2) do
|
228
|
+
@in.tail do |l|
|
229
|
+
lines << l
|
230
|
+
lines.size == 100 and appender.wakeup
|
231
|
+
end
|
232
|
+
end
|
233
|
+
rescue TimeoutError
|
234
|
+
end
|
235
|
+
end
|
236
|
+
threads.collect { |t| t.wakeup and t.join }
|
237
|
+
assert_equal(30, lines.size)
|
238
|
+
assert reopened
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_tail_remove3
|
242
|
+
return if File::PATH_SEPARATOR == ';' # Grmpf! Windows...
|
243
|
+
@in.backward
|
244
|
+
reopened = false
|
245
|
+
@in.after_reopen { |f| reopened = true }
|
246
|
+
lines = []
|
247
|
+
threads = []
|
248
|
+
threads << appender = Thread.new do
|
249
|
+
Thread.stop
|
250
|
+
@out.close
|
251
|
+
File.unlink(@out.path)
|
252
|
+
@out = File.new(@in.path, "wb")
|
253
|
+
append(@out, 10)
|
254
|
+
sleep 1
|
255
|
+
append(@out, 10)
|
256
|
+
File.unlink(@out.path)
|
257
|
+
@out = File.new(@in.path, "wb")
|
258
|
+
append(@out, 10)
|
259
|
+
end
|
260
|
+
threads << Thread.new do
|
261
|
+
begin
|
262
|
+
timeout(2) do
|
263
|
+
@in.tail(15) do |l|
|
264
|
+
lines << l
|
265
|
+
lines.size == 100 and appender.wakeup
|
266
|
+
end
|
267
|
+
end
|
268
|
+
rescue TimeoutError
|
269
|
+
end
|
270
|
+
end
|
271
|
+
threads.collect { |t| t.wakeup and t.join }
|
272
|
+
assert_equal(15, lines.size)
|
273
|
+
assert reopened
|
201
274
|
end
|
202
275
|
|
203
276
|
def teardown
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.
|
2
|
+
rubygems_version: 0.9.2
|
3
3
|
specification_version: 1
|
4
4
|
name: file-tail
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2007-04-01 00:00:00 +02:00
|
8
8
|
summary: File::Tail for Ruby
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -25,6 +25,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
25
25
|
platform: ruby
|
26
26
|
signing_key:
|
27
27
|
cert_chain:
|
28
|
+
post_install_message:
|
28
29
|
authors:
|
29
30
|
- Florian Frank
|
30
31
|
files:
|
@@ -41,14 +42,15 @@ files:
|
|
41
42
|
- examples/pager.rb
|
42
43
|
- examples/tail.rb
|
43
44
|
- lib/file
|
45
|
+
- lib/file/tail
|
44
46
|
- lib/file/tail.rb
|
45
|
-
|
46
|
-
|
47
|
+
- lib/file/tail/version.rb
|
48
|
+
test_files:
|
49
|
+
- tests/test_file-tail.rb
|
47
50
|
rdoc_options:
|
48
51
|
- --title
|
49
52
|
- File::Tail
|
50
|
-
-
|
51
|
-
- tests/test_file-tail.rb
|
53
|
+
- --line-numbers
|
52
54
|
extra_rdoc_files: []
|
53
55
|
|
54
56
|
executables: []
|