file-tail 0.1.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|