lib/new_relic/agent/agent.rb in newrelic_rpm-3.5.2.17 vs lib/new_relic/agent/agent.rb in newrelic_rpm-3.5.3.24
- old
+ new
@@ -6,10 +6,11 @@
require 'stringio'
require 'new_relic/agent/new_relic_service'
require 'new_relic/agent/pipe_service'
require 'new_relic/agent/configuration/manager'
require 'new_relic/agent/database'
+require 'new_relic/agent/thread_profiler'
module NewRelic
module Agent
# The Agent is a singleton that is instantiated when the plugin is
@@ -24,10 +25,11 @@
@metric_ids = {}
@stats_engine = NewRelic::Agent::StatsEngine.new
@transaction_sampler = NewRelic::Agent::TransactionSampler.new
@sql_sampler = NewRelic::Agent::SqlSampler.new
+ @thread_profiler = NewRelic::Agent::ThreadProfiler.new
@error_collector = NewRelic::Agent::ErrorCollector.new
@connect_attempts = 0
@last_harvest_time = Time.now
@obfuscator = lambda {|sql| NewRelic::Agent::Database.default_sql_obfuscator(sql) }
@@ -68,10 +70,12 @@
# the statistics engine that holds all the timeslice data
attr_reader :stats_engine
# the transaction sampler that handles recording transactions
attr_reader :transaction_sampler
attr_reader :sql_sampler
+ # begins a thread profile session when instructed by agent commands
+ attr_reader :thread_profiler
# error collector is a simple collection of recorded errors
attr_reader :error_collector
# whether we should record raw, obfuscated, or no sql
attr_reader :record_sql
# a cached set of metric_ids to save the collector some time -
@@ -590,14 +594,13 @@
# Try to launch the worker thread and connect to the server.
#
# See #connect for a description of connection_options.
def start_worker_thread(connection_options = {})
log.debug "Creating Ruby Agent worker thread."
- @worker_thread = Thread.new do
+ @worker_thread = NewRelic::Agent::Thread.new('Worker Loop') do
deferred_work!(connection_options)
- end # thread new
- @worker_thread['newrelic_label'] = 'Worker Loop'
+ end
end
# A shorthand for NewRelic::Control.instance
def control
NewRelic::Control.instance
@@ -978,11 +981,11 @@
options[:record_sql] = NewRelic::Agent::Database.record_sql_method
end
if Agent.config[:'transaction_tracer.explain_enabled']
options[:explain_sql] = Agent.config[:'transaction_tracer.explain_threshold']
end
- traces = @traces.collect {|trace| trace.prepare_to_send(options)}
+ traces = @traces.map {|trace| trace.prepare_to_send(options) }
@service.transaction_sample_data(traces)
log.debug "Sent slowest sample (#{@service.agent_id}) in #{Time.now - now} seconds"
rescue UnrecoverableServerException => e
log.debug e.message
end
@@ -992,10 +995,21 @@
# the slowest sample around - it has been sent already and we
# can clear the collection and move on
@traces = nil
end
+ def harvest_and_send_thread_profile(disconnecting=false)
+ @thread_profiler.stop(true) if disconnecting
+
+ if @thread_profiler.finished?
+ profile = @thread_profiler.harvest
+
+ log.debug "Sending thread profile #{profile.profile_id}"
+ @service.profile_data(profile)
+ end
+ end
+
# Gets the collection of unsent errors from the error
# collector. We pass back in an existing array of errors that
# may be left over from a previous send
def harvest_errors
@unsent_errors = @error_collector.harvest_errors(@unsent_errors)
@@ -1021,17 +1035,41 @@
# 20 instances to prevent leakage
@unsent_errors = []
end
end
- def transmit_data
+ # Only JSON marshalling appears to work with collector on
+ # get_agent_commands and agent_command_results. We only support
+ # these features on Ruby versions that can hack JSON out of the box
+ def agent_commands_supported?
+ RUBY_VERSION >= "1.9.2"
+ end
+
+ def check_for_agent_commands
+ if !agent_commands_supported?
+ log.debug("Skipping agent commands, as they aren't supported on this environment")
+ return
+ end
+
+ commands = @service.get_agent_commands
+ log.debug "Received get_agent_commands = #{commands}"
+
+ @thread_profiler.respond_to_commands(commands) do |command_id, error|
+ @service.agent_command_results(command_id, error)
+ end
+ end
+
+ def transmit_data(disconnecting=false)
now = Time.now
log.debug "Sending data to New Relic Service"
harvest_and_send_errors
harvest_and_send_slowest_sample
harvest_and_send_slowest_sql
harvest_and_send_timeslice_data
+ harvest_and_send_thread_profile(disconnecting)
+
+ check_for_agent_commands
rescue => e
retry_count ||= 0
retry_count += 1
if retry_count <= 1
log.debug "retrying transmit_data after #{e}"
@@ -1053,10 +1091,11 @@
# disconnect, so that the parent process can continue to send data
def graceful_disconnect
if @connected
begin
@service.request_timeout = 10
- transmit_data
+ transmit_data(true)
+
if @connected_pid == $$ && !@service.kind_of?(NewRelic::Agent::NewRelicService)
log.debug "Sending New Relic service agent run shutdown message"
@service.shutdown(Time.now.to_f)
else
log.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown"