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"