1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
60
61
62
63
64
65
66
67
68
69
70
71
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
| | #!/usr/bin/env rackup -s thin
#
# async_tailer.ru
# raggi/thin
#
# Tested with 150 spawned tails on OS X
#
# Created by James Tucker on 2008-06-18.
# Copyright 2008 James Tucker <raggi@rubyforge.org>.
# Uncomment if appropriate for you..
# EM.epoll
# EM.kqueue
tail_log_file = ENV["TAIL_LOG_FILE"] or abort "TAIL_LOG_FILE= env must be set"
unless ::File.file?(tail_log_file) && ::File.readable?(tail_log_file)
abort "#{tail_log_file} must be a readable regular file"
end
class DeferrableBody
include EventMachine::Deferrable
def initialize
@queue = []
# make sure to flush out the queue before closing the connection
callback{
until @queue.empty?
@queue.shift.each{|chunk| @body_callback.call(chunk) }
end
}
end
def schedule_dequeue
return unless @body_callback
EventMachine::next_tick do
next unless body = @queue.shift
body.each do |chunk|
@body_callback.call(chunk)
end
schedule_dequeue unless @queue.empty?
end
end
def call(body)
@queue << body
schedule_dequeue
end
def each &blk
@body_callback = blk
schedule_dequeue
end
end
module TailRenderer
attr_accessor :callback
def receive_data(data)
@callback.call([data])
end
def unbind
@callback.succeed
end
end
class AsyncTailer
AsyncResponse = [-1, {}, []].freeze
def call(env)
body = DeferrableBody.new
EventMachine::next_tick do
env['async.callback'].call [200, {'Content-Type' => 'text/html'}, body]
body.call ["<h1>Async Tailer</h1><pre>"]
end
EventMachine::popen("tail -f #{ENV["TAIL_LOG_FILE"]}", TailRenderer) do |t|
t.callback = body
# If for some reason we 'complete' body, close the tail.
body.callback do
t.close_connection
end
# If for some reason the client disconnects, close the tail.
body.errback do
t.close_connection
end
end
AsyncResponse
end
end
run AsyncTailer.new
|