module MuninPassenger::Collect

Public Class Methods

default_state_file() click to toggle source
# File lib/munin_passenger/collect.rb, line 8
def self.default_state_file
  {
    'pses' => []
  }
end
get_group_stats(doc) click to toggle source
# File lib/munin_passenger/collect.rb, line 49
def self.get_group_stats(doc)
  ret = []
  doc.xpath('//info/supergroups/supergroup').each do |x_supergroup|
    x_supergroup.xpath('./group').each do |x_group|
      g = OpenStruct.new
      g.name = x_group.xpath('name').first.text
      g.queue = x_group.xpath('get_wait_list_size').first.text
      ret << g
    end
  end
  ret
end
get_ps_stats(doc) click to toggle source
# File lib/munin_passenger/collect.rb, line 62
def self.get_ps_stats(doc)
  state = read_state_file
  slots_by_pid = {}
  state['pses'].each_with_index do |pid, i|
    slots_by_pid[pid] = i if pid
  end
  ret = [nil] * state['pses'].size  # Need at least as many workers as the most we've seen.
  curr_pses = []
  now = Time.now
  doc.xpath('//info/supergroups/supergroup').each do |x_supergroup|
    x_supergroup.xpath('./group').each do |x_group|
      x_group.xpath('./processes/process').each do |x_ps|
        pid = x_ps.xpath('pid').first.text
        ps = OpenStruct.new
        ps.active      = true
        ps.pid         = pid
        ps.sessions    = x_ps.xpath('sessions').first.text.to_i
        ps.last_used   = (now - Time.at(x_ps.xpath('last_used').first.text.to_i / 1000 / 1000).to_i).to_i # in seconds
        ps.ram         = x_ps.xpath('real_memory').first.text.to_i   # in KB
        ps.cpu         = x_ps.xpath('cpu').first.text.to_i           # in %
        ps.uptime      = (now - Time.at(x_ps.xpath('spawn_start_time').first.text.to_i / 1000 / 1000).to_i).to_i # in seconds
        ps.processed   = x_ps.xpath('processed').first.text.to_i     # in requests
        ps.last_seen   = now.to_i
        curr_pses << ps
      end
    end
  end
  # This is all a little tricky,
  # but if we name each metric after the pid,
  # munin will throw away the history when passenger is restarted and the pids change.
  # So instead we have "worker1", "worker2", etc.,
  # and we show the current pid in parentheses.
  # Each time we collect info, we keep a pid in the same slot as before.
  # If a pid goes away, we free that slot.
  # If it's the first we've seen a pid,
  # we give it the first free slot.
  new_pses = []
  curr_pses.each do |ps|
    i = slots_by_pid[ps.pid]
    if i
      ret[i] = ps
    else
      new_pses << ps
    end
  end
  new_pses.each do |ps|
    i = ret.index{|x| x == nil}
    if i
      ret[i] = ps
    else
      ret << ps
    end
  end
  state['pses'] = ret.map do |ps|
    if ps
      {
        'pid'       => ps.pid,
        'last_seen' => ps.last_seen,
      }
    else
      nil
    end
  end
  write_state_file(state)
  # Now if there are still nils,
  # it means we are running than fewer workers than before.
  # Preserve those slots,
  # but the graphing code will have to watch out
  # and note that they have no process currently.
  ret
end
parse_stats(f) click to toggle source
# File lib/munin_passenger/collect.rb, line 41
def self.parse_stats(f)
  Nokogiri::XML(f) do |config|
    config.strict.
           noblanks.  # Exclude blank nodes
           nonet      # Don't make any network connections
  end
end
read_state_file() click to toggle source
# File lib/munin_passenger/collect.rb, line 14
def self.read_state_file
  filename = ENV['MUNIN_STATEFILE']
  if filename and File.exist?(filename)
    begin
      JSON.parse(File.open(filename, 'r') {|f| f.read})
    rescue
      $stderr.puts "WARN: Couldn't open munin statefile at #{filename}: #{$!.message}"
      default_state_file
    end
  else
    default_state_file
  end
end
run_status() click to toggle source
# File lib/munin_passenger/collect.rb, line 134
def self.run_status
  dir = if ENV['PASSENGER_ROOT']
          "#{ENV['PASSENGER_ROOT']}/"
        else
          ''
        end

  sudo = if ENV['WITHOUT_SUDO']
           ''
         else
           'sudo '
         end

  status = `#{sudo}#{dir}passenger-status --show=xml`
  if not $?.success?
    $stderr.puts 'Error running passenger-status'
    exit 1
  end
  status
end
write_state_file(state) click to toggle source
# File lib/munin_passenger/collect.rb, line 28
def self.write_state_file(state)
  filename = ENV['MUNIN_STATEFILE']
  if filename
    begin
      File.open(filename, 'w') do |f|
        f.write state.to_json
      end
    rescue
      $stderr.puts "WARN: Error writing to statefile at #{filename}: #{$!.message}"
    end
  end
end