# encoding: utf-8 require 'socket' require 'net/https' require 'net/http' require 'logger' require 'zlib' require 'stringio' require 'one_apm/support/event_buffer/sampled_buffer' require 'one_apm/agent/harvester' require 'one_apm/support/hostname' require 'one_apm/support/ip' require 'one_apm/support/environment_report' require 'one_apm/configuration' require 'one_apm/collector/collector_service' require 'one_apm/collector/containers/agent_command_router' require 'one_apm/collector/containers/transaction_event_aggregator' require 'one_apm/collector/containers/custom_event_aggregator' require 'one_apm/collector/containers/utilization_data' require 'one_apm/collector/support/forked_process_service' require 'one_apm/collector/support/sampler_collection' require 'one_apm/agent/database' require 'one_apm/support/event/event_listener' require 'one_apm/agent/cross_app/cross_app_monitor' require 'one_apm/agent/synthetics_monitor' require 'one_apm/support/event_buffer/synthetics_event_buffer' require 'one_apm/agent/javascript_instrumentor' require 'one_apm/support/vm/monotonic_gc_profiler' require 'one_apm/agent/agent/start' require 'one_apm/agent/agent/start_worker_thread' require 'one_apm/agent/agent/connect' require 'one_apm/agent/agent/helpers' require 'one_apm/agent/agent/container_data_manager' require 'one_apm/agent/agent/forkable_dispatcher_functions' require 'one_apm/agent/agent/restart_monitor' require 'one_apm/agent/agent/restart' require 'one_apm/agent/agent/cross_app_samples_sender' require 'one_apm/agent/agent/rule_fetcher' module OneApm module Agent class Agent include OneApm::Agent::Agent::Start include OneApm::Agent::Agent::StartWorkerThread include OneApm::Agent::Agent::Connect include OneApm::Agent::Agent::Helpers include OneApm::Agent::Agent::ContainerDataManager include OneApm::Agent::Agent::ForkableDispatcherFunctions include OneApm::Agent::Agent::RuleFetcher attr_reader :record_sql attr_reader :javascript_instrumentor attr_reader :cross_process_id attr_reader :cross_app_encoding_bytes attr_reader :cross_app_monitor attr_accessor :service attr_reader :events attr_reader :transaction_rules attr_accessor :external_rename_rules attr_reader :harvester attr_reader :harvest_samplers attr_reader :harvest_lock attr_reader :monotonic_gc_profiler def self.instance @instance ||= self.new end def self.config OneApm::Manager.config end def initialize start_service @events = OneApm::Support::EventListener.new init_containers OneApm::Agent::SyntheticsMonitor.new @events OneApm::Agent::RestartMonitor.new @cross_app_monitor = OneApm::Agent::CrossAppMonitor.new(@events) @transaction_rules = OneApm::Support::RulesEngine.new @harvest_samplers = OneApm::Collector::SamplerCollection.new(@events) @monotonic_gc_profiler = OneApm::Support::VM::MonotonicGCProfiler.new @javascript_instrumentor = OneApm::Agent::JavascriptInstrumentor.new(@events) @restart = OneApm::Agent::Restart.new(@events) @cross_app_samples_sender = OneApm::Agent::CrossAppSamplesSender.new(@events, self) @harvester = OneApm::Agent::Harvester.new(@events) @after_fork_lock = Mutex.new @connect_state = :pending @connect_attempts = 0 @environment_report = nil @harvest_lock = Mutex.new end def probe OneApm::Probe.instance end def start_service if OneApm::Manager.config[:monitor_mode] && !@service @service = OneApm::Collector::CollectorService.new end end def start return unless agent_should_start? log_startup check_config_and_start_agent log_version_and_pid events.subscribe(:finished_configuring) do log_ignore_url_regexes end end def shutdown(options = {}) return if not started? OneApm::Manager.logger.info "Starting Agent shutdown" stop_event_loop untraced_graceful_disconnect OneApm::Manager.revert_to_default_configuration @started = nil OneApm::Probe.reset end def agent_should_start? return false if already_started? || disabled? || defer_for_background_jobs? unless app_name_configured? && tier_name_configured? OneApm::Manager.logger.error "No application name or tier name configured in #{probe.env} environment" false else true end end def connect(options={}) opts = { :keep_retrying => OneApm::Manager.config[:keep_retrying], :force_reconnect => OneApm::Manager.config[:force_reconnect] }.merge(options) return unless should_connect?(opts[:force_reconnect]) OneApm::Manager.logger.debug "Connecting Process to OneApm: #$0" query_server_for_configuration @connected_pid = Process.pid @connect_state = :connected rescue OneApm::ForceDisconnectException => e handle_force_disconnect(e) rescue OneApm::LicenseException => e handle_license_error(e) rescue OneApm::UnrecoverableAgentException => e handle_unrecoverable_agent_error(e) rescue StandardError, Timeout::Error, OneApm::ServerConnectionException => e log_error(e) if opts[:keep_retrying] note_connect_failure OneApm::Manager.logger.info "Will re-attempt in #{connect_retry_period} seconds" sleep connect_retry_period retry else disconnect end rescue Exception => e OneApm::Manager.logger.error "Exception of unexpected type during Agent#connect():", e raise end def graceful_disconnect if connected? begin @service.request_timeout = 10 @events.notify(:before_shutdown) transmit_data transmit_event_data transmit_utilization_data if OneApm::Manager.config[:collect_utilization] if @connected_pid == $$ && !@service.kind_of?(OneApm::Collector::CollectorService) OneApm::Manager.logger.debug "Sending OneApm service agent run shutdown message" @service.shutdown(Time.now.to_f) else OneApm::Manager.logger.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown" end OneApm::Manager.logger.debug "Graceful disconnect complete" rescue Timeout::Error, StandardError => e OneApm::Manager.logger.debug "Error when disconnecting #{e.class.name}: #{e.message}" end else OneApm::Manager.logger.debug "Bypassing graceful disconnect - agent not connected" end end def untraced_graceful_disconnect OneApm::Manager.disable_all_tracing do graceful_disconnect end rescue => e OneApm::Manager.logger.error e end end class ShimAgent < OneApm::Agent::Agent def self.instance @instance ||= self.new end def initialize super @stats_engine.extend OneApm::Collector::StatsEngine::Shim @transaction_sampler.extend OneApm::Collector::TransactionSampler::Shim @sql_sampler.extend OneApm::Collector::SqlSampler::Shim @error_collector.extend OneApm::Collector::ErrorCollector::Shim end def after_fork *args; end def start *args; end def shutdown *args; end def merge_data_for_endpoint *args; end def push_trace_execution_flag *args; end def pop_trace_execution_flag *args; end def browser_timing_header; "" end end end end