# encoding: utf-8 require 'one_apm/agent/threading/agent_thread' require 'one_apm/agent/threading/backtrace_service' require 'one_apm/agent/threading/thread_profile' module OneApm module Collector module Commands class ThreadProfilerSession def initialize(backtrace_service) @backtrace_service = backtrace_service end def handle_start_command(agent_command) raise_unsupported_error unless OneApm::Agent::Threading::BacktraceService.is_supported? raise_thread_profiler_disabled unless enabled? raise_already_started_error if running? start(agent_command) end def handle_stop_command(agent_command) report_data = agent_command.arguments.fetch("report_data", true) stop(report_data) end def start(agent_command) OneApm::Manager.logger.debug("Starting Thread Profiler.") profile = @backtrace_service.subscribe( OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS, agent_command.arguments ) @started_at = Time.now @duration = profile.duration if profile end def stop(report_data) return unless running? OneApm::Manager.logger.debug("Stopping Thread Profiler.") @finished_profile = @backtrace_service.harvest(OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS) @backtrace_service.unsubscribe(OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS) @finished_profile = nil if !report_data end def harvest OneApm::Manager.logger.debug("Harvesting from Thread Profiler #{@finished_profile.to_log_description unless @finished_profile.nil?}") profile = @finished_profile @backtrace_service.profile_agent_code = false @finished_profile = nil @started_at = nil profile end def enabled? OneApm::Manager.config[:'thread_profiler.enabled'] end def running? @backtrace_service.subscribed?(OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS) end def ready_to_harvest? past_time? || stopped? end def past_time? @started_at && (Time.now > @started_at + @duration) end def stopped? !!@finished_profile end private def raise_command_error(msg) raise OneApm::Collector::AgentCommandRouter::AgentCommandError.new(msg) end def raise_unsupported_error msg = <<-EOF Thread profiling is only supported on 1.9.2 and greater versions of Ruby. We detected running agents capable of profiling, but the profile started with an agent running Ruby #{RUBY_VERSION}. Profiling again might select an appropriate agent, but we recommend running a consistent version of Ruby across your application for better results. EOF raise_command_error(msg) end def raise_thread_profiler_disabled msg = "Not starting Thread Profiler because of config 'thread_profiler.enabled' = #{enabled?}" raise_command_error(msg) end def raise_already_started_error msg = "Profile already in progress. Ignoring agent command to start another." raise_command_error(msg) end end end end end