instrumental_agent 0.3.0 → 0.4.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/lib/instrumental/agent.rb +73 -38
- data/lib/instrumental/version.rb +1 -1
- data/spec/agent_spec.rb +16 -1
- data/spec/test_server.rb +13 -8
- metadata +4 -4
data/lib/instrumental/agent.rb
CHANGED
@@ -20,8 +20,8 @@ module Instrumental
|
|
20
20
|
@logger = l
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.logger
|
24
|
-
@logger ||= Logger.new('/dev/null')
|
23
|
+
def self.logger(force = false)
|
24
|
+
@logger ||= Logger.new(File.open('/dev/null', 'a')) # append mode so it's forksafe
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.all
|
@@ -52,11 +52,14 @@ module Instrumental
|
|
52
52
|
@port = (collector[1] || 8000).to_i
|
53
53
|
@enabled = options[:enabled]
|
54
54
|
@test_mode = options[:test_mode]
|
55
|
+
@pid = Process.pid
|
56
|
+
|
55
57
|
|
56
58
|
if @enabled
|
57
59
|
@failures = 0
|
58
60
|
@queue = Queue.new
|
59
|
-
|
61
|
+
start_connection_worker
|
62
|
+
setup_cleanup_at_exit
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
@@ -95,7 +98,7 @@ module Instrumental
|
|
95
98
|
end
|
96
99
|
|
97
100
|
def connected?
|
98
|
-
|
101
|
+
@socket && !@socket.closed?
|
99
102
|
end
|
100
103
|
|
101
104
|
def logger
|
@@ -125,6 +128,14 @@ module Instrumental
|
|
125
128
|
|
126
129
|
def send_command(cmd, *args)
|
127
130
|
if enabled?
|
131
|
+
if @pid != Process.pid
|
132
|
+
logger.info "Detected fork"
|
133
|
+
@pid = Process.pid
|
134
|
+
@socket = nil
|
135
|
+
@queue = Queue.new
|
136
|
+
start_connection_worker
|
137
|
+
end
|
138
|
+
|
128
139
|
cmd = "%s %s\n" % [cmd, args.collect(&:to_s).join(" ")]
|
129
140
|
if @queue.size < MAX_BUFFER
|
130
141
|
logger.debug "Queueing: #{cmd.chomp}"
|
@@ -137,7 +148,7 @@ module Instrumental
|
|
137
148
|
end
|
138
149
|
end
|
139
150
|
|
140
|
-
def
|
151
|
+
def test_connection
|
141
152
|
# FIXME: Test connection state hack
|
142
153
|
begin
|
143
154
|
@socket.read_nonblock(1) # TODO: put data back?
|
@@ -146,43 +157,57 @@ module Instrumental
|
|
146
157
|
end
|
147
158
|
end
|
148
159
|
|
149
|
-
def
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
@failures = 0
|
155
|
-
logger.info "connected to collector"
|
156
|
-
@socket.puts "hello version #{Instrumental::VERSION} test_mode #{@test_mode}"
|
157
|
-
@socket.puts "authenticate #{@api_key}"
|
160
|
+
def start_connection_worker
|
161
|
+
if enabled?
|
162
|
+
disconnect
|
163
|
+
logger.info "Starting thread"
|
164
|
+
@thread = Thread.new do
|
158
165
|
loop do
|
159
|
-
|
160
|
-
begin
|
161
|
-
test_server_connection
|
162
|
-
rescue Exception => err
|
163
|
-
@queue << command_and_args # connection dead, requeue
|
164
|
-
raise err
|
165
|
-
end
|
166
|
-
|
167
|
-
if command_and_args == 'exit'
|
168
|
-
logger.info "exiting, #{@queue.size} commands remain"
|
169
|
-
@socket.flush
|
170
|
-
Thread.exit
|
171
|
-
else
|
172
|
-
logger.debug "Sending: #{command_and_args.chomp}"
|
173
|
-
@socket.puts command_and_args
|
174
|
-
end
|
166
|
+
break if connection_worker
|
175
167
|
end
|
176
|
-
rescue Exception => err
|
177
|
-
logger.error err.to_s
|
178
|
-
# FIXME: not always a disconnect
|
179
|
-
@failures += 1
|
180
|
-
delay = [(@failures - 1) ** BACKOFF, MAX_RECONNECT_DELAY].min
|
181
|
-
logger.info "disconnected, reconnect in #{delay}..."
|
182
|
-
sleep delay
|
183
|
-
retry
|
184
168
|
end
|
185
169
|
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def connection_worker
|
173
|
+
command_and_args = nil
|
174
|
+
logger.info "connecting to collector"
|
175
|
+
@socket = TCPSocket.new(host, port)
|
176
|
+
@failures = 0
|
177
|
+
logger.info "connected to collector at #{host}:#{port}"
|
178
|
+
@socket.puts "hello version #{Instrumental::VERSION} test_mode #{@test_mode}"
|
179
|
+
@socket.puts "authenticate #{@api_key}"
|
180
|
+
loop do
|
181
|
+
command_and_args = @queue.pop
|
182
|
+
test_connection
|
183
|
+
|
184
|
+
case command_and_args
|
185
|
+
when 'exit'
|
186
|
+
logger.info "exiting, #{@queue.size} commands remain"
|
187
|
+
return true
|
188
|
+
else
|
189
|
+
logger.debug "Sending: #{command_and_args.chomp}"
|
190
|
+
@socket.puts command_and_args
|
191
|
+
command_and_args = nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
rescue Exception => err
|
195
|
+
logger.error err.to_s
|
196
|
+
if command_and_args
|
197
|
+
logger.debug "requeueing: #{command_and_args}"
|
198
|
+
@queue << command_and_args
|
199
|
+
end
|
200
|
+
disconnect
|
201
|
+
@failures += 1
|
202
|
+
delay = [(@failures - 1) ** BACKOFF, MAX_RECONNECT_DELAY].min
|
203
|
+
logger.info "disconnected, reconnect in #{delay}..."
|
204
|
+
sleep delay
|
205
|
+
retry
|
206
|
+
ensure
|
207
|
+
disconnect
|
208
|
+
end
|
209
|
+
|
210
|
+
def setup_cleanup_at_exit
|
186
211
|
at_exit do
|
187
212
|
if !@queue.empty? && @thread.alive?
|
188
213
|
if @failures > 0
|
@@ -196,6 +221,16 @@ module Instrumental
|
|
196
221
|
end
|
197
222
|
end
|
198
223
|
end
|
224
|
+
|
225
|
+
def disconnect
|
226
|
+
if connected?
|
227
|
+
logger.info "Disconnecting..."
|
228
|
+
@socket.flush
|
229
|
+
@socket.close
|
230
|
+
end
|
231
|
+
@socket = nil
|
232
|
+
end
|
233
|
+
|
199
234
|
end
|
200
235
|
|
201
236
|
end
|
data/lib/instrumental/version.rb
CHANGED
data/spec/agent_spec.rb
CHANGED
@@ -19,7 +19,7 @@ describe Instrumental::Agent, "disabled" do
|
|
19
19
|
@server.connect_count.should == 0
|
20
20
|
end
|
21
21
|
|
22
|
-
it "should not connect to the server" do
|
22
|
+
it "should not connect to the server after receiving a metric" do
|
23
23
|
wait
|
24
24
|
@agent.gauge('disabled_test', 1)
|
25
25
|
wait
|
@@ -149,6 +149,21 @@ describe Instrumental::Agent, "enabled" do
|
|
149
149
|
@server.commands.last.should == "increment reconnect_test 1 1234"
|
150
150
|
end
|
151
151
|
|
152
|
+
it "should automatically reconnect when forked" do
|
153
|
+
wait
|
154
|
+
@agent.increment('fork_reconnect_test', 1, 2)
|
155
|
+
fork do
|
156
|
+
@agent.increment('fork_reconnect_test', 1, 3) # triggers reconnect
|
157
|
+
end
|
158
|
+
wait
|
159
|
+
@agent.increment('fork_reconnect_test', 1, 4) # triggers reconnect
|
160
|
+
wait
|
161
|
+
@server.connect_count.should == 2
|
162
|
+
@server.commands.should include("increment fork_reconnect_test 1 2")
|
163
|
+
@server.commands.should include("increment fork_reconnect_test 1 3")
|
164
|
+
@server.commands.should include("increment fork_reconnect_test 1 4")
|
165
|
+
end
|
166
|
+
|
152
167
|
it "should never let an exception reach the user" do
|
153
168
|
@agent.stub!(:send_command).and_raise(Exception.new("Test Exception"))
|
154
169
|
@agent.increment('throws_exception', 2).should be_nil
|
data/spec/test_server.rb
CHANGED
@@ -5,6 +5,7 @@ class TestServer
|
|
5
5
|
@connect_count = 0
|
6
6
|
@connections = []
|
7
7
|
@commands = []
|
8
|
+
@host = 'localhost'
|
8
9
|
listen
|
9
10
|
end
|
10
11
|
|
@@ -14,18 +15,22 @@ class TestServer
|
|
14
15
|
Thread.new do
|
15
16
|
begin
|
16
17
|
# puts "listening"
|
17
|
-
socket = @server.accept
|
18
|
-
@connect_count += 1
|
19
|
-
@connections << socket
|
20
|
-
# puts "connection received"
|
21
18
|
loop do
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
socket = @server.accept
|
20
|
+
Thread.new do
|
21
|
+
@connect_count += 1
|
22
|
+
@connections << socket
|
23
|
+
# puts "connection received"
|
24
|
+
loop do
|
25
|
+
command = socket.gets.strip
|
26
|
+
# puts "got: #{command}"
|
27
|
+
commands << command
|
28
|
+
end
|
29
|
+
end
|
25
30
|
end
|
26
31
|
rescue Exception => err
|
27
32
|
unless @stopping
|
28
|
-
|
33
|
+
puts "EXCEPTION:", err unless @stopping
|
29
34
|
retry
|
30
35
|
end
|
31
36
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: instrumental_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Elijah Miller
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2011-
|
20
|
+
date: 2011-12-01 00:00:00 -05:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|