lib/new_relic/agent/agent.rb in newrelic_rpm-3.5.7.59 vs lib/new_relic/agent/agent.rb in newrelic_rpm-3.5.8.64.beta
- old
+ new
@@ -7,10 +7,12 @@
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'
+require 'new_relic/agent/event_listener'
+require 'new_relic/agent/cross_app_monitor'
module NewRelic
module Agent
# The Agent is a singleton that is instantiated when the plugin is
@@ -21,18 +23,19 @@
extend NewRelic::Agent::Configuration::Instance
def initialize
@launch_time = Time.now
- @metric_ids = {}
- @events = NewRelic::Agent::EventListener.new
- @stats_engine = NewRelic::Agent::StatsEngine.new
- @transaction_sampler = NewRelic::Agent::TransactionSampler.new
- @sql_sampler = NewRelic::Agent::SqlSampler.new
- @thread_profiler = NewRelic::Agent::ThreadProfiler.new
- @cross_process_monitor = NewRelic::Agent::CrossProcessMonitor.new(@events)
- @error_collector = NewRelic::Agent::ErrorCollector.new
+ @events = NewRelic::Agent::EventListener.new
+ @stats_engine = NewRelic::Agent::StatsEngine.new
+ @transaction_sampler = NewRelic::Agent::TransactionSampler.new
+ @sql_sampler = NewRelic::Agent::SqlSampler.new
+ @thread_profiler = NewRelic::Agent::ThreadProfiler.new
+ @cross_app_monitor = NewRelic::Agent::CrossAppMonitor.new(@events)
+ @error_collector = NewRelic::Agent::ErrorCollector.new
+ @transaction_rules = NewRelic::Agent::RulesEngine.new
+ @metric_rules = NewRelic::Agent::RulesEngine.new
@connect_state = :pending
@connect_attempts = 0
@last_harvest_time = Time.now
@@ -80,32 +83,29 @@
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 -
- # it returns a metric id for every metric name we send it, and
- # in the future we transmit using the metric id only
- attr_reader :metric_ids
- # in theory a set of rules applied by the agent to the output
- # of its metrics. Currently unimplemented
- attr_reader :url_rules
# a configuration for the Real User Monitoring system -
# handles things like static setup of the header for inclusion
# into pages
attr_reader :beacon_configuration
- # cross process id's and encoding
+ # cross application tracing ids and encoding
attr_reader :cross_process_id
- attr_reader :cross_process_encoding_bytes
+ attr_reader :cross_app_encoding_bytes
# service for communicating with collector
attr_accessor :service
# Global events dispatcher. This will provides our primary mechanism
# for agent-wide events, such as finishing configuration, error notification
# and request before/after from Rack.
attr_reader :events
+ # Transaction and metric renaming rules as provided by the
+ # collector on connect. The former are applied during txns,
+ # the latter during harvest.
+ attr_reader :transaction_rules
+ attr_reader :metric_rules
-
# Returns the length of the unsent errors array, if it exists,
# otherwise nil
def unsent_errors_size
@unsent_errors.length if @unsent_errors
end
@@ -185,11 +185,10 @@
if channel_id = options[:report_to_channel]
@service = NewRelic::Agent::PipeService.new(channel_id)
if connected?
@connected_pid = $$
- @metric_ids = {}
else
::NewRelic::Agent.logger.debug("Child process #{$$} not reporting to non-connected parent.")
@service.shutdown(Time.now)
disconnect
end
@@ -531,11 +530,11 @@
# this clears the data, clears connection attempts, and
# waits a while to reconnect.
def handle_force_restart(error)
::NewRelic::Agent.logger.debug error.message
reset_stats
- @metric_ids = {}
+ @service.reset_metric_id_cache if @service
@connect_state = :pending
sleep 30
end
# when a disconnect is requested, stop the current thread, which
@@ -745,16 +744,28 @@
::NewRelic::Agent.logger.debug "Server provided config: #{config_data.inspect}"
server_config = NewRelic::Agent::Configuration::ServerSource.new(config_data)
Agent.config.apply_config(server_config, 1)
log_connection!(config_data) if @service
+ add_rules_to_engine(config_data['transaction_name_rules'],
+ NewRelic::Agent.instance.transaction_rules)
+ add_rules_to_engine(config_data['metric_name_rules'],
+ NewRelic::Agent.instance.metric_rules)
+
# If you're adding something else here to respond to the server-side config,
# use Agent.instance.events.subscribe(:finished_configuring) callback instead!
@beacon_configuration = BeaconConfiguration.new
end
+ def add_rules_to_engine(rule_specifications, rules_engine)
+ return unless rule_specifications && rule_specifications.any?
+ rule_specifications.each do |rule_spec|
+ rules_engine << NewRelic::Agent::RulesEngine::Rule.new(rule_spec)
+ end
+ end
+
# Logs when we connect to the server, for debugging purposes
# - makes sure we know if an agent has not connected
def log_connection!(config_data)
::NewRelic::Agent.logger.debug "Connected to NewRelic Service at #{@service.collector.name}"
::NewRelic::Agent.logger.debug "Agent Run = #{@service.agent_id}."
@@ -770,34 +781,17 @@
end
end
end
include Connect
-
- # Serialize all the important data that the agent might want
- # to send to the server. We could be sending this to file (
- # common in short-running background transactions ) or
- # alternately we could serialize via a pipe or socket to a
- # local aggregation device
- def serialize
- accumulator = []
- accumulator[1] = harvest_transaction_traces if @transaction_sampler
- accumulator[2] = harvest_errors if @error_collector
- accumulator[0] = harvest_timeslice_data
- reset_stats
- @metric_ids = {}
- accumulator
- end
- public :serialize
-
- # Accepts data as provided by the serialize method and merges
+ # Accepts an array of (metrics, transaction_traces, errors) and merges
# it into our current collection of data to send. Can be
# dangerous if we re-merge the same data more than once - it
# will be sent multiple times.
def merge_data_from(data)
metrics, transaction_traces, errors = data
- @stats_engine.merge_data(metrics) if metrics
+ @stats_engine.merge!(metrics) if metrics
if transaction_traces && transaction_traces.respond_to?(:any?) &&
transaction_traces.any?
if @traces
@traces += transaction_traces
else
@@ -829,12 +823,12 @@
# * <tt>force_reconnect => true</tt> if you want to establish a new connection
# to the server before running the worker loop. This means you get a separate
# agent run and New Relic sees it as a separate instance (default is false).
def connect(options={})
defaults = {
- :keep_retrying => true,
- :force_reconnect => false
+ :keep_retrying => Agent.config[:keep_retrying],
+ :force_reconnect => Agent.config[:force_reconnect]
}
opts = defaults.merge(options)
return unless should_connect?(opts[:force_reconnect])
@@ -874,43 +868,29 @@
def harvest_timeslice_data(time=Time.now)
# this creates timeslices that are harvested below
NewRelic::Agent::BusyCalculator.harvest_busy
@unsent_timeslice_data ||= {}
- @unsent_timeslice_data = @stats_engine.harvest_timeslice_data(@unsent_timeslice_data, @metric_ids)
+ @unsent_timeslice_data = @stats_engine.harvest_timeslice_data(@unsent_timeslice_data,
+ @metric_rules)
@unsent_timeslice_data
end
- # takes an array of arrays of spec and id, adds it into the
- # metric cache so we can save the collector some work by
- # sending integers instead of strings
- def fill_metric_id_cache(pairs_of_specs_and_ids)
- Array(pairs_of_specs_and_ids).each do |metric_spec_hash, metric_id|
- metric_spec = MetricSpec.new(metric_spec_hash['name'],
- metric_spec_hash['scope'])
- @metric_ids[metric_spec] = metric_id
- end
- end
-
# note - exceptions are logged in invoke_remote. If an exception is encountered here,
# then the metric data is downsampled for another
# transmission later
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)
- # In this version of the protocol
- # we get back an assoc array of spec to id.
- metric_specs_and_ids = []
begin
- metric_specs_and_ids = @service.metric_data(@last_harvest_time.to_f,
- now.to_f,
- @unsent_timeslice_data.values)
+ @service.metric_data(@last_harvest_time.to_f,
+ now.to_f,
+ @unsent_timeslice_data)
rescue UnrecoverableServerException => e
::NewRelic::Agent.logger.debug e.message
end
- fill_metric_id_cache(metric_specs_and_ids)
::NewRelic::Agent.logger.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@service.agent_id}) in #{Time.now - now} seconds"
# if we successfully invoked this web service, then clear the unsent message cache.
@unsent_timeslice_data = {}