class StackProf::Remote::ProcessReportCollector

ProcessReportCollector handles the work of actually starting, stopping, and collecting the dumps from the StackProf profiler.

Internally it uses RBTrace to execute the start/stop methods against all runnign processes that match pids found by the :pid_finder option. By default this matches unicorn workers.

Constants

DEFAULT_OPTIONS

Public Class Methods

new(options = {}) click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 23
def initialize(options = {})
  @options = DEFAULT_OPTIONS.merge(options)
  collect_pids
end
report_from_marshaled_results(marshaled_data) click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 62
def self.report_from_marshaled_results(marshaled_data)
  data = Marshal.load(marshaled_data)
  if data.is_a?(Array)
    data.compact.inject(nil) do |sum, d|
      sum ? StackProf::Report.new(d) + sum : StackProf::Report.new(d)
    end
  else
    StackProf::Report.new(data)
  end
end

Public Instance Methods

logger() click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 28
def logger
  StackProf::Remote::Middleware.logger
end
marshaled_results() click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 47
def marshaled_results
  if @saved_files
    logger.debug "[stackprof] Saved Files #{@saved_files.inspect}"
    saved_data = @saved_files.collect {|f|
      f = f.gsub(/"/,'') # RBTrace returns double quoted strings
      if File.readable?(f)
         Marshal.load(File.read(f))
      else
        logger.error "[stackprof] File #{f} not readable by process #{Process.pid}"
      end
    }.compact
    Marshal.dump(saved_data)
  end
end
save() click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 42
def save
  command = "StackProf::Remote::ReportSaver.save('#{@options[:path]}')"
  @saved_files = execute(command)
end
start() click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 32
def start
  command = "StackProf.start(mode: #{@options[:mode].inspect}, interval: #{@options[:interval].inspect}, raw: #{@options[:raw].inspect})"
  execute(command)
end
stop() click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 37
def stop
  command = "StackProf.stop"
  execute(command)
end

Private Instance Methods

collect_pids() click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 74
def collect_pids
  logger.debug "[stackprof] Collecting PIDs"
  @pids = @options[:pid_finder].call
  @pids -= [Process.pid]
  logger.debug "[stackprof] Found PIDs #{@pids.inspect} and current #{Process.pid}"
end
execute(command) click to toggle source
# File lib/stackprof/remote/process_report_collector.rb, line 81
def execute(command)
  logger.debug "[stackprof] execute: #{command}"
  results = @pids.collect do |pid|
    begin
      tracer = RBTracer.new(pid)
      output = tracer.eval(command)
    ensure
      tracer.detach
      output
    end
  end
  results << eval(command)
  logger.debug "[stackprof] Results: #{results.inspect}"
  results
end