lib/new_relic/agent/agent.rb in newrelic_rpm-3.6.2.96 vs lib/new_relic/agent/agent.rb in newrelic_rpm-3.6.3.103.beta
- old
+ new
@@ -14,10 +14,11 @@
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'
+require 'new_relic/agent/request_sampler'
require 'new_relic/environment_report'
module NewRelic
module Agent
@@ -38,10 +39,11 @@
@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
+ @request_sampler = NewRelic::Agent::RequestSampler.new(@events)
@connect_state = :pending
@connect_attempts = 0
@last_harvest_time = Time.now
@@ -49,21 +51,10 @@
# FIXME: temporary work around for RUBY-839
if Agent.config[:monitor_mode]
@service = NewRelic::Agent::NewRelicService.new
end
-
- txn_tracer_enabler = Proc.new do
- if NewRelic::Agent.config[:'transaction_tracer.enabled'] ||
- NewRelic::Agent.config[:developer_mode]
- @stats_engine.transaction_sampler = @transaction_sampler
- else
- @stats_engine.transaction_sampler = nil
- end
- end
- Agent.config.register_callback(:'transaction_tracer.enabled', &txn_tracer_enabler)
- Agent.config.register_callback(:developer_mode, &txn_tracer_enabler)
end
# contains all the class-level methods for NewRelic::Agent::Agent
module ClassMethods
# Should only be called by NewRelic::Control - returns a
@@ -202,10 +193,12 @@
disconnected? ||
@worker_thread && @worker_thread.alive?
::NewRelic::Agent.logger.debug "Starting the worker thread in #{$$} after forking."
+ reset_objects_with_locks
+
# Clear out stats that are left over from parent process
reset_stats
# Don't ever check to see if this is a spawner. If we're in a forked process
# I'm pretty sure we're not also forking new instances.
@@ -322,11 +315,11 @@
# Log startup information that we almost always want to know
def log_startup
log_environment
log_dispatcher
- log_app_names
+ log_app_name
end
# Log the environment the app thinks it's running in.
# Useful in debugging, as this is the key for config YAML lookups.
def log_environment
@@ -340,18 +333,18 @@
dispatcher_name = Agent.config[:dispatcher].to_s
return if log_if(dispatcher_name.empty?, :info, "No known dispatcher detected.")
::NewRelic::Agent.logger.info "Dispatcher: #{dispatcher_name}"
end
+ def log_app_name
+ ::NewRelic::Agent.logger.info "Application: #{Agent.config.app_names.join(", ")}"
+ end
+
# Logs the configured application names
- def log_app_names
+ def app_name_configured?
names = Agent.config.app_names
- if names.respond_to?(:any?) && names.any?
- ::NewRelic::Agent.logger.info "Application: #{names.join(", ")}"
- else
- ::NewRelic::Agent.logger.error 'Unable to determine application name. Please set the application name in your newrelic.yml or in a NEW_RELIC_APP_NAME environment variable.'
- end
+ return names.respond_to?(:any?) && names.any?
end
# Connecting in the foreground blocks further startup of the
# agent until we have a connection - useful in cases where
# you're trying to log a very-short-running process and want
@@ -474,19 +467,36 @@
end
end
include Start
- # Logs a bunch of data and starts the agent, if needed
- def start
- return if already_started? || disabled?
+ # Check to see if the agent should start, returning +true+ if it should.
+ def agent_should_start?
+ return false if already_started? || disabled?
+
if defer_for_resque?
::NewRelic::Agent.logger.debug "Deferring startup for Resque in case it daemonizes"
- return
+ return false
end
+ unless app_name_configured?
+ NewRelic::Agent.logger.error "No application name configured.",
+ "The Agent cannot start without at least one. Please check your ",
+ "newrelic.yml and ensure that it is valid and has at least one ",
+ "value set for app_name in the #{NewRelic::Control.instance.env} ",
+ "environment."
+ return false
+ end
+
+ return true
+ end
+
+ # Logs a bunch of data and starts the agent, if needed
+ def start
+ return unless agent_should_start?
+
@started = true
@local_host = determine_host
log_startup
check_config_and_start_agent
log_version_and_pid
@@ -501,10 +511,17 @@
@unsent_timeslice_data = {}
@last_harvest_time = Time.now
@launch_time = Time.now
end
+ # Clear out state for any objects that we know lock from our parents
+ # This is necessary for cases where we're in a forked child and Ruby
+ # might be holding locks for background thread that aren't there anymore.
+ def reset_objects_with_locks
+ @stats_engine = NewRelic::Agent::StatsEngine.new
+ end
+
def add_harvest_sampler(subclass)
begin
::NewRelic::Agent.logger.debug "#{subclass.name} not supported on this platform." and return unless subclass.supported_on_this_platform?
sampler = subclass.new
if subclass.use_harvest_sampler?
@@ -1011,10 +1028,21 @@
# 20 instances to prevent leakage
@unsent_errors = []
end
end
+ # Fetch samples from the RequestSampler and send them.
+ def harvest_and_send_analytic_event_data
+ samples = @request_sampler.samples
+ @service.analytic_event_data(samples) unless samples.empty?
+ @request_sampler.reset
+ rescue => e
+ NewRelic::Agent.logger.debug "Failed to sent analytics; throttling to conserve memory"
+ @request_sampler.throttle
+ raise
+ end
+
def check_for_agent_commands
commands = @service.get_agent_commands
::NewRelic::Agent.logger.debug "Received get_agent_commands = #{commands.inspect}"
@thread_profiler.respond_to_commands(commands) do |command_id, error|
@@ -1029,9 +1057,10 @@
@service.session do # use http keep-alive
harvest_and_send_errors
harvest_and_send_slowest_sample
harvest_and_send_slowest_sql
harvest_and_send_timeslice_data
+ harvest_and_send_analytic_event_data
harvest_and_send_thread_profile(disconnecting)
check_for_agent_commands
end
rescue EOFError => e