lib/new_relic/agent/agent.rb in newrelic_rpm-3.0.1 vs lib/new_relic/agent/agent.rb in newrelic_rpm-3.1.0.beta1

- old
+ new

@@ -62,10 +62,22 @@ attr_reader :histogram attr_reader :metric_ids attr_reader :url_rules attr_reader :beacon_configuration + def unsent_errors_size + @unsent_errors.length if @unsent_errors + end + + def unsent_traces_size + @traces.length if @traces + end + + def unsent_timeslice_data + @unsent_timeslice_data.keys.length + end + def record_transaction(duration_seconds, options={}) is_error = options['is_error'] || options['error_message'] || options['exception'] metric = options['metric'] metric ||= options['uri'] # normalize this with url rules raise "metric or uri arguments required" unless metric @@ -148,13 +160,15 @@ def connected? @connected end # Attempt a graceful shutdown of the agent. - def shutdown + def shutdown(options={}) + run_loop_before_exit = options.fetch(:force_send, false) return if not started? if @worker_loop + @worker_loop.run_task if run_loop_before_exit @worker_loop.stop log.debug "Starting Agent shutdown" # if litespeed, then ignore all future SIGUSR1 - it's @@ -429,12 +443,13 @@ end def create_and_run_worker_loop @worker_loop = WorkerLoop.new @worker_loop.run(@report_period) do - harvest_and_send_slowest_sample if @should_send_samples - harvest_and_send_errors if error_collector.enabled + NewRelic::Agent.load_data + harvest_and_send_errors + harvest_and_send_slowest_sample harvest_and_send_timeslice_data end end def handle_force_restart(error) @@ -660,10 +675,41 @@ log.debug "Connection data = #{config_data.inspect}" end end include Connect + def serialize + accumulator = [] + accumulator[1] = harvest_transaction_traces if @transaction_sampler + accumulator[2] = harvest_errors if @error_collector + accumulator[0] = harvest_timeslice_data + accumulator + end + + public :serialize + + def merge_data_from(data) + metrics, transaction_traces, errors = data + @stats_engine.merge_data(metrics) if metrics + if transaction_traces + if @traces + @traces = @traces + transaction_traces + else + @traces = transaction_traces + end + end + if errors + if @unsent_errors + @unsent_errors = @unsent_errors + errors + else + @unsent_errors = errors + end + end + end + + public :merge_data_from + # Connect to the server and validate the license. If successful, # @connected has true when finished. If not successful, you can # keep calling this. Return false if we could not establish a # connection with the server and we should not retry, such as if # there's a bad license key. @@ -713,36 +759,43 @@ def is_application_spawner? $0 =~ /ApplicationSpawner|^unicorn\S* master/ end - def harvest_and_send_timeslice_data - + def harvest_timeslice_data(time=Time.now) + # this creates timeslices that are harvested below NewRelic::Agent::BusyCalculator.harvest_busy - now = Time.now - NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point(0.0) - NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/metric_data').record_data_point(0.0) - @unsent_timeslice_data ||= {} @unsent_timeslice_data = @stats_engine.harvest_timeslice_data(@unsent_timeslice_data, @metric_ids) + @unsent_timeslice_data + end + def fill_metric_id_cache(pairs_of_specs_and_ids) + Array(pairs_of_specs_and_ids).each do |metric_spec, metric_id| + @metric_ids[metric_spec] = metric_id + end + end + + def harvest_and_send_timeslice_data + now = Time.now + NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point(0.0) + NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/metric_data').record_data_point(0.0) + harvest_timeslice_data(now) begin # In this version of the protocol, we get back an assoc array of spec to id. - metric_ids = invoke_remote(:metric_data, @agent_id, + metric_specs_and_ids = invoke_remote(:metric_data, @agent_id, @last_harvest_time.to_f, now.to_f, @unsent_timeslice_data.values) rescue Timeout::Error # assume that the data was received. chances are that it was - metric_ids = nil + metric_specs_and_ids = [] end - metric_ids.each do | spec, id | - @metric_ids[spec] = id - end if metric_ids + fill_metric_id_cache(metric_specs_and_ids) log.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@agent_id}) in #{Time.now - now} seconds" # if we successfully invoked this web service, then clear the unsent message cache. @unsent_timeslice_data = {} @@ -752,13 +805,17 @@ # note - exceptions are logged in invoke_remote. If an exception is encountered here, # then the metric data is downsampled for another timeslices end - def harvest_and_send_slowest_sample + def harvest_transaction_traces @traces = @transaction_sampler.harvest(@traces, @slowest_transaction_threshold) + @traces + end + def harvest_and_send_slowest_sample + harvest_transaction_traces unless @traces.empty? now = Time.now log.debug "Sending (#{@traces.length}) transaction traces" begin # take the traces and prepare them for sending across the @@ -790,12 +847,17 @@ # exception is encountered here, then the slowest sample of is # determined of the entire period since the last reported # sample. end - def harvest_and_send_errors + def harvest_errors @unsent_errors = @error_collector.harvest_errors(@unsent_errors) + @unsent_errors + end + + def harvest_and_send_errors + harvest_errors if @unsent_errors && @unsent_errors.length > 0 log.debug "Sending #{@unsent_errors.length} errors" begin invoke_remote :error_data, @agent_id, @unsent_errors rescue PostTooBigException @@ -923,18 +985,20 @@ rescue SystemCallError, SocketError => e # These include Errno connection errors raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to the server: #{e}" ensure NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point((Time.now - now).to_f) - NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/' + method.to_s).record_data_point((Time.now - now).to_f) + NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/' + method.to_s).record_data_point((Time.now - now).to_f) end def graceful_disconnect if @connected begin @request_timeout = 10 - log.debug "Flushing unsent metric data to server" - @worker_loop.run_task +# log.debug "Flushing unsent metric data to server" +# harvest_and_send_timeslice_data + log.debug "Serializing agent data to disk" + NewRelic::Agent.save_data if @connected_pid == $$ log.debug "Sending RPM service agent run shutdown message" invoke_remote :shutdown, @agent_id, Time.now.to_f else log.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown"