newrelic_rpm 2.13.4 → 2.13.5.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of newrelic_rpm might be problematic. Click here for more details.
- data/CHANGELOG +9 -0
- data/lib/new_relic/agent.rb +2 -1
- data/lib/new_relic/agent/agent.rb +393 -204
- data/lib/new_relic/agent/error_collector.rb +113 -43
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +14 -16
- data/lib/new_relic/agent/instrumentation/queue_time.rb +201 -0
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +1 -1
- data/lib/new_relic/agent/instrumentation/sequel.rb +95 -0
- data/lib/new_relic/agent/method_tracer.rb +391 -313
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +43 -41
- data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +2 -0
- data/lib/new_relic/agent/samplers/memory_sampler.rb +122 -120
- data/lib/new_relic/agent/samplers/object_sampler.rb +2 -0
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +0 -1
- data/lib/new_relic/agent/stats_engine/samplers.rb +20 -14
- data/lib/new_relic/agent/stats_engine/transactions.rb +35 -7
- data/lib/new_relic/control.rb +12 -17
- data/lib/new_relic/control/configuration.rb +1 -0
- data/lib/new_relic/control/frameworks/rails.rb +7 -4
- data/lib/new_relic/control/frameworks/rails3.rb +1 -1
- data/lib/new_relic/control/instrumentation.rb +2 -18
- data/lib/new_relic/local_environment.rb +117 -59
- data/lib/new_relic/rack/developer_mode.rb +212 -207
- data/lib/new_relic/recipes.rb +0 -9
- data/lib/new_relic/stats.rb +87 -81
- data/lib/new_relic/transaction_analysis.rb +1 -1
- data/lib/new_relic/version.rb +2 -2
- data/lib/newrelic_rpm.rb +2 -3
- data/lib/tasks/tests.rake +5 -1
- data/newrelic_rpm.gemspec +14 -5
- data/test/config/test_control.rb +14 -2
- data/test/new_relic/agent/active_record_instrumentation_test.rb +342 -119
- data/test/new_relic/agent/add_method_tracer_test.rb +158 -0
- data/test/new_relic/agent/agent_connect_test.rb +295 -0
- data/test/new_relic/agent/agent_controller_test.rb +86 -18
- data/test/new_relic/agent/agent_start_test.rb +326 -0
- data/test/new_relic/agent/agent_start_worker_thread_test.rb +157 -0
- data/test/new_relic/agent/apdex_from_server_test.rb +9 -0
- data/test/new_relic/agent/collection_helper_test.rb +3 -1
- data/test/new_relic/agent/error_collector_notice_error_test.rb +255 -0
- data/test/new_relic/agent/error_collector_test.rb +6 -0
- data/test/new_relic/agent/method_tracer_test.rb +2 -2
- data/test/new_relic/agent/method_tracer_trace_execution_scoped_test.rb +233 -0
- data/test/new_relic/agent/net_instrumentation_test.rb +17 -12
- data/test/new_relic/agent/queue_time_test.rb +333 -0
- data/test/new_relic/agent/rpm_agent_test.rb +4 -2
- data/test/new_relic/agent/stats_engine/samplers_test.rb +27 -1
- data/test/new_relic/agent/transaction_sample_subtest_test.rb +56 -0
- data/test/new_relic/agent/transaction_sample_test.rb +103 -174
- data/test/new_relic/agent/transaction_sampler_test.rb +9 -2
- data/test/new_relic/control_test.rb +7 -2
- data/test/new_relic/metric_spec_test.rb +1 -1
- data/test/new_relic/stats_test.rb +112 -15
- data/test/test_helper.rb +79 -16
- data/ui/helpers/developer_mode_helper.rb +2 -0
- metadata +19 -7
- data/lib/new_relic_api.rb +0 -276
data/CHANGELOG
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
v2.13.5
|
2
|
+
* Moved the API helper to the github newrelic_api gem.
|
3
|
+
* Revamped queue time to include server, queue, and middleware time
|
4
|
+
* Increased test coverage and stability
|
5
|
+
* Add Trinidad as a dispatcher (from Calavera, on github)
|
6
|
+
* Sequel instrumentation from Aman Gupta
|
7
|
+
* patches to 1.9 compatibility from dkastner on github
|
8
|
+
* Support for 1.9.2's garbage collection instrumentation from Justin Weiss
|
9
|
+
|
1
10
|
v2.13.4
|
2
11
|
* Update DNS lookup code to remove hardcoded IP addresses
|
3
12
|
|
data/lib/new_relic/agent.rb
CHANGED
@@ -70,7 +70,8 @@ module NewRelic
|
|
70
70
|
require 'new_relic/noticed_error'
|
71
71
|
require 'new_relic/histogram'
|
72
72
|
require 'new_relic/timer_lib'
|
73
|
-
|
73
|
+
|
74
|
+
require 'new_relic/agent'
|
74
75
|
require 'new_relic/agent/chained_call'
|
75
76
|
require 'new_relic/agent/agent'
|
76
77
|
require 'new_relic/agent/shim_agent'
|
@@ -37,6 +37,7 @@ module NewRelic
|
|
37
37
|
@transaction_sampler = NewRelic::Agent::TransactionSampler.new
|
38
38
|
@stats_engine.transaction_sampler = @transaction_sampler
|
39
39
|
@error_collector = NewRelic::Agent::ErrorCollector.new
|
40
|
+
@connect_attempts = 0
|
40
41
|
|
41
42
|
@request_timeout = NewRelic::Control.instance.fetch('timeout', 2 * 60)
|
42
43
|
|
@@ -94,11 +95,6 @@ module NewRelic
|
|
94
95
|
# busy time ?
|
95
96
|
end
|
96
97
|
|
97
|
-
# This method is deprecated. Use NewRelic::Agent.manual_start
|
98
|
-
def manual_start(ignored=nil, also_ignored=nil)
|
99
|
-
raise "This method no longer supported. Instead use the class method NewRelic::Agent.manual_start"
|
100
|
-
end
|
101
|
-
|
102
98
|
# This method should be called in a forked process after a fork.
|
103
99
|
# It assumes the parent process initialized the agent, but does
|
104
100
|
# not assume the agent started.
|
@@ -226,80 +222,158 @@ module NewRelic
|
|
226
222
|
def log
|
227
223
|
NewRelic::Agent.logger
|
228
224
|
end
|
225
|
+
|
226
|
+
# Herein lies the corpse of the former 'start' method. May
|
227
|
+
# it's unmatched flog score rest in pieces.
|
228
|
+
module Start
|
229
|
+
def already_started?
|
230
|
+
if started?
|
231
|
+
control.log!("Agent Started Already!", :error)
|
232
|
+
true
|
233
|
+
end
|
234
|
+
end
|
229
235
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
236
|
+
def disabled?
|
237
|
+
!control.agent_enabled?
|
238
|
+
end
|
239
|
+
|
240
|
+
def log_dispatcher
|
241
|
+
dispatcher_name = control.dispatcher.to_s
|
242
|
+
return if log_if(dispatcher_name.empty?, :info, "No dispatcher detected.")
|
243
|
+
log.info "Dispatcher: #{dispatcher_name}"
|
244
|
+
end
|
245
|
+
|
246
|
+
def log_app_names
|
247
|
+
log.info "Application: #{control.app_names.join(", ")}"
|
238
248
|
end
|
239
|
-
return if !control.agent_enabled?
|
240
|
-
@started = true
|
241
|
-
@local_host = determine_host
|
242
249
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
log.info "Dispatcher: #{control.dispatcher.to_s}"
|
247
|
-
end
|
248
|
-
log.info "Application: #{control.app_names.join(", ")}" unless control.app_names.empty?
|
249
|
-
|
250
|
-
sampler_config = control.fetch('transaction_tracer', {})
|
251
|
-
# TODO: Should move this state into the transaction sampler instance
|
252
|
-
@should_send_samples = @config_should_send_samples = sampler_config.fetch('enabled', true)
|
253
|
-
@should_send_random_samples = sampler_config.fetch('random_sample', false)
|
254
|
-
@explain_threshold = sampler_config.fetch('explain_threshold', 0.5).to_f
|
255
|
-
@explain_enabled = sampler_config.fetch('explain_enabled', true)
|
256
|
-
@record_sql = sampler_config.fetch('record_sql', :obfuscated).to_sym
|
257
|
-
|
258
|
-
# use transaction_threshold: 4.0 to force the TT collection
|
259
|
-
# threshold to 4 seconds
|
260
|
-
# use transaction_threshold: apdex_f to use your apdex t value
|
261
|
-
# multiplied by 4
|
262
|
-
# undefined transaction_threshold defaults to 2.0
|
263
|
-
apdex_f = 4 * NewRelic::Control.instance.apdex_t
|
264
|
-
@slowest_transaction_threshold = sampler_config.fetch('transaction_threshold', 2.0)
|
265
|
-
if @slowest_transaction_threshold =~ /apdex_f/i
|
266
|
-
@slowest_transaction_threshold = apdex_f
|
267
|
-
end
|
268
|
-
@slowest_transaction_threshold = @slowest_transaction_threshold.to_f
|
269
|
-
|
270
|
-
log.warn "Agent is configured to send raw SQL to RPM service" if @record_sql == :raw
|
271
|
-
|
272
|
-
case
|
273
|
-
when !control.monitor_mode?
|
274
|
-
log.warn "Agent configured not to send data in this environment - edit newrelic.yml to change this"
|
275
|
-
when !control.license_key
|
276
|
-
log.error "No license key found. Please edit your newrelic.yml file and insert your license key."
|
277
|
-
when control.license_key.length != 40
|
278
|
-
log.error "Invalid license key: #{control.license_key}"
|
279
|
-
when [:passenger, :unicorn].include?(control.dispatcher)
|
280
|
-
log.info "Connecting workers after forking."
|
281
|
-
else
|
282
|
-
# Do the connect in the foreground if we are in sync mode
|
283
|
-
NewRelic::Agent.disable_all_tracing { connect(:keep_retrying => false) } if control.sync_startup
|
250
|
+
def apdex_f
|
251
|
+
(4 * NewRelic::Control.instance.apdex_t).to_f
|
252
|
+
end
|
284
253
|
|
285
|
-
|
286
|
-
|
254
|
+
def apdex_f_threshold?
|
255
|
+
sampler_config.fetch('transaction_threshold', '') =~ /apdex_f/i
|
256
|
+
end
|
287
257
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
258
|
+
def set_sql_recording!
|
259
|
+
@record_sql = sampler_config.fetch('record_sql', :obfuscated).to_sym
|
260
|
+
log_sql_transmission_warning?
|
261
|
+
end
|
262
|
+
|
263
|
+
def log_sql_transmission_warning?
|
264
|
+
log_if((@record_sql == :raw), :warn, "Agent is configured to send raw SQL to RPM service")
|
265
|
+
end
|
266
|
+
|
267
|
+
def sampler_config
|
268
|
+
control.fetch('transaction_tracer', {})
|
269
|
+
end
|
270
|
+
|
271
|
+
# this entire method should be done on the transaction
|
272
|
+
# sampler object, rather than here. We should pass in the
|
273
|
+
# sampler config.
|
274
|
+
def config_transaction_tracer
|
275
|
+
@should_send_samples = @config_should_send_samples = sampler_config.fetch('enabled', true)
|
276
|
+
@should_send_random_samples = sampler_config.fetch('random_sample', false)
|
277
|
+
@explain_threshold = sampler_config.fetch('explain_threshold', 0.5).to_f
|
278
|
+
@explain_enabled = sampler_config.fetch('explain_enabled', true)
|
279
|
+
set_sql_recording!
|
280
|
+
|
281
|
+
# default to 2.0, string 'apdex_f' will turn into your
|
282
|
+
# apdex * 4
|
283
|
+
@slowest_transaction_threshold = sampler_config.fetch('transaction_threshold', 2.0).to_f
|
284
|
+
@slowest_transaction_threshold = apdex_f if apdex_f_threshold?
|
285
|
+
end
|
286
|
+
|
287
|
+
def connect_in_foreground
|
288
|
+
NewRelic::Agent.disable_all_tracing { connect(:keep_retrying => false) }
|
289
|
+
end
|
290
|
+
|
291
|
+
def using_rubinius?
|
292
|
+
RUBY_VERSION =~ /rubinius/i
|
293
|
+
end
|
294
|
+
|
295
|
+
def using_jruby?
|
296
|
+
defined?(JRuby)
|
297
|
+
end
|
298
|
+
|
299
|
+
def using_sinatra?
|
300
|
+
defined?(Sinatra::Application)
|
301
|
+
end
|
302
|
+
|
303
|
+
# we should not set an at_exit block if people are using
|
304
|
+
# these as they don't do standard at_exit behavior per MRI/YARV
|
305
|
+
def weird_ruby?
|
306
|
+
using_rubinius? || using_jruby? || using_sinatra?
|
307
|
+
end
|
308
|
+
|
309
|
+
def install_exit_handler
|
310
|
+
if control.send_data_on_exit && !weird_ruby?
|
311
|
+
# Our shutdown handler needs to run after other shutdown handlers
|
312
|
+
at_exit { at_exit { shutdown } }
|
299
313
|
end
|
300
314
|
end
|
301
|
-
|
302
|
-
|
315
|
+
|
316
|
+
def notify_log_file_location
|
317
|
+
log_file = NewRelic::Control.instance.log_file
|
318
|
+
log_if(log_file, :info, "Agent Log found in #{log_file}")
|
319
|
+
end
|
320
|
+
|
321
|
+
def log_version_and_pid
|
322
|
+
log.info "New Relic RPM Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}"
|
323
|
+
end
|
324
|
+
|
325
|
+
def log_if(boolean, level, message)
|
326
|
+
self.log.send(level, message) if boolean
|
327
|
+
boolean
|
328
|
+
end
|
329
|
+
|
330
|
+
def log_unless(boolean, level, message)
|
331
|
+
self.log.send(level, message) unless boolean
|
332
|
+
boolean
|
333
|
+
end
|
334
|
+
|
335
|
+
def monitoring?
|
336
|
+
log_unless(control.monitor_mode?, :warn, "Agent configured not to send data in this environment - edit newrelic.yml to change this")
|
337
|
+
end
|
338
|
+
|
339
|
+
def has_license_key?
|
340
|
+
log_unless(control.license_key, :error, "No license key found. Please edit your newrelic.yml file and insert your license key.")
|
341
|
+
end
|
342
|
+
|
343
|
+
def has_correct_license_key?
|
344
|
+
has_license_key? && correct_license_length
|
345
|
+
end
|
346
|
+
|
347
|
+
def correct_license_length
|
348
|
+
key = control.license_key
|
349
|
+
log_unless((key.length == 40), :error, "Invalid license key: #{key}")
|
350
|
+
end
|
351
|
+
|
352
|
+
def using_forking_dispatcher?
|
353
|
+
log_if([:passenger, :unicorn].include?(control.dispatcher), :info, "Connecting workers after forking.")
|
354
|
+
end
|
355
|
+
|
356
|
+
def check_config_and_start_agent
|
357
|
+
return unless monitoring? && has_correct_license_key?
|
358
|
+
return if using_forking_dispatcher?
|
359
|
+
connect_in_foreground if control.sync_startup
|
360
|
+
start_worker_thread
|
361
|
+
install_exit_handler
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
include Start
|
366
|
+
|
367
|
+
def start
|
368
|
+
return if already_started? || disabled?
|
369
|
+
@started = true
|
370
|
+
@local_host = determine_host
|
371
|
+
log_dispatcher
|
372
|
+
log_app_names
|
373
|
+
config_transaction_tracer
|
374
|
+
check_config_and_start_agent
|
375
|
+
log_version_and_pid
|
376
|
+
notify_log_file_location
|
303
377
|
end
|
304
378
|
|
305
379
|
# Clear out the metric data, errors, and transaction traces. Reset the histogram data.
|
@@ -318,13 +392,77 @@ module NewRelic
|
|
318
392
|
@collector ||= control.server
|
319
393
|
end
|
320
394
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
395
|
+
module StartWorkerThread
|
396
|
+
|
397
|
+
def check_transaction_sampler_status
|
398
|
+
# disable transaction sampling if disabled by the server
|
399
|
+
# and we're not in dev mode
|
400
|
+
if control.developer_mode? || @should_send_samples
|
401
|
+
@transaction_sampler.enable
|
402
|
+
else
|
403
|
+
@transaction_sampler.disable
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def log_worker_loop_start
|
408
|
+
log.info "Reporting performance data every #{@report_period} seconds."
|
409
|
+
log.debug "Running worker loop"
|
410
|
+
end
|
411
|
+
|
412
|
+
def create_and_run_worker_loop
|
413
|
+
@worker_loop = WorkerLoop.new
|
414
|
+
@worker_loop.run(@report_period) do
|
415
|
+
harvest_and_send_timeslice_data
|
416
|
+
harvest_and_send_slowest_sample if @should_send_samples
|
417
|
+
harvest_and_send_errors if error_collector.enabled
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def handle_force_restart(error)
|
422
|
+
log.info error.message
|
423
|
+
# disconnect and start over.
|
424
|
+
# clear the stats engine
|
425
|
+
reset_stats
|
426
|
+
@metric_ids = {}
|
427
|
+
@connected = nil
|
428
|
+
# Wait a short time before trying to reconnect
|
429
|
+
sleep 30
|
430
|
+
end
|
431
|
+
|
432
|
+
def handle_force_disconnect(error)
|
433
|
+
# when a disconnect is requested, stop the current thread, which
|
434
|
+
# is the worker thread that gathers data and talks to the
|
435
|
+
# server.
|
436
|
+
log.error "RPM forced this agent to disconnect (#{error.message})"
|
437
|
+
disconnect
|
438
|
+
end
|
439
|
+
|
440
|
+
def handle_server_connection_problem(error)
|
441
|
+
log.error "Unable to establish connection with the server. Run with log level set to debug for more information."
|
442
|
+
log.debug("#{error.class.name}: #{error.message}\n#{error.backtrace.first}")
|
443
|
+
disconnect
|
444
|
+
end
|
445
|
+
|
446
|
+
def handle_other_error(error)
|
447
|
+
log.error "Terminating worker loop: #{error.class.name}: #{error.message}\n #{error.backtrace.join("\n ")}"
|
448
|
+
disconnect
|
449
|
+
end
|
450
|
+
|
451
|
+
def catch_errors
|
452
|
+
yield
|
453
|
+
rescue NewRelic::Agent::ForceRestartException => e
|
454
|
+
handle_force_restart(e)
|
455
|
+
retry
|
456
|
+
rescue NewRelic::Agent::ForceDisconnectException => e
|
457
|
+
handle_force_disconnect(e)
|
458
|
+
rescue NewRelic::Agent::ServerConnectionException => e
|
459
|
+
handle_server_connection_problem(e)
|
460
|
+
rescue Exception => e
|
461
|
+
handle_other_error(e)
|
462
|
+
end
|
463
|
+
|
464
|
+
def deferred_work!(connection_options)
|
465
|
+
catch_errors do
|
328
466
|
NewRelic::Agent.disable_all_tracing do
|
329
467
|
# We try to connect. If this returns false that means
|
330
468
|
# the server rejected us for a licensing reason and we should
|
@@ -332,51 +470,25 @@ module NewRelic
|
|
332
470
|
# that means it didn't try to connect because we're in the master.
|
333
471
|
connect(connection_options)
|
334
472
|
if @connected
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
else
|
339
|
-
@transaction_sampler.enable # otherwise ensure TT's are enabled
|
340
|
-
end
|
341
|
-
|
342
|
-
log.info "Reporting performance data every #{@report_period} seconds."
|
343
|
-
log.debug "Running worker loop"
|
344
|
-
# Note if the agent attempts to report more frequently than allowed by the server
|
345
|
-
# the server will start dropping data.
|
346
|
-
@worker_loop = WorkerLoop.new
|
347
|
-
@worker_loop.run(@report_period) do
|
348
|
-
harvest_and_send_timeslice_data
|
349
|
-
harvest_and_send_slowest_sample if @should_send_samples
|
350
|
-
harvest_and_send_errors if error_collector.enabled
|
351
|
-
end
|
473
|
+
check_transaction_sampler_status
|
474
|
+
log_worker_loop_start
|
475
|
+
create_and_run_worker_loop
|
352
476
|
else
|
353
|
-
log.debug "No connection. Worker thread
|
477
|
+
log.debug "No connection. Worker thread ending."
|
354
478
|
end
|
355
479
|
end
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
# is the worker thread that gathers data and talks to the
|
369
|
-
# server.
|
370
|
-
log.error "RPM forced this agent to disconnect (#{e.message})"
|
371
|
-
@connected = false
|
372
|
-
rescue NewRelic::Agent::ServerConnectionException => e
|
373
|
-
log.error "Unable to establish connection with the server. Run with log level set to debug for more information."
|
374
|
-
log.debug("#{e.class.name}: #{e.message}\n#{e.backtrace.first}")
|
375
|
-
@connected = false
|
376
|
-
rescue Exception => e
|
377
|
-
log.error "Terminating worker loop: #{e.class.name}: #{e}\n #{e.backtrace.join("\n ")}"
|
378
|
-
@connected = false
|
379
|
-
end # begin
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
include StartWorkerThread
|
484
|
+
|
485
|
+
# Try to launch the worker thread and connect to the server.
|
486
|
+
#
|
487
|
+
# See #connect for a description of connection_options.
|
488
|
+
def start_worker_thread(connection_options = {})
|
489
|
+
log.debug "Creating RPM worker thread."
|
490
|
+
@worker_thread = Thread.new do
|
491
|
+
deferred_work!(connection_options)
|
380
492
|
end # thread new
|
381
493
|
@worker_thread['newrelic_label'] = 'Worker Loop'
|
382
494
|
end
|
@@ -384,112 +496,189 @@ module NewRelic
|
|
384
496
|
def control
|
385
497
|
NewRelic::Control.instance
|
386
498
|
end
|
499
|
+
|
500
|
+
module Connect
|
501
|
+
attr_accessor :connect_retry_period
|
502
|
+
attr_accessor :connect_attempts
|
387
503
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
# there's a bad license key.
|
393
|
-
#
|
394
|
-
# Set keep_retrying=false to disable retrying and return asap, such as when
|
395
|
-
# invoked in the foreground. Otherwise this runs until a successful
|
396
|
-
# connection is made, or the server rejects us.
|
397
|
-
#
|
398
|
-
# * <tt>:keep_retrying => false</tt> to only try to connect once, and
|
399
|
-
# return with the connection set to nil. This ensures we may try again
|
400
|
-
# later (default true).
|
401
|
-
# * <tt>force_reconnect => true</tt> if you want to establish a new connection
|
402
|
-
# to the server before running the worker loop. This means you get a separate
|
403
|
-
# agent run and RPM sees it as a separate instance (default is false).
|
404
|
-
def connect(options)
|
405
|
-
# Don't proceed if we already connected (@connected=true) or if we tried
|
406
|
-
# to connect and were rejected with prejudice because of a license issue
|
407
|
-
# (@connected=false).
|
408
|
-
return if !@connected.nil? && !options[:force_reconnect]
|
409
|
-
keep_retrying = options[:keep_retrying].nil? || options[:keep_retrying]
|
504
|
+
def disconnect
|
505
|
+
@connected = false
|
506
|
+
true
|
507
|
+
end
|
410
508
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
509
|
+
def tried_to_connect?(options)
|
510
|
+
!(@connected.nil? || options[:force_reconnect])
|
511
|
+
end
|
512
|
+
|
513
|
+
def should_keep_retrying?(options)
|
514
|
+
@keep_retrying = (options[:keep_retrying].nil? || options[:keep_retrying])
|
515
|
+
end
|
516
|
+
|
517
|
+
def get_retry_period
|
518
|
+
return 600 if self.connect_attempts > 6
|
519
|
+
connect_attempts * 60
|
520
|
+
end
|
521
|
+
|
522
|
+
def increment_retry_period!
|
523
|
+
self.connect_retry_period=(get_retry_period)
|
524
|
+
end
|
525
|
+
|
526
|
+
def should_retry?
|
527
|
+
if @keep_retrying
|
528
|
+
self.connect_attempts=(connect_attempts + 1)
|
529
|
+
increment_retry_period!
|
530
|
+
log.info "Will re-attempt in #{connect_retry_period} seconds"
|
531
|
+
true
|
532
|
+
else
|
533
|
+
disconnect
|
534
|
+
false
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
def log_error(error)
|
539
|
+
log.error "Error establishing connection with New Relic RPM Service at #{control.server}: #{error.message}"
|
540
|
+
log.debug error.backtrace.join("\n")
|
541
|
+
end
|
542
|
+
|
543
|
+
def handle_license_error(error)
|
544
|
+
log.error error.message
|
545
|
+
log.info "Visit NewRelic.com to obtain a valid license key, or to upgrade your account."
|
546
|
+
disconnect
|
547
|
+
end
|
548
|
+
|
549
|
+
def log_seed_token
|
550
|
+
if control.validate_seed
|
551
|
+
log.debug "Connecting with validation seed/token: #{control.validate_seed}/#{control.validate_token}"
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
def environment_for_connect
|
556
|
+
control['send_environment_info'] != false ? control.local_env.snapshot : []
|
557
|
+
end
|
558
|
+
|
559
|
+
def validate_settings
|
560
|
+
{
|
561
|
+
:seed => control.validate_seed,
|
562
|
+
:token => control.validate_token
|
563
|
+
}
|
564
|
+
end
|
565
|
+
|
566
|
+
def connect_settings
|
567
|
+
{
|
423
568
|
:pid => $$,
|
424
569
|
:host => @local_host,
|
425
570
|
:app_name => control.app_names,
|
426
571
|
:language => 'ruby',
|
427
572
|
:agent_version => NewRelic::VERSION::STRING,
|
428
|
-
:environment =>
|
573
|
+
:environment => environment_for_connect,
|
429
574
|
:settings => control.settings,
|
430
|
-
:validate =>
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
575
|
+
:validate => validate_settings
|
576
|
+
}
|
577
|
+
end
|
578
|
+
def connect_to_server
|
579
|
+
log_seed_token
|
580
|
+
connect_data = invoke_remote(:connect, connect_settings)
|
581
|
+
end
|
436
582
|
|
437
|
-
|
438
|
-
|
439
|
-
|
583
|
+
def configure_error_collector!(server_enabled)
|
584
|
+
# Ask for permission to collect error data
|
585
|
+
enabled = if error_collector.config_enabled && server_enabled
|
586
|
+
error_collector.enabled = true
|
587
|
+
else
|
588
|
+
error_collector.enabled = false
|
589
|
+
end
|
590
|
+
log.debug "Errors will #{enabled ? '' : 'not '}be sent to the RPM service."
|
591
|
+
end
|
592
|
+
|
593
|
+
def enable_random_samples!(sample_rate)
|
594
|
+
@transaction_sampler.random_sampling = true
|
595
|
+
@transaction_sampler.sampling_rate = sample_rate
|
596
|
+
log.info "Transaction sampling enabled, rate = #{@transaction_sampler.sampling_rate}"
|
597
|
+
end
|
598
|
+
|
440
599
|
|
600
|
+
def configure_transaction_tracer!(server_enabled, sample_rate)
|
441
601
|
# Ask the server for permission to send transaction samples.
|
442
602
|
# determined by subscription license.
|
443
|
-
@should_send_samples = @config_should_send_samples &&
|
603
|
+
@should_send_samples = @config_should_send_samples && server_enabled
|
444
604
|
|
445
605
|
if @should_send_samples
|
446
|
-
|
447
|
-
|
448
|
-
@transaction_sampler.sampling_rate = connect_data['sampling_rate']
|
449
|
-
log.info "Transaction sampling enabled, rate = #{@transaction_sampler.sampling_rate}"
|
450
|
-
end
|
606
|
+
# I don't think this is ever true, but...
|
607
|
+
enable_random_samples!(sample_rate) if @should_send_random_samples
|
451
608
|
log.debug "Transaction tracing threshold is #{@slowest_transaction_threshold} seconds."
|
452
609
|
else
|
453
610
|
log.debug "Transaction traces will not be sent to the RPM service."
|
454
611
|
end
|
612
|
+
end
|
455
613
|
|
456
|
-
|
457
|
-
|
614
|
+
def set_collector_host!
|
615
|
+
host = invoke_remote(:get_redirect_host)
|
616
|
+
if host
|
617
|
+
@collector = control.server_from_host(host)
|
618
|
+
end
|
619
|
+
end
|
458
620
|
|
459
|
-
|
621
|
+
def query_server_for_configuration
|
622
|
+
set_collector_host!
|
623
|
+
|
624
|
+
finish_setup(connect_to_server)
|
625
|
+
end
|
626
|
+
def finish_setup(config_data)
|
627
|
+
@agent_id = config_data['agent_run_id']
|
628
|
+
@report_period = config_data['data_report_period']
|
629
|
+
@url_rules = config_data['url_rules']
|
630
|
+
|
631
|
+
log_connection!(config_data)
|
632
|
+
configure_transaction_tracer!(config_data['collect_traces'], config_data['sample_rate'])
|
633
|
+
configure_error_collector!(config_data['collect_errors'])
|
634
|
+
end
|
460
635
|
|
461
|
-
|
462
|
-
|
636
|
+
def log_connection!(config_data)
|
637
|
+
control.log! "Connected to NewRelic Service at #{@collector}"
|
638
|
+
log.debug "Agent Run = #{@agent_id}."
|
639
|
+
log.debug "Connection data = #{config_data.inspect}"
|
640
|
+
end
|
641
|
+
end
|
642
|
+
include Connect
|
463
643
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
644
|
+
# Connect to the server and validate the license. If successful,
|
645
|
+
# @connected has true when finished. If not successful, you can
|
646
|
+
# keep calling this. Return false if we could not establish a
|
647
|
+
# connection with the server and we should not retry, such as if
|
648
|
+
# there's a bad license key.
|
649
|
+
#
|
650
|
+
# Set keep_retrying=false to disable retrying and return asap, such as when
|
651
|
+
# invoked in the foreground. Otherwise this runs until a successful
|
652
|
+
# connection is made, or the server rejects us.
|
653
|
+
#
|
654
|
+
# * <tt>:keep_retrying => false</tt> to only try to connect once, and
|
655
|
+
# return with the connection set to nil. This ensures we may try again
|
656
|
+
# later (default true).
|
657
|
+
# * <tt>force_reconnect => true</tt> if you want to establish a new connection
|
658
|
+
# to the server before running the worker loop. This means you get a separate
|
659
|
+
# agent run and RPM sees it as a separate instance (default is false).
|
660
|
+
def connect(options)
|
661
|
+
# Don't proceed if we already connected (@connected=true) or if we tried
|
662
|
+
# to connect and were rejected with prejudice because of a license issue
|
663
|
+
# (@connected=false), unless we're forced to by force_reconnect.
|
664
|
+
return if tried_to_connect?(options)
|
468
665
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
else
|
486
|
-
connect_retry_period, period_msg = 5 * 60, "5 minutes"
|
487
|
-
end
|
488
|
-
log.info "Will re-attempt in #{period_msg}"
|
489
|
-
retry
|
490
|
-
else
|
491
|
-
@connected = nil
|
492
|
-
end
|
666
|
+
# wait a few seconds for the web server to boot, necessary in development
|
667
|
+
@connect_retry_period = should_keep_retrying?(options) ? 10 : 0
|
668
|
+
|
669
|
+
sleep connect_retry_period
|
670
|
+
log.debug "Connecting Process to RPM: #$0"
|
671
|
+
query_server_for_configuration
|
672
|
+
@connected_pid = $$
|
673
|
+
@connected = true
|
674
|
+
rescue NewRelic::Agent::LicenseException => e
|
675
|
+
handle_license_error(e)
|
676
|
+
rescue Timeout::Error, StandardError => e
|
677
|
+
log_error(e)
|
678
|
+
if should_retry?
|
679
|
+
retry
|
680
|
+
else
|
681
|
+
disconnect
|
493
682
|
end
|
494
683
|
end
|
495
684
|
|