gilmour 0.3.2 → 0.3.3
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.
- checksums.yaml +4 -4
- data/examples/fork_log_server.rb +97 -0
- data/lib/gilmour/backends/redis.rb +0 -7
- data/lib/gilmour/responder.rb +45 -60
- data/lib/gilmour/waiter.rb +8 -3
- data/version.rb +1 -1
- metadata +3 -3
- data/lib/gilmour/stdhijack.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7927c5fb1c94d36f7ae85c605d16b3e715cc215a
|
4
|
+
data.tar.gz: b57d2ca7464355623376c35faa04e2e0adbc133b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 088587c3aea578730a2926698cd952d76e101abd6e1c5e99e57459116407bc5cc27d68d91b9ceaec64fb0412718da5ad4e620859b81bd5f638af102faa82ad29
|
7
|
+
data.tar.gz: 80fe912c98305251b4871be44e10f4c8ee9551e185cfb7c4c31b9bff86289cbdbae905a03309754bff0f53a58a22d3842aa280a7cb4fc2bca25a59e4ffd9440b
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative '../lib/gilmour'
|
3
|
+
|
4
|
+
class EventServer
|
5
|
+
include Gilmour::Base
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
backend = 'redis'
|
9
|
+
enable_backend(backend, { })
|
10
|
+
registered_subscribers.each do |sub|
|
11
|
+
sub.backend = backend
|
12
|
+
end
|
13
|
+
$stderr.puts "Starting server. To see messaging in action run clients."
|
14
|
+
start(true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class EchoSubscriber < EventServer
|
19
|
+
class << self
|
20
|
+
def capture_output(pipe)
|
21
|
+
streams = [$stdout, $stderr]
|
22
|
+
|
23
|
+
# Save the streams to be reassigned later.
|
24
|
+
# Actually it doesn't matter because the child process would be killed
|
25
|
+
# anyway after the work is done.
|
26
|
+
saved = streams.collect { |stream| stream.dup }
|
27
|
+
|
28
|
+
begin
|
29
|
+
streams.each_with_index do |stream, ix|
|
30
|
+
# Probably I should not use IX, otherwise stdout and stderr can arrive
|
31
|
+
# out of order, which they should?
|
32
|
+
# If I reopen both of them on the same PIPE, they are guaranteed to
|
33
|
+
# arrive in order.
|
34
|
+
stream.reopen(pipe)
|
35
|
+
#stream.sync = true
|
36
|
+
end
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
# This is sort of meaningless, just makes sense aesthetically.
|
40
|
+
# To return what was borrowed.
|
41
|
+
streams.each_with_index do |stream, i|
|
42
|
+
stream.reopen(saved[i])
|
43
|
+
end
|
44
|
+
pipe.close unless pipe.closed?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def ds_respond(topic, opts={}, &blk)
|
49
|
+
options = { exclusive: true, fork: true }.merge(opts)
|
50
|
+
listen_to topic, options do
|
51
|
+
logger.error "Captuting output before execution"
|
52
|
+
|
53
|
+
waiter = Gilmour::Waiter.new
|
54
|
+
waiter.add 1
|
55
|
+
read_pipe, write_pipe = IO.pipe
|
56
|
+
|
57
|
+
th = Thread.new {
|
58
|
+
loop {
|
59
|
+
begin
|
60
|
+
result = read_pipe.readline.chomp
|
61
|
+
logger.debug result
|
62
|
+
rescue EOFError
|
63
|
+
waiter.done
|
64
|
+
rescue Exception => e
|
65
|
+
logger.error "Error: #{e.message}"
|
66
|
+
logger.error "Traceback: #{e.backtrace}"
|
67
|
+
end
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
EchoSubscriber::capture_output(write_pipe) do
|
72
|
+
instance_eval(&blk)
|
73
|
+
end
|
74
|
+
|
75
|
+
waiter.wait do
|
76
|
+
th.kill
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Passing second parameter as true makes only one instance of this handler handle a request
|
84
|
+
EchoSubscriber::ds_respond 'echo.*' do
|
85
|
+
if request.body == 'Palmolive'
|
86
|
+
respond nil
|
87
|
+
else
|
88
|
+
logger.error "logger: #{request.body}"
|
89
|
+
$stderr.puts "stderr.puts: #{request.body}"
|
90
|
+
puts "stdout.puts #{request.body}"
|
91
|
+
respond "#{request.topic}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
EventServer.new
|
@@ -42,9 +42,6 @@ module Gilmour
|
|
42
42
|
@report_errors = opts["broadcast_errors"] || opts[:broadcast_errors]
|
43
43
|
@report_errors = true if @report_errors != false
|
44
44
|
|
45
|
-
@capture_stdout = opts["capture_stdout"] || opts[:capture_stdout]
|
46
|
-
@capture_stdout = false if @capture_stdout != true
|
47
|
-
|
48
45
|
@ident = generate_ident
|
49
46
|
end
|
50
47
|
|
@@ -56,10 +53,6 @@ module Gilmour
|
|
56
53
|
"#{Socket.gethostname}-pid-#{Process.pid}-uuid-#{SecureRandom.uuid}"
|
57
54
|
end
|
58
55
|
|
59
|
-
def capture_stdout?
|
60
|
-
@capture_stdout
|
61
|
-
end
|
62
|
-
|
63
56
|
def report_health?
|
64
57
|
@report_health
|
65
58
|
end
|
data/lib/gilmour/responder.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'logger'
|
5
|
-
require_relative './stdhijack'
|
6
5
|
require_relative './waiter'
|
7
6
|
|
8
7
|
# Top level module
|
@@ -28,12 +27,16 @@ module Gilmour
|
|
28
27
|
attr_reader :logger
|
29
28
|
attr_reader :request
|
30
29
|
|
31
|
-
def fork_logger
|
30
|
+
def fork_logger(io_writer)
|
32
31
|
logger = Logger.new(STDERR)
|
33
32
|
loglevel = ENV["LOG_LEVEL"] ? ENV["LOG_LEVEL"].to_sym : :warn
|
34
33
|
logger.level = Gilmour::LoggerLevels[loglevel] || Logger::WARN
|
34
|
+
logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
35
35
|
logger.formatter = proc do |severity, datetime, progname, msg|
|
36
|
-
"#{LOG_PREFIX}#{severity}#{LOG_SEPERATOR}#{msg}"
|
36
|
+
data = "#{LOG_PREFIX}#{severity}#{LOG_SEPERATOR}#{msg}"
|
37
|
+
io_writer.write(data+"\n")
|
38
|
+
io_writer.flush
|
39
|
+
nil
|
37
40
|
end
|
38
41
|
logger
|
39
42
|
end
|
@@ -43,6 +46,7 @@ module Gilmour
|
|
43
46
|
original_formatter = Logger::Formatter.new
|
44
47
|
loglevel = ENV["LOG_LEVEL"] ? ENV["LOG_LEVEL"].to_sym : :warn
|
45
48
|
logger.level = Gilmour::LoggerLevels[loglevel] || Logger::WARN
|
49
|
+
logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
46
50
|
logger.formatter = proc do |severity, datetime, progname, msg|
|
47
51
|
original_formatter.call(severity, datetime, @sender, msg)
|
48
52
|
end
|
@@ -59,7 +63,6 @@ module Gilmour
|
|
59
63
|
@pipe = IO.pipe
|
60
64
|
@publish_pipe = IO.pipe
|
61
65
|
@logger = make_logger()
|
62
|
-
@capture_stdout = @backend.capture_stdout? || false
|
63
66
|
end
|
64
67
|
|
65
68
|
def receive_data(data)
|
@@ -116,59 +119,50 @@ module Gilmour
|
|
116
119
|
}
|
117
120
|
end
|
118
121
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
data
|
128
|
-
|
129
|
-
next
|
130
|
-
end
|
131
|
-
|
132
|
-
if data.start_with?(LOG_PREFIX)
|
133
|
-
data.split(LOG_PREFIX).each do |msg|
|
122
|
+
# All logs in forked mode are relayed chr
|
123
|
+
def child_io_relay(io_reader, waiter, parent_logger)
|
124
|
+
Thread.new {
|
125
|
+
waiter.add 1
|
126
|
+
loop {
|
127
|
+
begin
|
128
|
+
data = io_reader.readline.chomp
|
129
|
+
if data.start_with?(LOG_PREFIX)
|
130
|
+
data.split(LOG_PREFIX).each do |msg|
|
131
|
+
unless msg.empty?
|
134
132
|
msg_grp = msg.split(LOG_SEPERATOR, 2)
|
135
|
-
|
136
133
|
if msg_grp.length > 1
|
137
134
|
data = msg_grp[1]
|
138
135
|
case msg_grp[0]
|
139
136
|
when 'INFO'
|
140
|
-
|
137
|
+
parent_logger.info data
|
141
138
|
when 'UNKNOWN'
|
142
|
-
|
139
|
+
parent_logger.unknown data
|
143
140
|
when 'WARN'
|
144
|
-
|
141
|
+
parent_logger.warn data
|
145
142
|
when 'ERROR'
|
146
|
-
|
143
|
+
parent_logger.error data
|
147
144
|
when 'FATAL'
|
148
|
-
|
145
|
+
parent_logger.fatal data
|
149
146
|
else
|
150
|
-
|
147
|
+
parent_logger.debug data
|
151
148
|
end
|
152
149
|
else
|
153
|
-
|
150
|
+
parent_logger.debug msg
|
154
151
|
end
|
155
|
-
|
156
152
|
end
|
157
|
-
next
|
158
153
|
end
|
159
|
-
|
160
|
-
logger.debug data
|
161
|
-
rescue EOFError
|
162
|
-
waiter.done
|
163
|
-
rescue Exception => e
|
164
|
-
GLogger.error e.message
|
165
|
-
GLogger.error e.backtrace
|
154
|
+
next
|
166
155
|
end
|
167
|
-
}
|
168
|
-
}
|
169
|
-
end
|
170
156
|
|
171
|
-
|
157
|
+
parent_logger.debug data
|
158
|
+
rescue EOFError
|
159
|
+
waiter.done
|
160
|
+
rescue Exception => e
|
161
|
+
GLogger.error e.message
|
162
|
+
GLogger.error e.backtrace
|
163
|
+
end
|
164
|
+
}
|
165
|
+
}
|
172
166
|
end
|
173
167
|
|
174
168
|
# Called by parent
|
@@ -180,15 +174,12 @@ module Gilmour
|
|
180
174
|
@read_pipe, @write_pipe = @pipe
|
181
175
|
@read_publish_pipe, @write_publish_pipe = @publish_pipe
|
182
176
|
|
183
|
-
|
184
|
-
parent_io = [out_r]
|
185
|
-
child_io = [out_w]
|
177
|
+
io_reader, io_writer = IO.pipe
|
186
178
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
end
|
179
|
+
wg = Gilmour::Waiter.new
|
180
|
+
io_threads = []
|
181
|
+
io_threads << child_io_relay(io_reader, wg, @logger)
|
182
|
+
io_threads << pub_relay(wg)
|
192
183
|
|
193
184
|
pid = Process.fork do
|
194
185
|
@backend.stop
|
@@ -197,26 +188,20 @@ module Gilmour
|
|
197
188
|
#Close the parent channels in forked process
|
198
189
|
@read_pipe.close
|
199
190
|
@read_publish_pipe.close
|
200
|
-
|
191
|
+
io_reader.close unless io_reader.closed?
|
201
192
|
|
202
193
|
@response_sent = false
|
203
|
-
@logger = fork_logger
|
204
194
|
|
205
|
-
|
206
|
-
|
207
|
-
|
195
|
+
@logger = fork_logger(io_writer)
|
196
|
+
_execute(handler)
|
197
|
+
io_writer.close
|
208
198
|
end
|
209
199
|
|
210
200
|
# Cleanup the writers in Parent process.
|
211
|
-
|
212
|
-
|
201
|
+
io_writer.close
|
213
202
|
@write_pipe.close
|
214
203
|
@write_publish_pipe.close
|
215
204
|
|
216
|
-
wg = Gilmour::Waiter.new
|
217
|
-
io_threads = io_readers(parent_io, wg)
|
218
|
-
io_threads << pub_relay(wg)
|
219
|
-
|
220
205
|
begin
|
221
206
|
receive_data(@read_pipe.readline)
|
222
207
|
rescue EOFError => e
|
@@ -248,7 +233,7 @@ module Gilmour
|
|
248
233
|
|
249
234
|
# Cleanup.
|
250
235
|
@read_publish_pipe.close
|
251
|
-
|
236
|
+
io_reader.close unless io_reader.closed?
|
252
237
|
|
253
238
|
else
|
254
239
|
_execute(handler)
|
data/lib/gilmour/waiter.rb
CHANGED
@@ -13,9 +13,10 @@ module Gilmour
|
|
13
13
|
|
14
14
|
def done
|
15
15
|
synchronize do
|
16
|
-
@count -=
|
16
|
+
@count -= 1
|
17
17
|
if @count == 0
|
18
|
-
|
18
|
+
@done = true
|
19
|
+
@waiter_c.broadcast
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
@@ -33,7 +34,11 @@ module Gilmour
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def wait(timeout=nil)
|
36
|
-
synchronize
|
37
|
+
synchronize do
|
38
|
+
while !@done
|
39
|
+
@waiter_c.wait(@waiter_m, timeout)
|
40
|
+
end
|
41
|
+
end
|
37
42
|
yield if block_given?
|
38
43
|
end
|
39
44
|
end
|
data/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gilmour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aditya Godbole
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
12
|
+
date: 2015-07-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- LICENSE
|
111
111
|
- README.md
|
112
112
|
- examples/echoclient.rb
|
113
|
+
- examples/fork_log_server.rb
|
113
114
|
- examples/server.rb
|
114
115
|
- examples/thread_example.rb
|
115
116
|
- gilmour.gemspec
|
@@ -119,7 +120,6 @@ files:
|
|
119
120
|
- lib/gilmour/base.rb
|
120
121
|
- lib/gilmour/protocol.rb
|
121
122
|
- lib/gilmour/responder.rb
|
122
|
-
- lib/gilmour/stdhijack.rb
|
123
123
|
- lib/gilmour/waiter.rb
|
124
124
|
- test/spec/helpers/common.rb
|
125
125
|
- test/spec/helpers/connection.rb
|
data/lib/gilmour/stdhijack.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# StringIO also do as IO, but IO#reopen fails.
|
2
|
-
# The problem is that a StringIO cannot exist in the O/S's file descriptor
|
3
|
-
# table. STDERR.reopen(...) at the low level does a dup() or dup2() to
|
4
|
-
# copy one file descriptor to another.
|
5
|
-
#
|
6
|
-
# I have two options:
|
7
|
-
#
|
8
|
-
# (1) $stderr = StringIO.new
|
9
|
-
# Then any program which writes to $stderr will be fine. But anything
|
10
|
-
# which writes to STDERR will still go to file descriptor 2.
|
11
|
-
#
|
12
|
-
# (2) reopen STDERR with something which exists in the O/S file descriptor
|
13
|
-
# table: e.g. a file or a pipe.
|
14
|
-
#
|
15
|
-
# I canot use a file, hence a Pipe.
|
16
|
-
|
17
|
-
def capture_output(pipes, capture_stdout=false)
|
18
|
-
streams = []
|
19
|
-
|
20
|
-
if capture_stdout == true
|
21
|
-
streams << STDOUT
|
22
|
-
end
|
23
|
-
|
24
|
-
streams << STDERR
|
25
|
-
|
26
|
-
# Save the streams to be reassigned later.
|
27
|
-
# Actually it doesn't matter because the child process would be killed
|
28
|
-
# anyway after the work is done.
|
29
|
-
saved = streams.each do |stream|
|
30
|
-
stream.dup
|
31
|
-
end
|
32
|
-
|
33
|
-
begin
|
34
|
-
streams.each_with_index do |stream, ix|
|
35
|
-
# Probably I should not use IX, otherwise stdout and stderr can arrive
|
36
|
-
# out of order, which they should?
|
37
|
-
# If I reopen both of them on the same PIPE, they are guaranteed to
|
38
|
-
# arrive in order.
|
39
|
-
stream.reopen(pipes[ix])
|
40
|
-
end
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
# This is sort of meaningless, just makes sense aesthetically.
|
44
|
-
# To return what was borrowed.
|
45
|
-
streams.each_with_index do |stream, i|
|
46
|
-
stream.reopen(saved[i])
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|