right_agent 2.6.3 → 2.7.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.
- checksums.yaml +4 -4
- data/Rakefile +0 -1
- data/lib/right_agent/clients/base_retry_client.rb +40 -22
- data/lib/right_agent/core_payload_types/login_user.rb +1 -1
- data/lib/right_agent/error_tracker.rb +37 -33
- data/lib/right_agent/log.rb +9 -10
- data/right_agent.gemspec +3 -3
- data/spec/clients/base_retry_client_spec.rb +97 -56
- data/spec/error_tracker_spec.rb +63 -46
- data/spec/spec_helper.rb +6 -0
- metadata +3 -12
- data/spec/spec.opts +0 -2
- data/spec/spec.win32.opts +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74c2e07823dff52a0a487855918d9fe020f4509b
|
4
|
+
data.tar.gz: b9fc140fd85dc787e63a04880e3b195024ca0f42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a17751f1a016b2e81cdebb0281449c90db0be2cf4e8c17062d54ce36ee29d1517c4d2c1686debf81f75c34f4ae054d109ff9b3f45453b9db27070affb3df7f9b
|
7
|
+
data.tar.gz: f5720ae5a981c8b54a6d3d811fc8f35e8c0ea8c02d573c29fc78e9011c28fbf33aa7d9d089c0337f2a653f250f120cc94fa0403337a23b98681f6728f3037a70
|
data/Rakefile
CHANGED
@@ -273,40 +273,57 @@ module RightScale
|
|
273
273
|
end
|
274
274
|
end
|
275
275
|
|
276
|
-
#
|
277
|
-
#
|
276
|
+
# If EventMachine reactor is running, begin attempting to periodically
|
277
|
+
# reconnect with server by checking health. Randomize initial attempt to
|
278
|
+
# reduce server spiking.
|
279
|
+
#
|
280
|
+
# If EventMachine reactor is NOT running, attempt to reconnect once
|
281
|
+
# and raise any exception that is encountered.
|
278
282
|
#
|
279
283
|
# @return [TrueClass] always true
|
280
284
|
def reconnect
|
281
285
|
unless @reconnecting
|
282
286
|
@reconnecting = true
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
@reconnect_timer = @reconnecting = nil
|
294
|
-
end
|
287
|
+
|
288
|
+
if EM.reactor_running?
|
289
|
+
@stats["reconnects"].update("initiate")
|
290
|
+
@reconnect_timer = EM_S::PeriodicTimer.new(rand(@options[:reconnect_interval])) do
|
291
|
+
begin
|
292
|
+
reconnect_once
|
293
|
+
rescue Exception => e
|
294
|
+
ErrorTracker.log(self, "Failed #{@options[:server_name]} reconnect", e, nil, :caller)
|
295
|
+
@stats["reconnects"].update("failure")
|
296
|
+
self.state = :disconnected
|
295
297
|
end
|
296
|
-
|
297
|
-
ErrorTracker.log(self, "Failed #{@options[:server_name]} reconnect", e, nil, :caller)
|
298
|
-
@stats["reconnects"].update("failure")
|
299
|
-
self.state = :disconnected
|
298
|
+
@reconnect_timer.interval = @options[:reconnect_interval] if @reconnect_timer
|
300
299
|
end
|
301
|
-
|
300
|
+
else
|
301
|
+
reconnect_once
|
302
302
|
end
|
303
303
|
end
|
304
|
+
|
304
305
|
true
|
305
306
|
end
|
306
307
|
|
307
|
-
#
|
308
|
-
#
|
309
|
-
#
|
308
|
+
# Attempt to reconnect exactly once. Perform no exception handling,
|
309
|
+
# state management, or scheduling of future reconnects, but cancel the
|
310
|
+
# reconnect timer if it exists and set @reconnecting, et al to nil.
|
311
|
+
def reconnect_once
|
312
|
+
create_http_client
|
313
|
+
if check_health == :connected
|
314
|
+
enable_use
|
315
|
+
# Check state again since may have disconnected during enable_use
|
316
|
+
if self.state == :connected
|
317
|
+
@stats["reconnects"].update("success")
|
318
|
+
@reconnect_timer.cancel if @reconnect_timer
|
319
|
+
@reconnect_timer = @reconnecting = nil
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Make request via HTTP. Attempt to reconnect first if disconnected and EM reactor is not running.
|
325
|
+
# Rely on underlying HTTP client to log request and response.
|
326
|
+
# Retry request if response indicates to or if there are connectivity failures.
|
310
327
|
#
|
311
328
|
# There are also several timeouts involved:
|
312
329
|
# - Underlying BalancedHttpClient connection open timeout (:open_timeout)
|
@@ -364,6 +381,7 @@ module RightScale
|
|
364
381
|
:request_timeout => @options[:request_timeout],
|
365
382
|
:request_uuid => request_uuid,
|
366
383
|
:headers => headers }
|
384
|
+
reconnect_once if (:disconnected == state) && !EM.reactor_running?
|
367
385
|
raise Exceptions::ConnectivityFailure, "#{@type} client not connected" unless [:connected, :closing].include?(state)
|
368
386
|
result = @http_client.send(verb, path, params, http_options.merge(options))
|
369
387
|
rescue StandardError => e
|
@@ -40,7 +40,7 @@ module RightScale
|
|
40
40
|
@public_key = args[2]
|
41
41
|
@common_name = args[3] || ''
|
42
42
|
@superuser = args[4] || false
|
43
|
-
@expires_at = Time.at(args[5]) if args[5] && (args[5] != 0) # nil -> 0 because of expires_at.to_i below
|
43
|
+
@expires_at = Time.at(args[5].to_i) if args[5] && (args[5] != 0) # nil -> 0 because of expires_at.to_i below
|
44
44
|
@public_keys = args[6]
|
45
45
|
@profile_data = args[7]
|
46
46
|
@public_key_fingerprints = args[8]
|
@@ -14,7 +14,7 @@ module RightScale
|
|
14
14
|
# Tracker for unexpected errors
|
15
15
|
# Logs them with appropriate trace information
|
16
16
|
# Accumulates statistics about exceptions
|
17
|
-
# Reports exceptions to external Errbit service via
|
17
|
+
# Reports exceptions to external Errbit service via Airbrake
|
18
18
|
class ErrorTracker
|
19
19
|
|
20
20
|
include RightSupport::Ruby::EasySingleton
|
@@ -104,36 +104,38 @@ module RightScale
|
|
104
104
|
# @return [TrueClass] always true
|
105
105
|
def notify(exception, packet = nil, agent = nil, component = nil)
|
106
106
|
if @notify_enabled
|
107
|
-
data = {
|
108
|
-
:error_message => exception.respond_to?(:message) ? exception.message : exception.to_s,
|
109
|
-
:backtrace => exception.respond_to?(:backtrace) ? exception.backtrace : caller,
|
110
|
-
:environment_name => ENV["RAILS_ENV"],
|
111
|
-
}
|
112
|
-
if agent
|
113
|
-
data[:cgi_data] = (@cgi_data || {}).merge(:agent_class => agent.class.name)
|
114
|
-
elsif @cgi_data
|
115
|
-
data[:cgi_data] = @cgi_data
|
116
|
-
end
|
117
|
-
data[:error_class] = exception.class.name if exception.is_a?(Exception)
|
118
|
-
data[:component] = component if component
|
119
107
|
if packet && packet.is_a?(Packet)
|
120
|
-
|
108
|
+
action = packet.type.split("/").last if packet.respond_to?(:type)
|
121
109
|
params = packet.respond_to?(:payload) && packet.payload
|
122
110
|
uuid = packet.respond_to?(:token) && packet.token
|
123
111
|
elsif packet.is_a?(Hash)
|
124
|
-
|
125
|
-
|
112
|
+
action_path = packet[:path] || packet["path"]
|
113
|
+
action = action_path.split("/").last if action_path
|
126
114
|
params = packet[:data] || packet["data"]
|
127
115
|
uuid = packet[:uuid] || packet["uuid"]
|
128
116
|
else
|
129
117
|
params = uuid = nil
|
130
118
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
119
|
+
|
120
|
+
n = Airbrake.build_notice(
|
121
|
+
exception,
|
122
|
+
{ component: component, action: action },
|
123
|
+
:right_agent )
|
124
|
+
|
125
|
+
n[:params] = params.is_a?(Hash) ? filter(params) : {:param => params} if params
|
126
|
+
n[:session] = { :uuid => uuid } if uuid
|
127
|
+
|
128
|
+
if agent
|
129
|
+
n[:environment] = (@cgi_data || {}).merge(:agent_class => agent.class.name)
|
130
|
+
elsif @cgi_data
|
131
|
+
n[:environment] = @cgi_data || {}
|
132
|
+
end
|
133
|
+
|
134
|
+
Airbrake.notify(n, {}, :right_agent)
|
134
135
|
end
|
135
136
|
true
|
136
137
|
rescue Exception => e
|
138
|
+
raise if e.class.name =~ /^RSpec/ # keep us from going insane while running tests
|
137
139
|
Log.error("Failed to notify Errbit", e, :trace)
|
138
140
|
end
|
139
141
|
|
@@ -168,7 +170,7 @@ module RightScale
|
|
168
170
|
@exception_stats.reset
|
169
171
|
end
|
170
172
|
|
171
|
-
# Configure
|
173
|
+
# Configure Airbrake for exception notification
|
172
174
|
#
|
173
175
|
# @param [String] agent_name uniquely identifying agent process on given server
|
174
176
|
#
|
@@ -181,11 +183,11 @@ module RightScale
|
|
181
183
|
#
|
182
184
|
# @return [TrueClass] always true
|
183
185
|
#
|
184
|
-
# @raise [RuntimeError]
|
186
|
+
# @raise [RuntimeError] airbrake gem missing
|
185
187
|
def notify_init(agent_name, options)
|
186
188
|
if options[:airbrake_endpoint] && options[:airbrake_api_key]
|
187
|
-
unless require_succeeds?("
|
188
|
-
raise RuntimeError, "
|
189
|
+
unless require_succeeds?("airbrake-ruby")
|
190
|
+
raise RuntimeError, "airbrake-ruby gem missing - required if airbrake options used in ErrorTracker"
|
189
191
|
end
|
190
192
|
|
191
193
|
@cgi_data = {
|
@@ -194,21 +196,23 @@ module RightScale
|
|
194
196
|
:agent_name => agent_name
|
195
197
|
}
|
196
198
|
@cgi_data[:shard_id] = options[:shard_id] if options[:shard_id]
|
197
|
-
@cgi_data[:sha] = CURRENT_SOURCE_SHA if defined?(CURRENT_SOURCE_SHA)
|
198
|
-
|
199
|
-
uri = URI.parse(options[:airbrake_endpoint])
|
200
|
-
HydraulicBrake.configure do |config|
|
201
|
-
config.secure = (uri.scheme == "https")
|
202
|
-
config.host = uri.host
|
203
|
-
config.port = uri.port
|
204
|
-
config.api_key = options[:airbrake_api_key]
|
205
|
-
config.project_root = AgentConfig.root_dir
|
206
|
-
end
|
207
199
|
@filter_params = (options[:filter_params] || []).map { |p| p.to_s }
|
208
200
|
@notify_enabled = true
|
201
|
+
|
202
|
+
return true if Airbrake.send(:configured?, :right_agent)
|
203
|
+
|
204
|
+
Airbrake.configure(:right_agent) do |config|
|
205
|
+
config.host = options[:airbrake_endpoint]
|
206
|
+
config.project_id = options[:airbrake_api_key]
|
207
|
+
config.project_key = options[:airbrake_api_key]
|
208
|
+
config.root_directory = AgentConfig.root_dir
|
209
|
+
config.environment = ENV['RAILS_ENV']
|
210
|
+
config.app_version = CURRENT_SOURCE_SHA if defined?(CURRENT_SOURCE_SHA)
|
211
|
+
end
|
209
212
|
else
|
210
213
|
@notify_enabled = false
|
211
214
|
end
|
215
|
+
|
212
216
|
true
|
213
217
|
end
|
214
218
|
|
data/lib/right_agent/log.rb
CHANGED
@@ -416,22 +416,21 @@ module RightScale
|
|
416
416
|
|
417
417
|
# Initialize logger
|
418
418
|
#
|
419
|
-
#
|
420
|
-
#
|
421
|
-
#
|
422
|
-
# opts[
|
423
|
-
# is already initialized
|
424
|
-
# opts[:print](TrueClass|FalseClass):: Whether to print to STDOUT log destination
|
419
|
+
# @param [String] identity RightNet identity (for log file name or syslog program name)
|
420
|
+
# @param [String] path directory to create log files in
|
421
|
+
# @option opts [Boolean] :force whether to re-initialize if logger is already initialized
|
422
|
+
# @option opts [Boolean] :print whether to print log-location info to STDOUT
|
425
423
|
#
|
426
|
-
#
|
427
|
-
# logger(RightScale::Multiplexer):: logger instance
|
424
|
+
# @return [RightScale::Multiplexer] logger instance
|
428
425
|
def init(identity=nil, path=nil, opts={})
|
429
426
|
if opts[:force] || !@initialized
|
430
427
|
@initialized = true
|
431
428
|
@level_frozen = false
|
432
|
-
logger =
|
429
|
+
logger = opts[:logger]
|
433
430
|
|
434
|
-
if
|
431
|
+
if !logger.nil?
|
432
|
+
$stderr.puts "Logging to already-initialized #{logger.class.name}" if opts[:print]
|
433
|
+
elsif @log_to_file_only || Platform.windows?
|
435
434
|
if path
|
436
435
|
file = File.join(path, "#{identity}.log")
|
437
436
|
else
|
data/right_agent.gemspec
CHANGED
@@ -25,8 +25,8 @@ require 'rbconfig'
|
|
25
25
|
|
26
26
|
Gem::Specification.new do |spec|
|
27
27
|
spec.name = 'right_agent'
|
28
|
-
spec.version = '2.
|
29
|
-
spec.date = '
|
28
|
+
spec.version = '2.7.0'
|
29
|
+
spec.date = '2016-05-20'
|
30
30
|
spec.authors = ['Lee Kirchhoff', 'Raphael Simon', 'Tony Spataro', 'Scott Messier']
|
31
31
|
spec.email = 'lee@rightscale.com'
|
32
32
|
spec.homepage = 'https://github.com/rightscale/right_agent'
|
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
|
|
44
44
|
spec.add_dependency('faye-websocket', '~> 0.7.0')
|
45
45
|
spec.add_dependency('eventmachine', ['>= 0.12.10', '< 2.0'])
|
46
46
|
spec.add_dependency('net-ssh', '~> 2.0')
|
47
|
-
spec.add_dependency('addressable', '~> 2.3'
|
47
|
+
spec.add_dependency('addressable', '~> 2.3')
|
48
48
|
|
49
49
|
# TEAL HACK: rake gem may override current RUBY_PLATFORM to allow building
|
50
50
|
# gems for all supported platforms from any platform. rubygems 1.8.x makes it
|
@@ -34,6 +34,7 @@ describe RightScale::BaseRetryClient do
|
|
34
34
|
@log.should_receive(:warning).by_default.and_return { |m| raise RightScale::Log.format(*m) }
|
35
35
|
@url = "http://test.com"
|
36
36
|
@timer = flexmock("timer", :cancel => true, :interval= => 0).by_default
|
37
|
+
flexmock(EM).should_receive(:reactor_running?).and_return(true).by_default
|
37
38
|
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).by_default
|
38
39
|
@http_client = flexmock("http client", :get => true, :check_health => true, :close => true).by_default
|
39
40
|
flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).by_default
|
@@ -338,82 +339,102 @@ describe RightScale::BaseRetryClient do
|
|
338
339
|
@client.instance_variable_set(:@reconnecting, nil)
|
339
340
|
end
|
340
341
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
end
|
346
|
-
|
347
|
-
it "attempts to connect even if currently connected" do
|
348
|
-
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
349
|
-
@client.send(:create_http_client)
|
350
|
-
@client.send(:check_health).should == :connected
|
351
|
-
flexmock(@client).should_receive(:check_health).once
|
352
|
-
@client.send(:reconnect).should be_true
|
353
|
-
end
|
354
|
-
|
355
|
-
it "recreates HTTP client and checks health" do
|
356
|
-
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
357
|
-
flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).once
|
358
|
-
@http_client.should_receive(:check_health).once
|
359
|
-
@client.send(:reconnect).should be_true
|
360
|
-
end
|
361
|
-
|
362
|
-
context "when health check successful" do
|
363
|
-
it "enables use of client" do
|
364
|
-
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
365
|
-
flexmock(@client).should_receive(:enable_use).once
|
342
|
+
context 'given EventMachine is running' do
|
343
|
+
it "waits random interval for initial reconnect attempt" do
|
344
|
+
flexmock(@client).should_receive(:rand).with(15).and_return(10).once
|
345
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).with(10, Proc).and_return(@timer).once
|
366
346
|
@client.send(:reconnect).should be_true
|
367
347
|
end
|
368
348
|
|
369
|
-
it "
|
349
|
+
it "attempts to connect even if currently connected" do
|
370
350
|
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
371
|
-
|
351
|
+
@client.send(:create_http_client)
|
352
|
+
@client.send(:check_health).should == :connected
|
353
|
+
flexmock(@client).should_receive(:check_health).once
|
372
354
|
@client.send(:reconnect).should be_true
|
373
|
-
@client.instance_variable_get(:@reconnecting).should be true
|
374
355
|
end
|
375
356
|
|
376
|
-
it "
|
377
|
-
@client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
|
378
|
-
@client.instance_variable_set(:@reconnecting, nil)
|
379
|
-
@timer.should_receive(:cancel).once
|
357
|
+
it "recreates HTTP client and checks health" do
|
380
358
|
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
359
|
+
flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).once
|
360
|
+
@http_client.should_receive(:check_health).once
|
381
361
|
@client.send(:reconnect).should be_true
|
382
|
-
@client.instance_variable_get(:@reconnecting).should be_nil
|
383
362
|
end
|
384
363
|
|
385
|
-
|
386
|
-
|
387
|
-
|
364
|
+
context "when health check successful" do
|
365
|
+
it "enables use of client" do
|
366
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
367
|
+
flexmock(@client).should_receive(:enable_use).once
|
368
|
+
@client.send(:reconnect).should be_true
|
369
|
+
end
|
370
|
+
|
371
|
+
it "rechecks state after enables use" do
|
372
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
373
|
+
flexmock(@client).should_receive(:enable_use).and_return { @client.instance_variable_set(:@state, :disconnected) }.once
|
374
|
+
@client.send(:reconnect).should be_true
|
375
|
+
@client.instance_variable_get(:@reconnecting).should be true
|
376
|
+
end
|
377
|
+
|
378
|
+
it "disables timer" do
|
379
|
+
@client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
|
380
|
+
@client.instance_variable_set(:@reconnecting, nil)
|
381
|
+
@timer.should_receive(:cancel).once
|
382
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
383
|
+
@client.send(:reconnect).should be_true
|
384
|
+
@client.instance_variable_get(:@reconnecting).should be_nil
|
385
|
+
end
|
386
|
+
|
387
|
+
it "does not reset timer interval" do
|
388
|
+
@timer.should_receive(:interval=).never
|
389
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
390
|
+
@client.send(:reconnect).should be_true
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
context "when reconnect fails" do
|
395
|
+
it "logs error if exception is raised" do
|
396
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
397
|
+
flexmock(@client).should_receive(:enable_use).and_raise(StandardError).once
|
398
|
+
@log.should_receive(:error).with("Failed test reconnect", StandardError, :caller).once
|
399
|
+
@client.send(:reconnect).should be_true
|
400
|
+
@client.state.should == :disconnected
|
401
|
+
end
|
402
|
+
|
403
|
+
it "resets the timer interval to the configured value" do
|
404
|
+
@client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
|
405
|
+
@log.should_receive(:error).with("Failed test health check", StandardError, :caller).once
|
406
|
+
@http_client.should_receive(:check_health).and_raise(StandardError).once
|
407
|
+
@timer.should_receive(:interval=).with(15).once
|
408
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
409
|
+
@client.send(:reconnect).should be_true
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
it "does nothing if already reconnecting" do
|
414
|
+
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).once
|
415
|
+
@client.send(:reconnect).should be_true
|
416
|
+
@client.instance_variable_get(:@reconnecting).should be_true
|
388
417
|
@client.send(:reconnect).should be_true
|
418
|
+
@client.instance_variable_get(:@reconnecting).should be_true
|
389
419
|
end
|
390
420
|
end
|
391
421
|
|
392
|
-
context
|
393
|
-
|
394
|
-
flexmock(EM
|
395
|
-
flexmock(@client).should_receive(:enable_use).and_raise(StandardError).once
|
396
|
-
@log.should_receive(:error).with("Failed test reconnect", StandardError, :caller).once
|
397
|
-
@client.send(:reconnect).should be_true
|
398
|
-
@client.state.should == :disconnected
|
422
|
+
context 'given EventMachine is inactive' do
|
423
|
+
before(:each) do
|
424
|
+
flexmock(EM).should_receive(:reactor_running?).and_return(false)
|
399
425
|
end
|
400
426
|
|
401
|
-
it "
|
402
|
-
@client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
|
403
|
-
@log.should_receive(:error).with("Failed test health check", StandardError, :caller).once
|
404
|
-
@http_client.should_receive(:check_health).and_raise(StandardError).once
|
405
|
-
@timer.should_receive(:interval=).with(15).once
|
406
|
-
flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
|
427
|
+
it "tries once" do
|
407
428
|
@client.send(:reconnect).should be_true
|
408
429
|
end
|
409
|
-
end
|
410
430
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
431
|
+
it "raises exceptions" do
|
432
|
+
lambda do
|
433
|
+
flexmock(@client).should_receive(:create_http_client).and_raise(Exception)
|
434
|
+
|
435
|
+
@client.send(:reconnect)
|
436
|
+
end.should raise_error(Exception)
|
437
|
+
end
|
417
438
|
end
|
418
439
|
end
|
419
440
|
|
@@ -431,6 +452,26 @@ describe RightScale::BaseRetryClient do
|
|
431
452
|
@client.init(:test, @auth_client, @options)
|
432
453
|
end
|
433
454
|
|
455
|
+
context 'given EventMachine is inactive' do
|
456
|
+
before(:each) do
|
457
|
+
flexmock(EM).should_receive(:reactor_running?).and_return(false)
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'reconnects if necessary' do
|
461
|
+
@client.instance_variable_set(:@state, :disconnected)
|
462
|
+
@http_client.should_receive(:get).with(@path, @params, Hash).once
|
463
|
+
@client.send(:make_request, :get, @path, @params)
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'raises connection errors' do
|
467
|
+
@client.instance_variable_set(:@state, :disconnected)
|
468
|
+
@http_client.should_receive(:check_health).and_raise(Exception)
|
469
|
+
lambda {
|
470
|
+
@client.send(:make_request, :get, @path, @params)
|
471
|
+
}.should raise_error(Exception)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
434
475
|
it "raises exception if terminating" do
|
435
476
|
@client.close
|
436
477
|
lambda { @client.send(:make_request, :get, @path) }.should raise_error(RightScale::Exceptions::Terminating)
|
data/spec/error_tracker_spec.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
require '
|
23
|
+
require 'airbrake-ruby'
|
24
24
|
|
25
25
|
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
26
26
|
|
@@ -39,7 +39,7 @@ describe RightScale::ErrorTracker do
|
|
39
39
|
@trace_level = RightScale::Agent::TRACE_LEVEL
|
40
40
|
@tracker = RightScale::ErrorTracker.instance
|
41
41
|
@log = flexmock(RightScale::Log)
|
42
|
-
@brake = flexmock(
|
42
|
+
@brake = flexmock(Airbrake)
|
43
43
|
@options = {
|
44
44
|
:shard_id => @shard_id,
|
45
45
|
:trace_level => @trace_level,
|
@@ -161,82 +161,97 @@ describe RightScale::ErrorTracker do
|
|
161
161
|
@exception = RuntimeError.new("error")
|
162
162
|
@tracker.init(@agent, @agent_name, @options)
|
163
163
|
@cgi_data = @tracker.instance_variable_get(:@cgi_data)
|
164
|
+
ENV['RAILS_ENV'] = 'development'
|
164
165
|
end
|
165
166
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
167
|
+
after(:each) do
|
168
|
+
ENV['RAILS_ENV'] = nil
|
169
|
+
end
|
170
|
+
|
171
|
+
it "sends notification using Airbrake" do
|
172
|
+
@brake.should_receive(:notify).with(on { |a|
|
173
|
+
a[:errors].first[:type] == "RuntimeError" &&
|
174
|
+
a[:environment] == @cgi_data
|
175
|
+
}, {}, :right_agent).once
|
173
176
|
@tracker.notify(@exception).should be true
|
174
177
|
end
|
175
178
|
|
176
179
|
it "includes packet data in notification" do
|
177
180
|
request = RightScale::Request.new("/foo/bar", {:pay => "load"}, :token => "token")
|
178
|
-
@brake.should_receive(:notify).with(on { |a|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
a[:session_data] == {:uuid => "token"} }).once
|
181
|
+
@brake.should_receive(:notify).with(on { |a|
|
182
|
+
a[:errors].first[:message] == "error" &&
|
183
|
+
a[:context][:action] == 'bar' &&
|
184
|
+
a[:params] == { :pay => 'load' } &&
|
185
|
+
a[:session] == { :uuid => 'token' }
|
186
|
+
}, {}, :right_agent).once
|
187
|
+
|
186
188
|
@tracker.notify(@exception, request).should be true
|
187
189
|
end
|
188
190
|
|
189
191
|
it "includes event data in notification" do
|
190
|
-
@brake.should_receive(:notify).with(on { |a|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
192
|
+
@brake.should_receive(:notify).with(on { |a|
|
193
|
+
a[:errors].first[:message] == "error" &&
|
194
|
+
a[:errors].first[:type] == "RuntimeError" &&
|
195
|
+
a[:context][:action] == 'bar' &&
|
196
|
+
a[:params] == { :pay => 'load' } &&
|
197
|
+
a[:session] == { :uuid => 'token' }
|
198
|
+
}, {}, :right_agent).once
|
199
|
+
|
198
200
|
@tracker.notify(@exception, {"uuid" => "token", "path" => "/foo/bar", "data" => {:pay => "load"}}).should be true
|
199
201
|
end
|
200
202
|
|
201
203
|
it "adds agent class to :cgi_data in notification" do
|
202
|
-
@brake.should_receive(:notify).with(on { |a|
|
204
|
+
@brake.should_receive(:notify).with(on { |a|
|
205
|
+
a[:environment] == @cgi_data.merge(:agent_class => 'AgentMock')
|
206
|
+
}, {}, :right_agent).once
|
207
|
+
|
203
208
|
@tracker.notify(@exception, packet = nil, @agent).should be true
|
204
209
|
end
|
205
210
|
|
206
211
|
it "adds component to notification" do
|
207
|
-
@brake.should_receive(:notify).with(on { |a|
|
212
|
+
@brake.should_receive(:notify).with(on { |a|
|
213
|
+
a[:context][:component] == 'component'
|
214
|
+
}, {}, :right_agent).once
|
208
215
|
@tracker.notify(@exception, packet = nil, agent = nil, "component").should be true
|
209
216
|
end
|
210
217
|
|
211
218
|
it "converts non-nil, non-hash payload in packet to a hash" do
|
212
219
|
request = RightScale::Request.new("/foo/bar", "payload", :token => "token")
|
213
|
-
@brake.should_receive(:notify).with(on { |a|
|
220
|
+
@brake.should_receive(:notify).with(on { |a|
|
221
|
+
a[:params] == { :param => 'payload' }
|
222
|
+
}, {}, :right_agent).once
|
214
223
|
@tracker.notify(@exception, request).should be true
|
215
224
|
end
|
216
225
|
|
217
226
|
it "converts non-nil, non-hash data in event to a hash" do
|
218
|
-
@brake.should_receive(:notify).with(on { |a|
|
227
|
+
@brake.should_receive(:notify).with(on { |a|
|
228
|
+
a[:params] == { :param => 'payload' }
|
229
|
+
}, {}, :right_agent).once
|
219
230
|
@tracker.notify(@exception, {"uuid" => "token", "path" => "/foo/bar", "data" => "payload"}).should be true
|
220
231
|
end
|
221
232
|
|
222
233
|
it "omits :parameters from notification if payload in packet is nil" do
|
223
234
|
request = RightScale::Request.new("/foo/bar", nil, :token => "token")
|
224
|
-
@brake.should_receive(:notify).with(on { |a|
|
235
|
+
@brake.should_receive(:notify).with(on { |a|
|
236
|
+
a[:params] == {}
|
237
|
+
}, {}, :right_agent).once
|
225
238
|
@tracker.notify(@exception, request).should be true
|
226
239
|
end
|
227
240
|
|
228
241
|
it "omits :parameters from notification if data in packet is nil" do
|
229
|
-
@brake.should_receive(:notify).with(on { |a|
|
242
|
+
@brake.should_receive(:notify).with(on { |a|
|
243
|
+
a[:params] == {}
|
244
|
+
}, {}, :right_agent).once
|
230
245
|
@tracker.notify(@exception, {"uuid" => "token", "path" => "/foo/bar", "data" => nil}).should be true
|
231
246
|
end
|
232
247
|
|
233
248
|
it "functions even if cgi_data has not been initialized by notify_init" do
|
234
249
|
@tracker.instance_variable_set(:@cgi_data, nil)
|
235
|
-
@brake.should_receive(:notify).with(on { |a|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
250
|
+
@brake.should_receive(:notify).with(on { |a|
|
251
|
+
a[:errors].first[:message] == "error" &&
|
252
|
+
a[:errors].first[:type] == "RuntimeError" &&
|
253
|
+
a[:environment] == {}
|
254
|
+
}, {}, :right_agent).once
|
240
255
|
@tracker.notify(@exception).should be true
|
241
256
|
end
|
242
257
|
|
@@ -285,7 +300,7 @@ describe RightScale::ErrorTracker do
|
|
285
300
|
|
286
301
|
context :notify_init do
|
287
302
|
class ConfigMock
|
288
|
-
attr_accessor :
|
303
|
+
attr_accessor :host, :api_key, :project_id, :project_key, :root_directory, :environment
|
289
304
|
end
|
290
305
|
|
291
306
|
it "does not initialize if Airbrake endpoint or API key is undefined" do
|
@@ -296,7 +311,10 @@ describe RightScale::ErrorTracker do
|
|
296
311
|
@tracker.instance_variable_get(:@notify_enabled).should be false
|
297
312
|
end
|
298
313
|
|
299
|
-
it "initializes cgi data and configures
|
314
|
+
it "initializes cgi data and configures Airbrake" do
|
315
|
+
# dirty, but we need to make sure this is unset in order to progress
|
316
|
+
Airbrake.instance_variable_set(:@notifiers, {})
|
317
|
+
|
300
318
|
config = ConfigMock.new
|
301
319
|
@brake.should_receive(:configure).and_yield(config).once
|
302
320
|
@tracker.send(:notify_init, @agent_name, @options).should be true
|
@@ -305,20 +323,19 @@ describe RightScale::ErrorTracker do
|
|
305
323
|
cgi_data[:pid].should be_a Integer
|
306
324
|
cgi_data[:process].should be_a String
|
307
325
|
cgi_data[:shard_id].should == @shard_id
|
308
|
-
config.
|
309
|
-
config.
|
310
|
-
config.
|
311
|
-
config.
|
312
|
-
config.project_root.should be_a String
|
326
|
+
config.host.should == "https://airbrake.com"
|
327
|
+
config.project_id.should == @api_key
|
328
|
+
config.project_key.should == @api_key
|
329
|
+
config.root_directory.should be_a String
|
313
330
|
@tracker.instance_variable_get(:@notify_enabled).should be true
|
314
331
|
@tracker.instance_variable_get(:@filter_params).should == ["password"]
|
315
332
|
end
|
316
333
|
|
317
|
-
it "raises exception if
|
318
|
-
flexmock(@tracker).should_receive(:require_succeeds?).with("
|
334
|
+
it "raises exception if airbrake-ruby is not available" do
|
335
|
+
flexmock(@tracker).should_receive(:require_succeeds?).with("airbrake-ruby").and_return(false)
|
319
336
|
lambda do
|
320
337
|
@tracker.send(:notify_init, @agent_name, @options)
|
321
|
-
end.should raise_error(RuntimeError, /
|
338
|
+
end.should raise_error(RuntimeError, /airbrake-ruby gem missing/)
|
322
339
|
end
|
323
340
|
end
|
324
341
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Kirchhoff
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2016-05-20 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: right_support
|
@@ -116,9 +116,6 @@ dependencies:
|
|
116
116
|
- - "~>"
|
117
117
|
- !ruby/object:Gem::Version
|
118
118
|
version: '2.3'
|
119
|
-
- - "<"
|
120
|
-
- !ruby/object:Gem::Version
|
121
|
-
version: '2.4'
|
122
119
|
type: :runtime
|
123
120
|
prerelease: false
|
124
121
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -126,9 +123,6 @@ dependencies:
|
|
126
123
|
- - "~>"
|
127
124
|
- !ruby/object:Gem::Version
|
128
125
|
version: '2.3'
|
129
|
-
- - "<"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '2.4'
|
132
126
|
- !ruby/object:Gem::Dependency
|
133
127
|
name: ffi
|
134
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -376,8 +370,6 @@ files:
|
|
376
370
|
- spec/serialize/secure_serializer_spec.rb
|
377
371
|
- spec/serialize/serializable_spec.rb
|
378
372
|
- spec/serialize/serializer_spec.rb
|
379
|
-
- spec/spec.opts
|
380
|
-
- spec/spec.win32.opts
|
381
373
|
- spec/spec_helper.rb
|
382
374
|
- spec/tracer_spec.rb
|
383
375
|
homepage: https://github.com/rightscale/right_agent
|
@@ -403,9 +395,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
403
395
|
version: '0'
|
404
396
|
requirements: []
|
405
397
|
rubyforge_project:
|
406
|
-
rubygems_version: 2.2.
|
398
|
+
rubygems_version: 2.2.5
|
407
399
|
signing_key:
|
408
400
|
specification_version: 4
|
409
401
|
summary: Agent for interfacing server with RightScale system
|
410
402
|
test_files: []
|
411
|
-
has_rdoc: true
|
data/spec/spec.opts
DELETED
data/spec/spec.win32.opts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--format=nested
|