lib/new_relic/agent/agent.rb in newrelic_rpm-3.4.1 vs lib/new_relic/agent/agent.rb in newrelic_rpm-3.4.2.beta1

- old
+ new

@@ -4,19 +4,22 @@ require 'logger' require 'zlib' require 'stringio' require 'new_relic/agent/new_relic_service' require 'new_relic/agent/pipe_service' +require 'new_relic/agent/configuration/manager' module NewRelic module Agent # The Agent is a singleton that is instantiated when the plugin is # activated. It collects performance data from ruby applications # in realtime as the application runs, and periodically sends that # data to the NewRelic server. class Agent + extend NewRelic::Agent::Configuration::Instance + def initialize @launch_time = Time.now @metric_ids = {} @stats_engine = NewRelic::Agent::StatsEngine.new @@ -29,12 +32,12 @@ @last_harvest_time = Time.now @obfuscator = lambda {|sql| NewRelic::Agent::Database.default_sql_obfuscator(sql) } @forked = false # FIXME: temporary work around for RUBY-839 - if control.monitor_mode? - @service = NewRelic::Agent::NewRelicService.new(control.license_key, control.server) + if Agent.config[:monitor_mode] + @service = NewRelic::Agent::NewRelicService.new end end # contains all the class-level methods for NewRelic::Agent::Agent module ClassMethods @@ -159,13 +162,13 @@ @connected_pid = $$ @metric_ids = {} end # log.debug "Agent received after_fork notice in #$$: [#{control.agent_enabled?}; monitor=#{control.monitor_mode?}; connected: #{@connected.inspect}; thread=#{@worker_thread.inspect}]" - return if !control.agent_enabled? or - !control.monitor_mode? or - @connected == false or + return if !Agent.config[:agent_enabled] || + !Agent.config[:monitor_mode] || + @connected == false || @worker_thread && @worker_thread.alive? log.info "Starting the worker thread in #$$ after forking." # Clear out stats that are left over from parent process @@ -197,11 +200,11 @@ # # Options: # :force_send => (true/false) # force the agent to send data # before shutting down def shutdown(options={}) - run_loop_before_exit = options.fetch(:force_send, false) + run_loop_before_exit = Agent.config[:force_send] return if not started? if @worker_loop @worker_loop.run_task if run_loop_before_exit @worker_loop.stop end @@ -209,11 +212,11 @@ log.debug "Starting Agent shutdown" # if litespeed, then ignore all future SIGUSR1 - it's # litespeed trying to shut us down - if control.dispatcher == :litespeed + if Agent.config[:dispatcher] == :litespeed Signal.trap("SIGUSR1", "IGNORE") Signal.trap("SIGTERM", "IGNORE") end begin @@ -222,10 +225,14 @@ end rescue => e log.error e log.error e.backtrace.join("\n") end + NewRelic::Agent.config.remove_config do |config| + config.class == NewRelic::Agent::Configuration::ManualSource || + config.class == NewRelic::Agent::Configuration::ServerSource + end @started = nil end # Tells the statistics engine we are starting a new transaction def start_transaction @@ -292,25 +299,25 @@ # The agent is disabled when it is not force enabled by the # 'agent_enabled' option (e.g. in a manual start), or # enabled normally through the configuration file def disabled? - !control.agent_enabled? + !Agent.config[:agent_enabled] end # Logs the dispatcher to the log file to assist with # debugging. When no debugger is present, logs this fact to # assist with proper dispatcher detection def log_dispatcher - dispatcher_name = control.dispatcher.to_s + dispatcher_name = Agent.config[:dispatcher].to_s return if log_if(dispatcher_name.empty?, :info, "No dispatcher detected.") log.info "Dispatcher: #{dispatcher_name}" end # Logs the configured application names def log_app_names - log.info "Application: #{control.app_names.join(", ")}" + log.info "Application: #{Agent.config.app_names.join(", ")}" 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 @@ -336,11 +343,11 @@ # Installs our exit handler, which exploits the weird # behavior of at_exit blocks to make sure it runs last, by # doing an at_exit within an at_exit block. def install_exit_handler - if control.send_data_on_exit && !weird_ruby? + if Agent.config[:send_data_on_exit] && !weird_ruby? # Our shutdown handler needs to run after other shutdown handlers at_exit { at_exit { shutdown } } end end @@ -378,45 +385,46 @@ end # Warn the user if they have configured their agent not to # send data, that way we can see this clearly in the log file def monitoring? - log_unless(control.monitor_mode?, :warn, "Agent configured not to send data in this environment - edit newrelic.yml to change this") + log_unless(Agent.config[:monitor_mode], :warn, "Agent configured not to send data in this environment - edit newrelic.yml to change this") end # Tell the user when the license key is missing so they can # fix it by adding it to the file def has_license_key? - log_unless(control.license_key, :error, "No license key found. Please edit your newrelic.yml file and insert your license key.") + log_unless(Agent.config[:license_key], :error, "No license key found. Please edit your newrelic.yml file and insert your license key.") end # A correct license key exists and is of the proper length def has_correct_license_key? has_license_key? && correct_license_length end # A license key is an arbitrary 40 character string, # usually looks something like a SHA1 hash def correct_license_length - key = control.license_key + key = Agent.config[:license_key] log_unless((key.length == 40), :error, "Invalid license key: #{key}") end # If we're using a dispatcher that forks before serving # requests, we need to wait until the children are forked # before connecting, otherwise the parent process sends odd data def using_forking_dispatcher? - log_if([:passenger, :unicorn].include?(control.dispatcher), :info, "Connecting workers after forking.") + log_if([:passenger, :unicorn].include?(Agent.config[:dispatcher]), + :info, "Connecting workers after forking.") end # Sanity-check the agent configuration and start the agent, # setting up the worker thread and the exit handler to shut # down the agent def check_config_and_start_agent return unless monitoring? && has_correct_license_key? return if using_forking_dispatcher? - connect_in_foreground if control.sync_startup + connect_in_foreground if Agent.config[:sync_startup] start_worker_thread install_exit_handler end end @@ -454,21 +462,21 @@ module StartWorkerThread # disable transaction sampling if disabled by the server # and we're not in dev mode def check_transaction_sampler_status - if control.developer_mode? || @should_send_samples + if Agent.config[:developer_mode] || @should_send_samples @transaction_sampler.enable else @transaction_sampler.disable end end def check_sql_sampler_status # disable sql sampling if disabled by the server # and we're not in dev mode - if @sql_sampler.config.fetch('enabled', true) && ['raw', 'obfuscated'].include?(@sql_sampler.config.fetch('record_sql', 'obfuscated').to_s) && @transaction_sampler.config.fetch('enabled', true) + if Agent.config[:'slow_sql.enabled'] && ['raw', 'obfuscated'].include?(Agent.config[:'slow_sql.record_sql']) && Agent.config[:'transaction_tracer.enabled'] @sql_sampler.enable else @sql_sampler.disable end end @@ -671,43 +679,43 @@ # If we are using a seed and token to validate the agent, we # should debug log that fact so that debug logs include a # clue that token authentication is what will be used def log_seed_token - if control.validate_seed - log.debug "Connecting with validation seed/token: #{control.validate_seed}/#{control.validate_token}" + if Agent.config[:validate_seed] + log.debug "Connecting with validation seed/token: #{Agent.config[:validate_seed]}/#{Agent.config[:validate_token]}" end end # Checks whether we should send environment info, and if so, # returns the snapshot from the local environment def environment_for_connect - control['send_environment_info'] != false ? control.local_env.snapshot : [] + Agent.config[:send_environment_info] ? Control.instance.local_env.snapshot : [] end # These validation settings are used for cases where a # dynamic server is spun up for clients - partners can # include a seed and token to indicate that the host is # allowed to connect, rather than setting a unique hostname def validate_settings { - :seed => control.validate_seed, - :token => control.validate_token + :seed => Agent.config[:validate_seed], + :token => Agent.config[:validate_token] } end # Initializes the hash of settings that we send to the # server. Returns a literal hash containing the options def connect_settings { :pid => $$, :host => @local_host, - :app_name => control.app_names, + :app_name => Agent.config.app_names, :language => 'ruby', :agent_version => NewRelic::VERSION::STRING, :environment => environment_for_connect, - :settings => control.settings, + :settings => Agent.config.flattened_config, :validate => validate_settings } end # Does some simple logging to make sure that our seed and @@ -753,27 +761,25 @@ # sampler config. def config_transaction_tracer # Reconfigure the transaction tracer @transaction_sampler.configure! @sql_sampler.configure! - @should_send_samples = @config_should_send_samples = @transaction_sampler.config.fetch('enabled', true) - @should_send_random_samples = @transaction_sampler.config.fetch('random_sample', false) + @should_send_samples = @config_should_send_samples = Agent.config[:'transaction_tracer.enabled'] + @should_send_random_samples = Agent.config[:'transaction_tracer.random_sample'] set_sql_recording! # default to 2.0, string 'apdex_f' will turn into your # apdex * 4 - @slowest_transaction_threshold = @transaction_sampler.config.fetch('transaction_threshold', 2.0).to_f - @slowest_transaction_threshold = apdex_f if apdex_f_threshold? + @slowest_transaction_threshold = Agent.config[:'transaction_tracer.transaction_threshold'] end # Enables or disables the transaction tracer and sets its # options based on the options provided to the # method. def configure_transaction_tracer!(server_enabled, sample_rate) # Ask the server for permission to send transaction samples. # determined by subscription license. - @transaction_sampler.config['enabled'] = server_enabled @sql_sampler.configure! @should_send_samples = @config_should_send_samples && server_enabled if @should_send_samples # I don't think this is ever true, but... @@ -787,27 +793,19 @@ end end # apdex_f is always 4 times the apdex_t def apdex_f - (4 * NewRelic::Control.instance.apdex_t).to_f + (4 * Agent.config[:apdex_t]).to_f end - # If the transaction threshold is set to the string - # 'apdex_f', we use 4 times the apdex_t value to record - # transactions. This gears well with using apdex since you - # will attempt to send any transactions that register as 'failing' - def apdex_f_threshold? - @transaction_sampler.config.fetch('transaction_threshold', '') =~ /apdex_f/i - end - # Sets the sql recording configuration by trying to detect # any attempt to disable the sql collection - 'off', # 'false', 'none', and friends. Otherwise, we accept 'raw', # and unrecognized values default to 'obfuscated' def set_sql_recording! - record_sql_config = @transaction_sampler.config.fetch('record_sql', :obfuscated) + record_sql_config = Agent.config[:'transaction_tracer.record_sql'] case record_sql_config.to_s when 'off' @record_sql = :off when 'none' @record_sql = :off @@ -826,21 +824,10 @@ # - they should probably be using ssl when this is true def log_sql_transmission_warning? log.warn("Agent is configured to send raw SQL to the service") if @record_sql == :raw end - # Asks the collector to tell us which sub-collector we - # should be reporting to, and then does the name resolution - # on that host so we don't block on DNS during the normal - # course of agent processing -# def set_collector_host! -# host = invoke_remote(:get_redirect_host) -# if host -# @collector = control.server_from_host(host) -# end -# end - # Sets the collector host and connects to the server, then # invokes the final configuration with the returned data def query_server_for_configuration finish_setup(connect_to_server) end @@ -852,23 +839,24 @@ # # Can accommodate most arbitrary data - anything extra is # ignored unless we say to do something with it here. def finish_setup(config_data) return if config_data == nil - @service.agent_id = config_data['agent_run_id'] + + @service.agent_id = config_data['agent_run_id'] if @service @report_period = config_data['data_report_period'] @url_rules = config_data['url_rules'] @beacon_configuration = BeaconConfiguration.new(config_data) - @server_side_config_enabled = config_data['listen_to_server_config'] - if @server_side_config_enabled + if config_data['listen_to_server_config'] log.info "Using config from server" log.debug "Server provided config: #{config_data.inspect}" + server_config = NewRelic::Agent::Configuration::ServerSource.new(config_data) + Agent.config.apply_config(server_config, 1) end - control.merge_server_side_config(config_data) if @server_side_config_enabled config_transaction_tracer - log_connection!(config_data) + log_connection!(config_data) if @service configure_transaction_tracer!(config_data['collect_traces'], config_data['sample_rate']) configure_error_collector!(config_data['collect_errors']) end # Logs when we connect to the server, for debugging purposes