<?xml version="1.0" encoding="UTF-8"?>
<plugin-urls type="array">
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Scout</author>
    <cached-tag-list>rails</cached-tag-list>
    <canonical-name>rails</canonical-name>
    <code>require &quot;time&quot;
require &quot;stringio&quot;

require 'elif'
Elif.send(:remove_const, :MAX_READ_SIZE); Elif::MAX_READ_SIZE = 1024*100

class RailsRequests &lt; Scout::Plugin
  ONE_DAY    = 60 * 60 * 24

  OPTIONS=&lt;&lt;-EOS
  log:
    name: Full Path to Rails Log File
    notes: &quot;The full path to the Ruby on Rails log file you wish to analyze (ex: /var/www/apps/APP_NAME/current/log/production.log).&quot;
  max_request_length:
    name: Max Request Length (sec)
    notes: If any request length is larger than this amount, an alert is generated (see Advanced for more options)
    default: 3
  rla_run_time:
    name: Request Log Analyzer Run Time (HH:MM)
    notes: It's best to schedule these summaries about fifteen minutes before any logrotate cron job you have set would kick in.
    default: '23:45'
    attributes: advanced
  ignored_actions:
    name: Ignored Actions
    notes: Takes a regex. Any URIs matching this regex will NOT count as slow requests, and you will NOT be notified if they exceed Max Request Length. Matching actions will still be included in daily summaries.
    attributes: advanced
  EOS
  
  # These regexes should handle standard rails logger and syslogger
  RAILS_22_COMPLETED = /(Completed in (\d+)ms .+) \[(\S+)\]\Z/
  RAILS_21_COMPLETED = /(Completed in (\d+\.\d+) .+) \[(\S+)\]\Z/
  
  PROCESSING = /Processing .+ at (\d+-\d+-\d+ \d+:\d+:\d+)\)/
  
  needs &quot;request_log_analyzer&quot;
  
  def build_report
    patch_elif

    log_path = option(:log)
    unless log_path and not log_path.empty?
      @file_found = false
      return error(&quot;A path to the Rails log file wasn't provided.&quot;,&quot;Please provide the full path to the Rails log file to analyze (ie - /var/www/apps/APP_NAME/log/production.log)&quot;)
    end
    max_length = option(:max_request_length).to_f

    # process the ignored_actions option -- this is a regex provided by users; matching URIs don't get counted as slow
    ignored_actions=nil
    if option(:ignored_actions) &amp;&amp; option(:ignored_actions).strip != ''
      begin
        ignored_actions = Regexp.new(option(:ignored_actions))
      rescue
        error(&quot;Argument error&quot;,&quot;Could not understand the regular expression for excluding slow actions: #{option(:ignored_actions)}. #{$!.message}&quot;)
      end
    end

    report_data        = { :slow_request_rate     =&gt; 0,
                           :request_rate          =&gt; 0,
                           :average_request_length =&gt; nil }
    slow_request_count = 0
    request_count      = 0
    last_completed     = nil
    slow_requests      = ''
    total_request_time = 0.0
    previous_last_request_time = memory(:last_request_time) || Time.now-60 # analyze last minute on first invocation
    
    # Time#parse is slow so uses a specially-formatted integer to compare request times.
    previous_last_request_time_as_timestamp = previous_last_request_time.strftime('%Y%m%d%H%M%S').to_i
    # set to the time of the first request processed (the most recent chronologically)
    last_request_time  = nil
    # needed to ensure that the analyzer doesn't run if the log file isn't found.
    @file_found        = true
    
    Elif.foreach(log_path) do |line|
      if line =~ RAILS_22_COMPLETED        
        last_completed = [$2.to_i / 1000.0, $1, $3]
      elsif line =~ RAILS_21_COMPLETED 
        last_completed = [$2.to_f, $1, $3]
      elsif last_completed and
            line =~ PROCESSING
        time_of_request = convert_timestamp($1)
        last_request_time = time_of_request if last_request_time.nil?
        if time_of_request &lt;= previous_last_request_time_as_timestamp
          break
        else
          request_count += 1
          total_request_time          += last_completed.first.to_f
          if max_length &gt; 0 and last_completed.first &gt; max_length
            # only test for ignored_actions if we actually have an ignored_actions regex
            if ignored_actions.nil? || (ignored_actions.is_a?(Regexp) &amp;&amp; !ignored_actions.match(last_completed.last))
              slow_request_count += 1
              slow_requests                    += &quot;#{last_completed.last}\n&quot;
              slow_requests                    += &quot;#{last_completed[1]}\n\n&quot;
            end
          end
        end # request should be analyzed
      end
    end
    
    # Create a single alert that holds all of the requests that exceeded the +max_request_length+.
    if (count = slow_request_count) &gt; 0
      alert( &quot;Maximum Time(#{option(:max_request_length)} sec) exceeded on #{count} request#{'s' if count != 1}&quot;,
             slow_requests )
    end
    # Calculate the average request time and request rate if there are any requests
    if request_count &gt; 0
      # calculate the time btw runs in minutes
      # this is used to generate rates.
      interval = (Time.now-(@last_run || previous_last_request_time))

      interval &lt; 1 ? inteval = 1 : nil # if the interval is less than 1 second (may happen on initial run) set to 1 second
      interval = interval/60 # convert to minutes
      interval = interval.to_f
      # determine the rate of requests and slow requests in requests/min
      request_rate                         = request_count /
                                             interval
      report_data[:request_rate]           = sprintf(&quot;%.2f&quot;, request_rate)
      
      slow_request_rate                    = slow_request_count /
                                             interval
      report_data[:slow_request_rate]      = sprintf(&quot;%.2f&quot;, slow_request_rate)
      
      # determine the average request length
      avg                                  = total_request_time /
                                             request_count
      report_data[:average_request_length] = sprintf(&quot;%.2f&quot;, avg)

      report_data[:slow_requests_percentage] = (request_count == 0) ? 0 : (slow_request_count.to_f / request_count.to_f) * 100.0

    end
    remember(:last_request_time, Time.parse(last_request_time.to_s) || Time.now)
    report(report_data)
  rescue Errno::ENOENT =&gt; error
    @file_found = false
    error(&quot;Unable to find the Rails log file&quot;, &quot;Could not find a Rails log file at: #{option(:log)}. Please ensure the path is correct.&quot;)
  rescue Exception =&gt; error
    error(&quot;#{error.class}:  #{error.message}&quot;, error.backtrace.join(&quot;\n&quot;))
  ensure
    # only run the analyzer if the log file is provided
    # this may take a couple of minutes on large log files.
    if @file_found and option(:log) and not option(:log).empty?
      generate_log_analysis(log_path)
    end
  end
  
  private
  
  # Time.parse is slow...uses this to compare times.
  def convert_timestamp(value)
    value.gsub(/[^0-9]/, '')[0...14].to_i
  end
  
  def silence
    old_verbose, $VERBOSE, $stdout = $VERBOSE, nil, StringIO.new
    yield
  ensure
    $VERBOSE, $stdout = old_verbose, STDOUT
  end
  
  def generate_log_analysis(log_path)
    # decide if it's time to run the analysis yet today
    if option(:rla_run_time) =~ /\A\s*(0?\d|1\d|2[0-3]):(0?\d|[1-4]\d|5[0-9])\s*\z/
      run_hour    = $1.to_i
      run_minutes = $2.to_i
    else
      run_hour    = 23
      run_minutes = 45
    end
    now = Time.now
    if last_summary = memory(:last_summary_time)
      if now.hour &gt; run_hour       or
        ( now.hour == run_hour     and
          now.min  &gt;= run_minutes ) and
         %w[year mon day].any? { |t| last_summary.send(t) != now.send(t) }
        remember(:last_summary_time, now)
      else
        remember(:last_summary_time, last_summary)
        return
      end
    else # summary hasn't been run yet ... set last summary time to 1 day ago
      last_summary = now - ONE_DAY
      # remember(:last_summary_time, last_summary)
      # on initial run, save the last summary time as now. otherwise if an error occurs, the 
      # plugin will attempt to create a summary on each run.
      remember(:last_summary_time, now) 
    end
    # make sure we get a full run
    if now - last_summary &lt; 60 * 60 * 22
      last_summary = now - ONE_DAY
    end
    
    self.class.class_eval(RLA_EXTS)
    
    analysis = analyze(last_summary, now, log_path)
    summary( :command =&gt; &quot;request-log-analyzer --after '&quot;                   +
                         last_summary.strftime('%Y-%m-%d %H:%M:%S')         +
                         &quot;' --before '&quot; + now.strftime('%Y-%m-%d %H:%M:%S') +
                         &quot;' '#{log_path}'&quot;,
             :output  =&gt; analysis )
  rescue Exception =&gt; error
    error(&quot;#{error.class}:  #{error.message}&quot;, error.backtrace.join(&quot;\n&quot;))
  end
  
  def analyze(last_summary, stop_time, log_path)
    log_file = read_backwards_to_timestamp(log_path, last_summary)
    if RequestLogAnalyzer::VERSION &lt;= &quot;1.3.7&quot;
      analyzer_with_older_rla(last_summary, stop_time, log_file)
    else
      analyzer_with_newer_rla(last_summary, stop_time, log_file)
    end
  end
  
  def analyzer_with_older_rla(last_summary, stop_time, log_file)
    summary  = StringIO.new
    output   = EmbeddedHTML.new(summary)
    format   = RequestLogAnalyzer::FileFormat.load(:rails)
    options  = {:source_files =&gt; log_file, :output =&gt; output}
    source   = RequestLogAnalyzer::Source::LogParser.new(format, options)
    control  = RequestLogAnalyzer::Controller.new(source, options)
    control.add_filter(:timespan, :after  =&gt; last_summary)
    control.add_filter(:timespan, :before =&gt; stop_time)
    control.add_aggregator(:summarizer)
    source.progress = nil
    format.setup_environment(control)
    silence do
      control.run!
    end
    summary.string.strip
  end
  
  def analyzer_with_newer_rla(last_summary, stop_time, log_file)
    summary = StringIO.new
    RequestLogAnalyzer::Controller.build(
      :output       =&gt; EmbeddedHTML,
      :file         =&gt; summary,
      :after        =&gt; last_summary, 
      :before       =&gt; stop_time,
      :source_files =&gt; log_file,
      :format       =&gt; RequestLogAnalyzer::FileFormat::Rails
    ).run!
    summary.string.strip
  end
  
  def patch_elif
    if Elif::VERSION &lt; &quot;0.2.0&quot;
      Elif.send(:define_method, :pos) do
        @current_pos +
        @line_buffer.inject(0) { |bytes, line| bytes + line.size }
      end
    end
  end
  
  def read_backwards_to_timestamp(path, timestamp)
    start = nil
    Elif.open(path) do |elif|
      elif.each do |line|
        if line =~ /\AProcessing .+ at (\d+-\d+-\d+ \d+:\d+:\d+)\)/
          time_of_request = Time.parse($1)
          if time_of_request &lt; timestamp
            break
          else
            start = elif.pos
          end
        end
      end
    end

    file = open(path)
    file.seek(start) if start
    file
  end
  
  RLA_EXTS = &lt;&lt;-'END_RUBY'
  class EmbeddedHTML &lt; RequestLogAnalyzer::Output::Base
    def print(str)
      @io &lt;&lt; str
    end
    alias_method :&lt;&lt;, :print
  
    def puts(str = &quot;&quot;)
      @io &lt;&lt; &quot;#{str}&lt;br/&gt;\n&quot;
    end
  
    def title(title)
      @io.puts(tag(:h2, title))
    end
  
    def line(*font)  
      @io.puts(tag(:hr))
    end
  
    def link(text, url = nil)
      url = text if url.nil?
      tag(:a, text, :href =&gt; url)
    end
  
    def table(*columns, &amp;block)
      rows = Array.new
      yield(rows)
  
      @io &lt;&lt; tag(:table, :cellspacing =&gt; 0) do |content|
        if table_has_header?(columns)
          content &lt;&lt; tag(:tr) do
            columns.map { |col| tag(:th, col[:title]) }.join(&quot;\n&quot;)
          end
        end
  
        odd = false
        rows.each do |row|
          odd = !odd
          content &lt;&lt; tag(:tr) do
            if odd
              row.map { |cell| tag(:td, cell, :class =&gt; &quot;alt&quot;) }.join(&quot;\n&quot;) 
            else
              row.map { |cell| tag(:td, cell) }.join(&quot;\n&quot;) 
            end
          end
        end
      end
    end
  
    def header
    end
  
    def footer
      @io &lt;&lt; tag(:hr) &lt;&lt; tag(:p, &quot;Powered by request-log-analyzer v#{RequestLogAnalyzer::VERSION}&quot;)
    end
  
    private
  
    def tag(tag, content = nil, attributes = nil)
      if block_given?
        attributes = content.nil? ? &quot;&quot; : &quot; &quot; + content.map { |(key, value)| &quot;#{key}=\&quot;#{value}\&quot;&quot; }.join(&quot; &quot;)
        content_string = &quot;&quot;
        content = yield(content_string)
        content = content_string unless content_string.empty? 
        &quot;&lt;#{tag}#{attributes}&gt;#{content}&lt;/#{tag}&gt;&quot;
      else
        attributes = attributes.nil? ? &quot;&quot; : &quot; &quot; + attributes.map { |(key, value)| &quot;#{key}=\&quot;#{value}\&quot;&quot; }.join(&quot; &quot;)
        if content.nil?
          &quot;&lt;#{tag}#{attributes} /&gt;&quot;
        else
          if content.class == Float
            &quot;&lt;#{tag}#{attributes}&gt;&lt;div class='color_bar' style=\&quot;width:#{(content*200).floor}px;\&quot;/&gt;&lt;/#{tag}&gt;&quot;
          else
            &quot;&lt;#{tag}#{attributes}&gt;#{content}&lt;/#{tag}&gt;&quot;
          end
        end
      end
    end  
  end
  END_RUBY
end

### Modifications below for Elif and File to ignore large chunks of data in long lines.

class Elif
  alias_method :gets_old, :gets
  # This is a modified version of +gets+. It ignores any segments that do not contain the 
  # +sep_string+. This prevents the buffer from growing in size in using more memory.
  def gets(sep_string = $\)
    # 
    # If we have more than one line in the buffer or we have reached the
    # beginning of the file, send the last line in the buffer to the caller.  
    # (This may be +nil+, if the buffer has been exhausted.)
    # 
    return @line_buffer.pop if @line_buffer.size &gt; 2 or @current_pos.zero?
        
    # 
    # Read more bytes and prepend them to the first (likely partial) line in the
    # buffer.
    # 
    chunk = String.new
    # read from the file and exit when a segment is read that contains the +set_string+.
    while chunk and chunk !~ /#{sep_string}/    
      # 
      # If we made it this far, we need to read more data to try and find the 
      # beginning of a line or the beginning of the file.  Move the file pointer
      # back a step, to give us new bytes to read.
      #
      @current_pos -= @read_size
      @file.seek(@current_pos, IO::SEEK_SET) 
      chunk = @file.read(@read_size)
    end
    
    @line_buffer[0] = &quot;#{chunk}#{@line_buffer[0]}&quot;

    @read_size      = MAX_READ_SIZE  # Set a size for the next read.
    
    # 
    # Divide the first line of the buffer based on +sep_string+ and #flatten!
    # those new lines into the buffer.
    # 
    @line_buffer[0] = @line_buffer[0].scan(/.*?#{Regexp.escape(sep_string)}|.+/)
    @line_buffer.flatten!
    
    # We have move data now, so try again to read a line...
    gets(sep_string)
  end
end

class File
  alias_method :gets_original, :gets
  # The size of the reads we will use to add to the line buffer.
  MAX_READ_SIZE=1024*100
  
  # 
  # This method returns the next line of the File.
  # 
  # It works by moving the file pointer forward +MAX_READ_SIZE+ at a time, 
  # storing seen lines in &lt;tt&gt;@line_buffer&lt;/tt&gt;.  Once the buffer contains at 
  # least two lines (ensuring we have seen on full line) or the file pointer 
  # reaches the end of the File, the last line from the buffer is returned.  
  # When the buffer is exhausted, this will throw +nil+ (from the empty Array).
  #
  # Read portions of the file that do not contain the +sep_string+ are not added to 
  # the buffer. This prevents &lt;tt&gt;@line_buffer&lt;tt&gt; from growing signficantly when parsing
  # large lines.
  #
  def gets(sep_string = $/)
    @read_size ||= MAX_READ_SIZE
    # A buffer to hold lines read, but not yet returned.
    @line_buffer ||= Array.new
        
    # Record where we are.
    @current_pos ||= pos
    
    # Last Position in the file
    @last_pos ||= nil
    if @last_pos.nil? 
      seek(0, IO::SEEK_END)
      @last_pos = pos
      seek(0,0)
    end
    
    # 
    # If we have more than one line in the buffer or we have reached the
    # beginning of the file, send the last line in the buffer to the caller.  
    # (This may be +nil+, if the buffer has been exhausted.)
    #
    if @line_buffer.size &gt; 2 or @current_pos &gt;= @last_pos
      self.lineno += 1
      return @line_buffer.shift 
    end
    
    sep = 
    
    chunk = String.new
    while chunk and chunk !~ /#{sep_string}/   
      chunk = read(@read_size)
    end
    
    # Appends new lines to the last element of the buffer
    line_buffer_pos = @line_buffer.any? ? @line_buffer.size-1 : 0
    
    if chunk
      @line_buffer[line_buffer_pos] = @line_buffer[line_buffer_pos].to_s&lt;&lt; chunk
    else
      # at the end
      return @line_buffer.shift
    end
    
    # 
    # Divide the last line of the buffer based on +sep_string+ and #flatten!
    # those new lines into the buffer.
    # 
    @line_buffer[line_buffer_pos] = @line_buffer[line_buffer_pos].scan(/.*?#{Regexp.escape(sep_string)}|.+/)
    @line_buffer.flatten!

    # 
    # If we made it this far, we need to read more data to try and find the 
    # end of a line or the end of the file.  Move the file pointer
    # forward a step, to give us new bytes to read.
    #
    @current_pos += @read_size
    seek(@current_pos, IO::SEEK_SET)
    
    # We have more data now, so try again to read a line...
    gets(sep_string)
  end
end

</code>
    <created-at type="datetime">2009-09-15T02:56:30Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Analyzes the performance of a Ruby on Rails application via its log file. Just install this plugin in Scout and provide the full path to the Rails log file (ex: /var/www/app/APP_NAME/log/production.log). The plugin generates an alert when any slow requests are generated and creates a detailed performance report via the &quot;Request Log Analyzer gem&quot;:http://github.com/wvanbergen/request-log-analyzer/tree/master every 24 hours. 

By default, a slow request is any request that is greater than or equal to 3 seconds. This can be modified in the plugin settings. 

Note that the Request Log Analyzer may take a couple of minutes to run on large log files. 

On the first run, a detailed report is generated for the previous 2 days of activity. No metric data is reported on the first run (requests, slow requests, and average request time).

h2. Dependencies

Requires:

&quot;elif gem&quot;:http://elif.rubyforge.org/

&lt;div class=&quot;terminal&quot;&gt;
sudo gem install elif
&lt;/div&gt;

&quot;request-log-analyzer gem&quot;:http://github.com/wvanbergen/request-log-analyzer/tree/master

&lt;div class=&quot;terminal&quot;&gt;
sudo gem install request-log-analyzer
&lt;/div&gt;

h2. Compatibility 

Tested on Linux, OSX, and Solaris. Requires the Scout Agent version 4.0 or greater.
</description>
    <featured type="boolean">false</featured>
    <id type="integer">181</id>
    <metadata type="yaml">--- &quot;metadata:\n  request_rate:\n    precision: 2\n    label: Requests\n    units: req/min\n  average_request_length:\n    precision: 2\n    units: sec\n  slow_request_rate:\n    precision: 2\n    label: Slow Requests\n    units: req/min\n  slow_requests_percentage:\n    precision: 0\n    units: \&quot;%\&quot;\n\n\
triggers:\n  - type: trend\n    dname: request_rate\n    direction: UP\n    percentage_change: 200\n    duration: 60\n    window_reference: LAST_WEEK\n    min_value: 100\n  - type: trend\n    dname: average_request_length\n    direction: UP\n    percentage_change: 200\n    duration: 60\n    window_reference: LAST_WEEK\n    min_value: 0.3 &quot;
</metadata>
    <name>Ruby on Rails Monitoring</name>
    <plugins-count type="integer">1004</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Rails Requests Plugin
======================
Created by [Scout](http://scoutapp.com)

Overview
--------

Analyzes the performance of a Ruby on Rails application via its log file. Just install this plugin in Scout and provide the full path to the Rails log file (ex: /var/www/app/APP_NAME/log/production.log). The plugin generates an alert when any slow requests are generated and creates a detailed performance report via the [Request Log Analyzer gem](http://github.com/wvanbergen/request-log-analyzer/tree/master) every 24 hours. 

By default, a slow request is any request that is greater than or equal to 3 seconds. This can be modified in the plugin settings. 

Note that the Request Log Analyzer may take a couple of minutes to run on large log files. 

On the first run, a detailed report is generated for the previous 2 days of activity. No metric data is reported on the first run (requests, slow requests, and average request time).

Dependencies
------------

Requires:

[elif gem](http://elif.rubyforge.org/):

sudo gem install elif

[request-log-analyzer gem](http://github.com/wvanbergen/request-log-analyzer/tree/master)

sudo gem install request-log-analyzer

Compatibility 
-------------

Tested on Linux, OSX, and Solaris. Requires the Scout Agent version 4.0 or greater.


</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">4</scout-version>
    <short-description>Monitors a Ruby on Rails application's performance, providing rich alerts on slow requests and a detailed daily performance report. Nothing to install in your Rails app - just provide a full path to the log file.</short-description>
    <tested-platforms>Linux, Solaris, and OSX.</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-11T20:02:54Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/rails_requests/rails_requests.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>load</cached-tag-list>
    <canonical-name>load</canonical-name>
    <code>#
# Modified load_averages to show load/processor, as this is a more accurate
# measurement of CPU utilization.
#
# Requires /proc/cpuinfo
#
class LoadAverages &lt; Scout::Plugin

  OPTIONS=&lt;&lt;-EOS
    num_processors:
      name: Number of Processors
      notes: For calculating CPU load. If left blank, autodetects through /proc/cpuinfo
      default: 1
  EOS

   def build_report
     if `uptime` =~ /load average(s*): ([\d.]+)(,*) ([\d.]+)(,*) ([\d.]+)\Z/
       report :last_minute          =&gt; $2.to_f/num_processors,
              :last_five_minutes    =&gt; $4.to_f/num_processors,
              :last_fifteen_minutes =&gt; $6.to_f/num_processors
     else
       raise &quot;Couldn't use `uptime` as expected.&quot;
     end
  rescue Exception
    error &quot;Error determining load&quot;, $!.message
  end

  def num_processors
    # first, check if the options provided is &gt; 0. So leave the options blank to auto-detect
    processors = option('num_processors').to_i
    return processors if processors &gt; 0

    # otherwise, pull it from memory
    processors = memory(:processors)

    # if we didn't get it from memory, try to auto-detect through /proc/cpuinfo
    unless processors &amp;&amp; processors &gt; 0
      if `cat /proc/cpuinfo | grep 'model name' | wc -l` =~ /(\d+)/
        processors = $1.to_i
      else
        raise &quot;Couldn't use /proc/cpuinfo as expected.&quot;
      end
      raise &quot;Couldn't use /proc/cpuinfo as expected.&quot; unless processors &gt; 0
    end
    remember(:processors, processors)
    return processors
  end

end
</code>
    <created-at type="datetime">2007-12-21T17:54:23Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors the load on server, generating an alert if the load over the last minute is greater than a specified amount. 

&quot;See our blog article&quot;:http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages for background on understanding load 
</description>
    <featured type="boolean">false</featured>
    <id type="integer">4</id>
    <metadata type="yaml">--- |
metadata:
  last_minute:
    precision: 2
  last_five_minutes:
    precision: 2
  last_fifteen_minutes:
    precision: 2

triggers:
  - type: peak
    dname: last_minute
    max_value: 3

</metadata>
    <name>Server Load</name>
    <plugins-count type="integer">727</plugins-count>
    <rating-avg type="decimal">4.0</rating-avg>
    <rating-count type="integer">2</rating-count>
    <rating-total type="integer">8</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors the load on server, generating an alert if the load over the last minute is greater than a specified amount. </short-description>
    <tested-platforms>linux macosx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-13T21:38:13Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/load_averages/load_averages.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>disk space, disk usage</cached-tag-list>
    <canonical-name>disk</canonical-name>
    <code>class DiskUsage &lt; Scout::Plugin

  # the Disk Freespace RegEx
  DF_RE = /\A\s*(\S.*?)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*\z/

  # Parses the file systems lines according to the Regular Expression
  # DF_RE.
  # 
  # normal line ex:
  # /dev/disk0s2   233Gi   55Gi  177Gi    24%    /
  
  # multi-line ex:
  # /dev/mapper/VolGroup00-LogVol00
  #                        29G   25G  2.5G  92% /
  #
  def parse_file_systems(io, &amp;line_handler)
    line_handler ||= lambda { |row| pp row }
    headers      =   nil

    row = &quot;&quot;
    io.each_line do |line|
      if headers.nil? and line =~ /\AFilesystem/
        headers = line.split(&quot; &quot;, 6)
      else
        row &lt;&lt; line
        if row =~  DF_RE
          fields = $~.captures
          line_handler[headers ? Hash[*headers.zip(fields).flatten] : fields]
          row = &quot;&quot;
        end
      end
    end
  end
  
  # Ensures disk space metrics are in GB. Metrics that don't contain 'G,M,or K' are just
  # turned into integers.
  def clean_value(value)
    if value =~ /G/i
      value.to_f
    elsif value =~ /M/i
      (value.to_f/1024.to_f).round
    elsif value =~ /K/i
      (value.to_f/1024.to_f/1024.to_f).round
    else
      value.to_f
    end
  end
  
  def build_report
    ENV['lang'] = 'C' # forcing English for parsing
    df_command   = option(&quot;command&quot;) || &quot;df -h&quot;
    df_output    = `#{df_command}`
          
    df_lines = []
    parse_file_systems(df_output) { |row| df_lines &lt;&lt; row }
    
    # if the user specified a filesystem use that
    df_line = nil
    if option(&quot;filesystem&quot;)
      df_lines.each do |line|
        if line.has_value?(option(&quot;filesystem&quot;))
          df_line = line
        end
      end
    end
    
    # else just use the first line
    df_line ||= df_lines.first
      
    # remove 'filesystem' and 'mounted on' if present - these don't change. 
    df_line.reject! { |name,value| ['filesystem','mounted on'].include?(name.downcase.gsub(/\n/,'')) }  
      
    # capacity on osx = Use% on Linux ... convert anything that isn't size, used, or avail to capacity ... a big assumption?
    assumed_capacity = df_line.find { |name,value| !['size','used','avail'].include?(name.downcase.gsub(/\n/,''))}
    df_line.delete(assumed_capacity.first)
    df_line['capacity'] = assumed_capacity.last
    
    # will be passed at the end to report to Scout
    report_data = Hash.new
      
    df_line.each do |name, value|
      report_data[name.downcase.strip.to_sym] = clean_value(value)
    end
    report(report_data)
  end
end
</code>
    <created-at type="datetime">2007-12-21T18:33:12Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors the amount of space remaining on a disk, generating an alert if the amount of space used exceeds a given percentage. 

h3. Specifying the filesystem

By default, the plugin will retrieve data from the first file system listed using the &lt;code&gt;df&lt;/code&gt; command. To override, enter the name of the filesystem in the 'Filesystem' plugin option.

</description>
    <featured type="boolean">false</featured>
    <id type="integer">6</id>
    <metadata type="yaml">--- |-
options:
  command:
    name: df Command
    notes: The command used to display free disk space
    default: &quot;df -h&quot;
  filesystem:
    name: Filesystem
    notes: The filesystem to check usage, if none specified, uses the first listed
    default: 
      
metadata:
  used:          
    label: Disk Space Used
    units: GB
    precision: 0
  size:
    label: Disk Size
    units: GB
    precision: 0
  capacity:
    label: Disk Capacity
    units: %
    precision: 0
  avail:
    label: Disk Space Available
    units: GB
    precision: 0
    larger_is_better: true

triggers:
  - type: peak
    dname: capacity
    max_value: 85
  # available disk space decreases by 10% compared to last week
  - type: trend
    dname: avail
    direction: DOWN
    percentage_change: 10
    duration: 60
    window_reference: LAST_WEEK
</metadata>
    <name>Disk Usage</name>
    <plugins-count type="integer">494</plugins-count>
    <rating-avg type="decimal">4.0</rating-avg>
    <rating-count type="integer">1</rating-count>
    <rating-total type="integer">4</rating-total>
    <readme>

How to test:

scout test /path/to/disk_usage.rb -v -l debug '{&quot;command&quot;=&gt;&quot;cat /path/to/test_disk_usage_output_normal.txt&quot;}'

scout test /path/to/disk_usage.rb -v -l debug '{&quot;command&quot;=&gt;&quot;cat /path/to/test_disk_usage_output_multiline.txt&quot;}'
</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors the amount of space remaining on a disk, generating an alert if the amount of space used exceeds a given percentage. </short-description>
    <tested-platforms>linux macosx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-13T21:38:13Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/disk_usage/disk_usage.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Eric Lindvall</author>
    <cached-tag-list>memory</cached-tag-list>
    <canonical-name>memory</canonical-name>
    <code>class MemoryProfiler &lt; Scout::Plugin
  def build_report
    mem_info = {}
    `cat /proc/meminfo`.each_line do |line|
      _, key, value = *line.match(/^(\w+):\s+(\d+)\s/)
      mem_info[key] = value.to_i
    end
    
    # memory info is empty - operating system may not support it (why doesn't an exception get raised earlier on mac osx?)
    if mem_info.empty?
      raise &quot;No such file or directory&quot;
    end
    
    mem_total = mem_info['MemTotal'] / 1024
    mem_free = (mem_info['MemFree'] + mem_info['Buffers'] + mem_info['Cached']) / 1024
    mem_used = mem_total - mem_free
    mem_percent_used = (mem_used / mem_total.to_f * 100).to_i

    swap_total = mem_info['SwapTotal'] / 1024
    swap_free = mem_info['SwapFree'] / 1024
    swap_used = swap_total - swap_free
    unless swap_total == 0    
      swap_percent_used = (swap_used / swap_total.to_f * 100).to_i
    end
    
    # will be passed at the end to report to Scout
    report_data = Hash.new

    report_data['Memory Total'] = mem_total
    report_data['Memory Used'] = mem_used
    report_data['% Memory Used'] = mem_percent_used

    report_data['Swap Total'] = swap_total
    report_data['Swap Used'] = swap_used
    unless  swap_total == 0   
      report_data['% Swap Used'] = swap_percent_used
    end
    report(report_data)
        
  rescue Exception =&gt; e
    if e.message =~ /No such file or directory/
      error('Unable to find /proc/meminfo',%Q(Unable to find /proc/meminfo. Please ensure your operationg system supports procfs:
         http://en.wikipedia.org/wiki/Procfs)
      )
    else
      raise
    end
  end
end
</code>
    <created-at type="datetime">2008-04-17T14:36:17Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Returns a profile of the system's memory usage (Swap Total, Swap Used, Swap Used, Memory Total, Memory Used, and Memory Used).
&lt;br/&gt;&lt;br/&gt;
*Compatibility*

Requires &quot;procfs&quot;:http://en.wikipedia.org/wiki/Procfs, which is supported under Solaris, BSD, and Linux:


</description>
    <featured type="boolean">false</featured>
    <id type="integer">15</id>
    <metadata type="yaml">--- |
metadata:
  Memory Total:
    units: MB
    precision: 0
    larger_is_better: true
  Memory Used:
    units: MB
    precision: 0
  % Memory Used:
    units: %
    precision: 0
  Swap Total:
    units: MB
    precision: 0
  Swap Used:
    units: MB
    precision: 0
  % Swap Used:
    units: %
    precision: 0

triggers:
  - type: peak
    dname: % Swap Used
    max_value: 50

</metadata>
    <name>Memory Profiler</name>
    <plugins-count type="integer">476</plugins-count>
    <rating-avg type="decimal">5.0</rating-avg>
    <rating-count type="integer">3</rating-count>
    <rating-total type="integer">15</rating-total>
    <readme>Memory Profiler Plugin
=====================
Created by Eric Lindvall 

Compatibility 
-------------
Requires [procfs](http://en.wikipedia.org/wiki/Procfs), which is supported under Solaris, BSD, and Linux:

Functionality
-------------
Returns a profile of the system's memory usage:
* Swap Total
* Swap Used
* % Swap Used
* Memory Total
* Memory Used
* % Memory Used</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Returns a profile of the system's memory usage (memory used, % memory used, swap used, % swap used, etc). Requires procfs.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T05:16:26Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/memory_profiler/memory_profiler.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Scout, Eric Lindvall</author>
    <cached-tag-list>memory, process</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class ProcessUsage &lt; Scout::Plugin  
  MEM_CONVERSION = 1024
  
  def build_report
    if option(:command_name).nil? or option(:command_name) == &quot;&quot;
      return error(&quot;Please specify the name of the process you want to monitor.&quot;)
    end
    ps_command   = option(:ps_command) || &quot;ps auxww&quot;
    ps_regex     = (option(:ps_regex) || &quot;(?i:\\bCOMMAND\\b)&quot;).to_s.gsub(&quot;COMMAND&quot;) { Regexp.escape(option(:command_name)) }

    ps_output = `#{ps_command}`
    unless $?.success?
      return error(&quot;Couldn't use `ps` as expected.&quot;, error.message)
    end

    ps_lines = ps_output.split(/\n/)
    fields   = ps_lines.shift.downcase.split
    unless (memory_index = fields.index(&quot;rss&quot;)) &amp;&amp; (pid_index = fields.index('pid'))
      return error( &quot;RSS or PID field not found.&quot;,
                    &quot;The output from `#{ps_command}` did not include the needed RSS and PID fields.&quot; )
    end

    # narrow the ps lines to just those mentioning the process we're interested in
    process_lines = ps_lines.grep(Regexp.new(ps_regex))

    if process_lines.any?
      rss_values = process_lines.map { |com| Float(com.split[memory_index]).abs }
      pids       = process_lines.map { |com| Integer(com.split[pid_index]) }
      highest    = rss_values.max
      total      = rss_values.inject(0){|s,value| s + value }
      restarts   = 0

      if remembered_pids = memory(:pids)
        # Find how many new pids we haven't seen before
        new_pids     = (pids - remembered_pids).length

        # Find how many more pids we have now than before
        started_pids = pids.length - remembered_pids.length
        started_pids = 0 if started_pids &lt; 1

        # Don't include newly started processes as restarts
        restarts = new_pids - started_pids
      end

      report(:memory        =&gt; (highest/MEM_CONVERSION).to_i,
             :total_rss     =&gt; (total/MEM_CONVERSION).to_i,
             :num_processes =&gt; process_lines.size,
             :restarts      =&gt; restarts)

      remember(:pids =&gt; pids)
    else
      error( &quot;Command not found.&quot;,
             &quot;No processes found matching #{option(:command_name)}.&quot; )
    end
  rescue Exception =&gt; e
    error(&quot;Error when executing: #{e.class}&quot;, e.message)
  end
end
</code>
    <created-at type="datetime">2007-12-12T23:49:41Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Given a process name, this plugin monitors:

* _Number of Processes_ - the number of matching processes running
* _Largest Process Memory Usage_ - the memory usage (RSS) of the largest instance
* _Total Memory Usage_ - the total memory usage (RSS) across all process instances.
* _Restarts_ - the number of process restarts

</description>
    <featured type="boolean">false</featured>
    <id type="integer">1</id>
    <metadata type="yaml">--- |
options:
  command_name:
    name: Command Name
    notes: The name of the command to pull statistics for.
    default: mongrel_rails
  ps_command:
    name: The Process Status (ps) Command
    notes: The command with options. The default works on most systems.
    default: ps auxww
  ps_regex:
    name: The regex used to match a command name.
    notes: &quot;By default, this matches a command name anywhere in the ps output line.  The word COMMAND get's replaced with the command you gave (regex escaped).  You may wish to try the following pattern if you only want to match a command in the last column:  (?i:COMMAND\\s+$)&quot;
    default: &quot;(?i:\\bCOMMAND\\b)&quot;
    
metadata:
  memory:          
    label: Largest Process Memory Usage
    units: MB
    precision: 0
  total_rss:          
    label: Total Memory Usage
    units: MB
    precision: 0
  num_processes:          
    label: Number of Processes
    units: &quot;&quot;
    precision: 0
  restarts:          
    label: Restarts
    units: &quot;&quot;
    precision: 0
     
triggers:
  - type: peak
    dname: memory
    max_value: 10
  - type: trend
    dname: memory
    direction: UP
    percentage_change: 20
    duration: 60
    window_reference: LAST_WEEK
    min_value: 5

</metadata>
    <name>Process Usage</name>
    <plugins-count type="integer">283</plugins-count>
    <rating-avg type="decimal">4.0</rating-avg>
    <rating-count type="integer">2</rating-count>
    <rating-total type="integer">8</rating-total>
    <readme>Process Usage Plugin
====================

Created by [Highgroove Studios LLC](http://www.highgroove.com)

Compatibility 
-------------

Works on Linux and OSX.

</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors the memory usage of a process, generating an alert if it exceeds a specified threshold. </short-description>
    <tested-platforms>linux macosx solaris</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T05:16:40Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/process_memory/process_usage.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Scout, Eric Lindvall</author>
    <cached-tag-list>http, url monitoring</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require 'benchmark'
require 'net/http'
require 'net/https'
require 'uri'

class UrlMonitor &lt; Scout::Plugin
  include Net
  
  TEST_USAGE = &quot;#{File.basename($0)} url URL last_run LAST_RUN&quot;
  TIMEOUT_LENGTH = 50 # seconds
  
  def build_report
    url = option(&quot;url&quot;).to_s.strip
    if url.empty?
      return error(&quot;A url wasn't provided.&quot;)
    end
    
    unless url =~ %r{\Ahttps?://}
      url = &quot;http://#{url}&quot;
    end
    
    response = nil
    response_time = Benchmark.realtime do
      response = http_response(url)
    end

    report(:status =&gt; response.class.to_s[/^Net::HTTP(.*)$/, 1],
           :response_time =&gt; response_time)
    
    is_up = valid_http_response?(response) ? 1 : 0
    report(:up =&gt; is_up)
    
    if is_up != memory(:was_up)
      if is_up == 0
        alert(&quot;The URL [#{url}] is not responding&quot;, unindent(&lt;&lt;-EOF))
            URL: #{url}

            Code: #{response.code}
            Status: #{response.class.to_s[/^Net::HTTP(.*)$/, 1]}
            Message: #{response.message}
          EOF
        remember(:down_at =&gt; Time.now)
      else
        if memory(:was_up) &amp;&amp; memory(:down_at)
          alert( &quot;The URL [#{url}] is responding again&quot;,
                 &quot;URL: #{url}\n\nStatus: #{response.class.to_s[/^Net::HTTP(.*)$/, 1]}. &quot; +
                 &quot;Was unresponsive for #{(Time.now - memory(:down_at)).to_i} seconds&quot;)
        else
          alert( &quot;The URL [#{url}] is responding&quot;,
                 &quot;URL: #{url}\n\nStatus: #{response.class.to_s[/^Net::HTTP(.*)$/, 1]}. &quot;)
        end
        memory.delete(:down_at)
      end
    end
    
    remember(:was_up =&gt; is_up)
  rescue Exception =&gt; e
    error( &quot;Error monitoring url [#{url}]&quot;,
           &quot;#{e.message}&lt;br&gt;&lt;br&gt;#{e.backtrace.join('&lt;br&gt;')}&quot; )
  end
  
  def valid_http_response?(result)
    [HTTPOK,HTTPFound].include?(result.class) 
  end
  
  # returns the http response (string) from a url
  def http_response(url)
    uri = URI.parse(url)

    response = nil
    retry_url_trailing_slash = true
    retry_url_execution_expired = true
    begin
      http = Net::HTTP.new(uri.host,uri.port)
      http.use_ssl = url =~ %r{\Ahttps://}
      http.start(){|http|
            http.open_timeout = TIMEOUT_LENGTH
            req = Net::HTTP::Get.new((uri.path != '' ? uri.path : '/' ) + (uri.query ? ('?' + uri.query) : ''))
            if uri.user &amp;&amp; uri.password
              req.basic_auth uri.user, uri.password
            end
            response = http.request(req)
      }
    rescue Exception =&gt; e
      # forgot the trailing slash...add and retry
      if e.message == &quot;HTTP request path is empty&quot; and retry_url_trailing_slash
        url += '/'
        uri = URI.parse(url)
        h = Net::HTTP.new(uri.host)
        retry_url_trailing_slash = false
        retry
      elsif e.message =~ /execution expired/ and retry_url_execution_expired
        retry_url_execution_expired = false
        retry
      else
        response = e.to_s
      end
    end
        
    return response
  end

  def unindent(string)
    indentation = string[/\A\s*/]
    string.strip.gsub(/^#{indentation}/, &quot;&quot;)
  end
end
</code>
    <created-at type="datetime">2007-12-12T23:50:57Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors the availability of a URL, sending an alert if the URL is not reachable. 
&lt;br/&gt;
An alert is generated every time the URL is unreachable.
&lt;br/&gt;
Accepts a single option - the url to monitor.</description>
    <featured type="boolean">false</featured>
    <id type="integer">2</id>
    <metadata type="yaml">--- |
options:
  url:
    name: Url
    notes: The full URL (including http://) of the URL to monitor. You can provide basic authentication options as well (http://user:pass@domain.com)
    default: &quot;http://www.scoutapp.com/&quot;

metadata:
  response_time:          
    label: Response Time
    units: secs
    precision: 2
    larger_is_better: false
  up:          
    label: Url Reachable
    precision: 0
    larger_is_better: true

</metadata>
    <name>URL Monitoring</name>
    <plugins-count type="integer">242</plugins-count>
    <rating-avg type="decimal">3.0</rating-avg>
    <rating-count type="integer">1</rating-count>
    <rating-total type="integer">3</rating-total>
    <readme>URL Monitoring Plugin
=====================
Created by [Highgroove Studios LLC](http://www.highgroove.com)

Compatibility 
-------------
Works fully on Linux and OSX. 

</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors the availability of a URL, sending an alert if the URL is not reachable. 

The following data is reported:

* Url Reachable (1 if reachable, 0 if not)
* Response Time (secs)</short-description>
    <tested-platforms>linux macosx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-01-21T23:08:55Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/url_monitor/url_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>uptime</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class Uptime &lt; Scout::Plugin
  def build_report
    if `uptime` =~ /up +([^,]+)/
      report :uptime =&gt; $1
    else
      raise &quot;Unexpected output format&quot;  
    end
  rescue Exception
    error &quot;Couldn't use `uptime` as expected.&quot;, $!.message
  end
end</code>
    <created-at type="datetime">2007-12-21T18:29:53Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Returns the length of time since the last server restart.</description>
    <featured type="boolean">false</featured>
    <id type="integer">5</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Server Uptime</name>
    <plugins-count type="integer">155</plugins-count>
    <rating-avg type="decimal">3.0</rating-avg>
    <rating-count type="integer">1</rating-count>
    <rating-total type="integer">3</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Returns the length of time since the last server restart.</short-description>
    <tested-platforms>linux macosx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:07Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/uptime/uptime.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Rob Lingle, Eric Lindvall</author>
    <cached-tag-list>disk, io, iostat</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class Iostat &lt; Scout::Plugin

  OPTIONS=&lt;&lt;-EOS
  device:
    name: Device
    notes: The device to check, eg 'sda1'. If not specified, uses the device mounted at '/'
  EOS

  def build_report
    stats = iostat(device)

    error(&quot;Device not found: #{device} -- check your plugin settings.&quot;,
          &quot;FYI, mount returns:\n#{`mount`}&quot;) and return if !stats

    counter(:rps,   stats['rio'],        :per =&gt; :second)
    counter(:wps,   stats['wio'],        :per =&gt; :second)
    counter(:rkbps, stats['rsect'] / 2,  :per =&gt; :second)
    counter(:wkbps, stats['wsect'] / 2,  :per =&gt; :second)
    counter(:util,  stats['use'] / 10.0, :per =&gt; :second)

    if old = memory(&quot;#{device}_stats&quot;)
      ios = (stats['rio'] - old['rio']) + (stats['wio']  - old['wio'])

      if ios &gt; 0
        await = ((stats['ruse'] - old['ruse']) + (stats['wuse'] - old['wuse'])) / ios.to_f

        report(:await =&gt; await)
      end
    end

    remember(&quot;#{device}_stats&quot; =&gt; stats)
  end
  
  private
  COLUMNS = %w(major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq)

  def iostat(dev)
    IO.foreach('/proc/diskstats') do |line|
      entry = Hash[*COLUMNS.zip(line.strip.split(/\s+/).collect { |v| Integer(v) rescue v }).flatten]

      return entry if dev.include?(entry['name'])
    end

    nil
  end

  def device
    option('device') || `mount`.split(&quot;\n&quot;).grep(/ \/ /)[0].split[0]
  end

  # Would be nice to be part of scout internals
  def counter(name, value, options = {}, &amp;block)
    current_time = Time.now

    if data = memory(name)
      last_time, last_value = data[:time], data[:value]
      elapsed_seconds       = current_time - last_time

      # We won't log it if the value has wrapped or enough time hasn't
      # elapsed
      if value &gt;= last_value &amp;&amp; elapsed_seconds &gt;= 1
        if block
          result = block.call(last_value, value)
        else
          result = value - last_value
        end

        case options[:per]
        when :second, 'second'
          result = result / elapsed_seconds.to_f
        when :minute, 'minute'
          result = result / elapsed_seconds.to_f / 60.0
        else
          raise &quot;Unknown option for ':per': #{options[:per].inspect}&quot;
        end

        if options[:round]
          # Backward compatibility
          options[:round] = 1 if options[:round] == true

          result = (result * (10 ** options[:round])).round / (10 ** options[:round]).to_f
        end

        report(name =&gt; result)
      end
    end

    remember(name =&gt; { :time =&gt; current_time, :value =&gt; value })
  end
end
</code>
    <created-at type="datetime">2009-07-15T22:45:37Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Parses &lt;code&gt;/proc/diskstats&lt;/code&gt; to report I/O stats. A specific device can be specified (by default, the device mounted at '/' is checked). 

Reports the following data:

* Reads/sec
* Writes/sec
* Read kBps
* Write kBps
* I/O Wait
* Utilization
 
Compatibility: Works on Linux and OSX. </description>
    <featured type="boolean">false</featured>
    <id type="integer">161</id>
    <metadata type="yaml">--- |
metadata:
  rps:
    label: Reads/sec
    precision: 0
  wps:
    label: Writes/sec
    precision: 0
  rkbps:
    label: Read kBps
    precision: 1
    units: kB/s
  wkbps:
    label: Write kBps
    precision: 1
    units: kB/s
  await:
    label: I/O Wait
    precision: 1
    units: ms
  util:
    label: Utilization
    precision: 0
    units: %

triggers:
  - type: peak
    dname: util
    max_value: 80%

</metadata>
    <name>Device Input/Output (iostat)</name>
    <plugins-count type="integer">151</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>I/O Statistics Plugin
=================================
Created by [Rob Lingle](http://github.com/roblingle)
Rewritten by [Eric Lindvall](http://github.com/eric) to not use iostat

Reports the current utilization

Dependencies
------------
Requires /proc/diskstats. 

Compatibility 
-------------

Works on Linux. 
</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Reports the current utilization.</short-description>
    <tested-platforms>Linux and OSX</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-06T01:01:53Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/iostat/iostat.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Forumwarz</author>
    <cached-tag-list>mysql</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;time&quot;
require &quot;digest/md5&quot;

# MySQL Slow Queries Monitoring plug in for scout.
# Created by Robin &quot;Evil Trout&quot; Ward for Forumwarz, based heavily on the Rails Request
# Monitoring Plugin.
#
# See: http://blog.forumwarz.com/2008/5/27/monitor-slow-mysql-queries-with-scout
#
# Example line from a slow queries log file:
#
# Time: 080606 15:22:26
# User@Host: root[root] @ localhost []
# Query_time: 21  Lock_time: 0  Rows_sent: 18  Rows_examined: 8157
# SELECT SQL_NO_CACHE IF('2008-04-18 19:03:00' &lt;= reports.time AND reports.time &lt; '2008-04-20 10:21:00', 0, IF('2008-04-20 10:21:00' &lt;= reports.time AND reports.time &lt; '2008-04-22 01:39:00', 1, IF('2008-04-22 01:39:00' &lt;= repo

class ScoutMysqlSlow &lt; Scout::Plugin
  needs &quot;elif&quot;
  
  # In order to limit the alert body size, only the first +MAX_QUERIES+ are listed in the alert body. 
  MAX_QUERIES = 10
  
  def build_report
    log_file_path = option(&quot;mysql_slow_log&quot;).to_s.strip
    if log_file_path.empty?
      return error( &quot;A path to the MySQL Slow Query log file wasn't provided.&quot;,
                    &quot;The full path to the slow queries log must be provided. Learn more about enabling the slow queries log here: http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html&quot; )
    end

    slow_query_count = 0
    all_queries = [] # all of the queries from the log file are stored here
    slow_queries = [] # only the slow queries are placed here
    sql = []
    last_run = memory(:last_run) || Time.now
    minimum_query_time = option(:minimum_query_time).to_f
    current_time = Time.now
    
    # starts at the bottom of the log file, moving up
    Elif.foreach(log_file_path) do |line|
      if line =~ /^# Query_time: ([\d\.]+) .+$/
        query_time = $1.to_f
        all_queries &lt;&lt; {:query_time =&gt; query_time, :sql =&gt; sql.reverse}
        sql = []
      elsif line =~ /^\# Time: (.*)$/
        t = Time.parse($1) {|y| y &lt; 100 ? y + 2000 : y}
        
        t2 = last_run
        if t &lt; t2
          break
        elsif all_queries.any?
          sq = all_queries.last
          if sq[:query_time] &gt;= minimum_query_time
            # this query occurred after the last time this plugin ran and should be counted.  
            slow_queries &lt;&lt; sq.merge({:time_of_query =&gt; t})
          end
        end
      elsif line !~ /^\#/ # an SQL query
        sql &lt;&lt; line
      end
    end  

    elapsed_seconds = current_time - last_run
    elapsed_seconds = 1 if elapsed_seconds &lt; 1
    # calculate per-second
    report(:slow_queries =&gt; slow_queries.size/(elapsed_seconds/60.to_f))
    if slow_queries.any?
      alert( build_alert(slow_queries,log_file_path) )
    end
    remember(:last_run,Time.now)
  rescue Errno::ENOENT =&gt; error
      error(&quot;Unable to find the MySQL slow queries log file&quot;, &quot;Could not find a MySQL slow queries log file at: #{option(:mysql_slow_log)}. Please ensure the path is correct.&quot;)    
  end
  
  def build_alert(slow_queries,log_file_path)
    subj = &quot;Maximum Query Time exceeded on #{slow_queries.size} #{slow_queries.size &gt; 1 ? 'queries' : 'query'}&quot;
    body = String.new
    slow_queries[0..(MAX_QUERIES-1)].each do |sq|
      body &lt;&lt; &quot;&lt;strong&gt;#{sq[:query_time]} sec query on #{sq[:time_of_query]}:&lt;/strong&gt;\n&quot;
      sql = sq[:sql].join
      sql = sql.size &gt; 500 ? sql[0..500] + '...' : sql
      body &lt;&lt; sql
      body &lt;&lt; &quot;\n\n&quot;
    end # slow_queries.each
    if slow_queries.size &gt; MAX_QUERIES
      body &lt;&lt; &quot;#{slow_queries.size-MAX_QUERIES} more slow queries occured. See the slow queries log file (located at #{log_file_path}) for more details.&quot;
    end
    {:subject =&gt; subj, :body =&gt; body}
  end # build_alert
end
</code>
    <created-at type="datetime">2008-06-06T21:35:26Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors for slow MySQL queries and generates an alert (containing the queries) whey they occur.

The plugin requires the path to your MySQL slow queries log file. 

h2. Enabling MySQL Slow Queries Logging

You must enable the &quot;MySQL slow queries log&quot;:http://dev.mysql.com/doc/refman/5.0/en/slow-query-log.html in your my.cnf file. 

This can be done with the following 2 lines: 

&lt;div class=&quot;terminal&quot;&gt;
set-variable=long_query_time=2
log-slow-queries=/var/log/mysql/mysql-slow.log
&lt;/div&gt;

A restart of mysql may be required. </description>
    <featured type="boolean">false</featured>
    <id type="integer">21</id>
    <metadata type="yaml">--- |-
options:
  mysql_slow_log:
    default: /var/log/mysql/mysql-slow.log
    name: Full path to the MySQL slow queries log file
  minimum_query_time:
    default: 0
    name: &quot;Minimum Query Time (sec)&quot;
    attributes: advanced
    notes: If the log file contains queries that are less than the specified time in seconds the queries will be ignored.
metadata:
  slow_queries:
    units: /min
    precision: 2
triggers:
  - type: trend
    dname: slow_queries
    direction: UP
    percentage_change: 30
    duration: 120
    window_reference: LAST_WEEK
    min_value: 0.3
</metadata>
    <name>MySQL Slow Queries</name>
    <plugins-count type="integer">127</plugins-count>
    <rating-avg type="decimal">5.0</rating-avg>
    <rating-count type="integer">3</rating-count>
    <rating-total type="integer">15</rating-total>
    <readme>Monitors for slow MySQL queries and generates an alert (containing the queries) whey they occur.

The plugin has two options, the path to your MySQL slow queries log and the threshold for a very slow query.

You must enable the [MySQL slow queries log](http://dev.mysql.com/doc/refman/5.0/en/slow-query-log.html) in your my.cnf file.

This can be done with the following 2 lines:

set-variable=long_query_time=2
log-slow-queries=/var/log/mysql/mysql-slow.log

</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors for slow MySQL queries and generates an alert (containing the queries) whey they occur.</short-description>
    <tested-platforms>Linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T01:54:45Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/mysql_slow_queries/mysql_slow_queries.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>passenger</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class PassengerMemoryStats &lt; Scout::Plugin
  def build_report
    cmd  = option(:passenger_memory_stats_command) || &quot;passenger-memory-stats&quot;
    data = `#{cmd} 2&gt;&amp;1`
    if $?.success?
      stats = parse_data(data)
      report(stats)
      stats.each do |name, total|
        short_name = name.sub(/_total\z/, &quot;&quot;)
        max        = option(&quot;max_#{short_name}&quot;).to_f
        next unless max.nonzero?
        num        = total.to_f
        mem_name   = &quot;#{name}_failure&quot;
        human_name = short_name.capitalize.
                                gsub(/_([a-z])/) { &quot; #{$1.capitalize}&quot;}.
                                gsub(&quot;Vms&quot;, &quot;VMS&quot;)
        if num &gt; max and not memory(mem_name)
          alert &quot;Maximum #{human_name} Exceeded (#{total})&quot;, ''
          remember(mem_name =&gt; true)
        elsif num &lt; max and memory(mem_name)
          alert &quot;Maximum #{human_name} Has Dropped Below Limit (#{total})&quot;, ''
          memory.delete(mem_name)
        else
          remember(mem_name =&gt; memory(mem_name))
        end
      end
    else
      error &quot;Could not get data from command&quot;, &quot;Error:  #{data}&quot;
    end
  end

  private

  def parse_data(data)
    table        = nil
    headers      = nil
    field_format = nil
    stats        = { &quot;apache_processes&quot;        =&gt; 0,
                     &quot;apache_vmsize_total&quot;     =&gt; 0.0,
                     &quot;apache_private_total&quot;    =&gt; 0.0,
                     &quot;nginx_processes&quot;         =&gt; 0,
                     &quot;nginx_vmsize_total&quot;      =&gt; 0.0,
                     &quot;nginx_private_total&quot;     =&gt; 0.0,
                     &quot;passenger_processes&quot;     =&gt; 0,
                     &quot;passenger_vmsize_total&quot;  =&gt; 0.0,
                     &quot;passenger_private_total&quot; =&gt; 0.0 }

    data.each do |line|
      line = line.gsub(/\e\[\d+m/,'')
      if line =~ /^\s*-+\s+(Apache|Passenger|Nginx)\s+processes/
        table        = $1.downcase
        headers      = nil
        field_format = nil
      elsif table and line =~ /^\s*###\s+Processes:\s*(\d+)/
        stats[&quot;#{table}_processes&quot;] = $1
      elsif table and line =~ /^[A-Za-z]/
        headers      = line.scan(/\S+\s*/)
        field_format = headers.map { |h| &quot;A#{h.size - 1}&quot; }.join(&quot;x&quot;).
                               sub(/\d+\z/, &quot;*&quot;)
        headers.map! { |h| h.strip.downcase }
      elsif table and headers and line =~ /^\d/
        fields = Hash[*headers.zip(line.strip.unpack(field_format)).flatten]
        stats[&quot;#{table}_vmsize_total&quot;] += as_mb(fields[&quot;vmsize&quot;])
        stats[&quot;#{table}_private_total&quot;] += as_mb(fields[&quot;private&quot;])
      end
    end

    stats.each_key do |field|
      if field =~ /(?:vmsize|private)_total\z/
        stats[field] = &quot;#{stats[field]} MB&quot;
      end
    end

    stats
  end

  def as_mb(memory_string)
    num = memory_string.to_f
    case memory_string
    when /\bB/i
      num / (1024 * 1024).to_f
    when /\bKB/i
      num / 1024.0
    when /\bGB/i
      num * 1024
    else
      num
    end
  end
end
</code>
    <created-at type="datetime">2008-08-22T15:49:33Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>&lt;p&gt;Tracks &quot;Phusion Passenger's&quot;:http://www.modrails.com VM size, process count, and the amount of private memory it has squirreled away. You can also elect to be emailed if any of these statistics crosses a line you indicate.  As an added bonus, this plugin also tracks the same statistics for the Apache instance managing Passenger.&lt;/p&gt;
&lt;p&gt;
The passenger-memory-stats program recommends that you run it with super user privileges to gain more information. This plugin is usable without the extra access rights, but you will need to add them if you want the full details.
 &lt;/p&gt;
&lt;p&gt;
Note that *you need to edit the sudoers file on your server to allow the Scout agent to run @passenger-memory-stats@ without a password*. You will need to address this access issue on your server. &quot;Learn how here&quot;:https://scoutapp.com/plugin_urls/82-phusion-passenger-monitor/help_entries/91
 &lt;/p&gt;</description>
    <featured type="boolean">false</featured>
    <id type="integer">82</id>
    <metadata type="yaml">--- |
options:
  passenger_memory_stats_command:
    name: The Passenger Memory Stats Command
    notes: The full path to the passenger-memory-stats command.
    default: /usr/bin/passenger-memory-stats
  max_apache_processes:
    name: Max Apache Processes
    notes: If Apache's process count is larger than this amount, an alert is generated.  Use 0 to disable this check.
    default: 0
  max_apache_vmsize:
    name: Max Apache VMSize (MB)
    notes: If Apache's memory is larger than this amount, an alert is generated.  Use 0 to disable this check.
    default: 2000
  max_apache_private:
    name: Max Apache Private Memory (MB)
    notes: If Apache's private memory is larger than this amount, an alert is generated.  Use 0 to disable this check.
    default: 0
  max_passenger_processes:
    name: Max Passenger Processes
    notes: If Passenger's process count is larger than this amount, an alert is generated.  Use 0 to disable this check.
    default: 0
  max_passenger_vmsize:
    name: Max Passenger VMSize (MB)
    notes: If Passenger's memory is larger than this amount, an alert is generated.  Use 0 to disable this check.
    default: 500
  max_passenger_private:
    name: Max Passenger Private Memory (MB)
    notes: If Passenger's private memory is larger than this amount, an alert is generated.  Use 0 to disable this check.
    default: 0

</metadata>
    <name>Phusion Passenger Monitor</name>
    <plugins-count type="integer">118</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Passenger Memory Stats
======================

Created by [Highgroove Studios LLC](http://www.highgroove.com)

Compatibility 
-------------

Works on Linux.

Sudo Usage
----------

The passenger-memory-stats program recommends that you run it would super user privileges to gain more information.  This plugin is usable without the extra access rights, but you will need to add them if you want the full details.

It's important to note though that it is not safe for you to transmit your super user password to us.  You will need to address this access issue on your server.

Our recommended procedure to handle this is:

1. Edit the sudoers file on your server to allow the user that runs the scout client listed in your crontab to be able to run passenger-memory-stats without a password
2. Login into Scout and edit your plugin settings to add sudo in front of the command name
</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Tracks Passenger's VM size, process count, and the amount of private memory it has squirreled away. You can also elect to be emailed if any of these statistics crosses a line you indicate.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T05:16:53Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/5bb58ea082496cbbef5f8d1bb0d84a2a82b0297a/passenger_memory_stats/passenger_memory_stats.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Eric Lindvall</author>
    <cached-tag-list>mysql</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># 
# Created by Eric Lindvall &lt;eric@5stops.com&gt;
#

require 'set'

class MysqlQueryStatistics &lt; Scout::Plugin
  ENTRIES = %w(Com_insert Com_select Com_update Com_delete).to_set
  
  needs &quot;mysql&quot;

  def build_report
    # get_option returns nil if the option value is blank
    user     = get_option(:user) || 'root'
    password = get_option(:password)
    host     = get_option(:host)
    port     = get_option(:port)
    socket   = get_option(:socket)
    
    now = Time.now
    mysql = Mysql.connect(host, user, password, nil, (port.nil? ? nil : port.to_i), socket)
    result = mysql.query('SHOW /*!50002 GLOBAL */ STATUS')
    rows = []
    total = 0
    result.each do |row| 
      rows &lt;&lt; row if ENTRIES.include?(row.first)

      total += row.last.to_i if row.first[0..3] == 'Com_'
    end
    result.free

    report_hash = {}
    rows.each do |row|
      name = row.first[/_(.*)$/, 1]
      value = calculate_counter(now, name, row.last.to_i)
      # only report if a value is calculated
      next unless value
      report_hash[name] = value
    end


    total_val = calculate_counter(now, 'total', total)
    report_hash['total'] = total_val if total_val
    
    report(report_hash)
  end

  private
  
  # Returns nil if an empty string
  def get_option(opt_name)
    val = option(opt_name)
    val = (val.is_a?(String) and val.strip == '') ? nil : val
    return val
  end
  
  # Note this calculates the difference between the last run and the current run.
  def calculate_counter(current_time, name, value)
    result = nil
    # only check if a past run has a value for the specified query type
    if memory(name) &amp;&amp; memory(name).is_a?(Hash)
      last_time, last_value = memory(name).values_at(:time, :value)
      # We won't log it if the value has wrapped
      if last_value and value &gt;= last_value
        elapsed_seconds = current_time - last_time
        elapsed_seconds = 1 if elapsed_seconds &lt; 1
        result = value - last_value

        # calculate per-second
        result = result / elapsed_seconds.to_f
      end
    end
    remember(name =&gt; {:time =&gt; current_time, :value =&gt; value})
    
    result
  end
end

</code>
    <created-at type="datetime">2008-06-24T22:14:02Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Returns the number of each of type of query as well as the total number of queries: 
* Delete
* Insert
* Update
* Select

Requires the MySQL gem.</description>
    <featured type="boolean">false</featured>
    <id type="integer">22</id>
    <metadata type="yaml">--- |-
options:
  user:
    name: MySQL username
    notes: Specify the username to connect with
    default: root
  password:
    name: MySQL password
    notes: Specify the password to connect with
  host:
    name: MySQL host
    notes: Specify something other than 'localhost' to connect via TCP
    default: localhost
  port:
    name: MySQL port
    notes: Specify the port to connect to MySQL with (if nonstandard)
  socket:
    name: MySQL socket
    notes: Specify the location of the MySQL socket
    
metadata:
  select:
    label: Select Queries
    units: /sec
  delete:
    label: Delete Queries
    units: /sec
  update:
    label: Update Queries
    units: /sec
  insert:
    label: Insert Queries
    units: /sec
  replace:
    label: Replace Queries
    units: /sec
  total:
    label: Total Queries
    units: /sec

triggers:    
  - type: trend
    data_series_name: total
    direction: UP                            
    percentage_change: 30                    
    duration: 60                           
    window_reference: LAST_WEEK
</metadata>
    <name>MySQL Statistics</name>
    <plugins-count type="integer">116</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Returns the number of each of type of query (delete, insert, update, select, and total). 

Requires the MySQL gem.</short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-12-07T21:34:15Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/1583aee15d63ae531d6fbd0c2cff53f8873bf348/mysql_query_statistics/mysql_query_statistics.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Eric Lindvall</author>
    <cached-tag-list>network</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># 
# Created by Eric Lindvall &lt;eric@5stops.com&gt;
#

class NetworkThroughput &lt; Scout::Plugin
  def build_report
    lines = IO.readlines('/proc/net/dev')[2..-1]

    lines.each do |line|
      iface, rest = line.split(':', 2).collect { |e| e.strip }
      next unless iface =~ /eth/
      cols = rest.split(/\s+/)

      in_bytes, in_packets, out_bytes, out_packets = cols.values_at(0, 1, 8, 9).collect { |i| i.to_i }

      local_counter(&quot;#{iface}_in&quot;,          in_bytes / 1024.0,  :per =&gt; :second, :round =&gt; 2)
      local_counter(&quot;#{iface}_in_packets&quot;,  in_packets,         :per =&gt; :second, :round =&gt; 2)
      local_counter(&quot;#{iface}_out&quot;,         out_bytes / 1024.0, :per =&gt; :second, :round =&gt; 2)
      local_counter(&quot;#{iface}_out_packets&quot;, out_packets,        :per =&gt; :second, :round =&gt; 2)
    end
  rescue Exception =&gt; e
    error(&quot;#{e.class}: #{e.message}\n\t#{e.backtrace.join(&quot;\n\t&quot;)}&quot;)
  end

  private
  # Would be nice to be part of scout internals
  def local_counter(name, value, options = {})
    current_time = Time.now

    if data = memory(name)
      last_time, last_value = data[:time], data[:value]
      elapsed_seconds       = current_time - last_time

      # We won't log it if the value has wrapped or enough time hasn't
      # elapsed
      if value &gt;= last_value &amp;&amp; elapsed_seconds &gt;= 1
        result = value - last_value

        case options[:per]
        when :second, 'second'
          result = result / elapsed_seconds.to_f
        when :minute, 'minute'
          result = result / elapsed_seconds.to_f / 60.0
        end

        if options[:round]
          # Backward compatibility
          options[:round] = 1 if options[:round] == true

          result = (result * (10 ** options[:round])).round / (10 ** options[:round]).to_f
        end

        report(name =&gt; result)
      end
    end

    remember(name =&gt; { :time =&gt; current_time, :value =&gt; value })
  end
end
</code>
    <created-at type="datetime">2010-01-27T20:49:21Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Measures network in/out in KB per sec and packets per sec.

This plugin relies on the existence of /proc/net/dev.</description>
    <featured type="boolean">false</featured>
    <id type="integer">261</id>
    <metadata type="yaml">--- |
metadata:
  eth0_out:
    units: KB/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth0 out
  eth0_out_packets:
    units: pkts/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth0 out packets
  eth0_in: 
    units: KB/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth0 in
  eth0_in_packets:
    units: pkts/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth0 in packets
  eth1_out_packets: 
    units: pkts/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth1 out packets
  eth1_out:
    units: KB/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth1 out
  eth1_in:
    units: KB/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth1 in
  eth1_in_packets:
    units: pkts/s
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: eth1 in packets

</metadata>
    <name>Network Throughput</name>
    <plugins-count type="integer">95</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">4</scout-version>
    <short-description>Measures network in/out in KB per sec and packets per sec. </short-description>
    <tested-platforms>linux, Solaris, and OSX.</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-01-27T20:51:35Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/network_throughput/network_throughput.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Scout</author>
    <cached-tag-list>apache</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;time&quot;
require &quot;stringio&quot;

class ApacheAnalyzer &lt; Scout::Plugin
  ONE_DAY    = 60 * 60 * 24

  needs &quot;elif&quot;
  needs &quot;request_log_analyzer&quot;

  def build_report
    patch_elif

    log_path = option(:log)
    format = option(:format) || 'common'
    request_count = 0
    lines_scanned = 0
    report_data = { :request_rate     =&gt; 0, :lines_scanned =&gt; 0 }
    last_run = memory(:last_request_time) || Time.now-60 # analyze last minute on first invocation

    # read backward, counting lines
    Elif.foreach(log_path) do |line|
      lines_scanned += 1
      if line =~ /(\d{2}\/[A-Za-z]{3}\/\d{4})(.)(\d{2}:\d{2}:\d{2})(?: .\d{4})?/
        # CLF logs time with a ':' between date and time; Time.parse doesn't like this
        time_of_request = Time.parse(&quot;#{$1} #{$3}&quot;)

        if time_of_request &lt; last_run
          break
        else
          request_count += 1
        end
      end

    end

    # calculate request_rate
    if request_count &gt; 0
      # calculate the time btw runs in minutes
      interval = (Time.now-last_run)
      interval &lt; 1 ? inteval = 1 : nil # if the interval is less than 1 second (may happen on initial run) set to 1 second
      interval = interval/60 # convert to minutes
      interval = interval.to_f
      # determine the rate of requests and slow requests in requests/min
      request_rate                         = request_count /
                                             interval
      report_data[:request_rate]           = sprintf(&quot;%.2f&quot;, request_rate)

    end

    # report data
    remember(:last_request_time, Time.now)
    report_data[:lines_scanned] = lines_scanned
    report(report_data)

    if log_path &amp;&amp; !log_path.empty?
      generate_log_analysis(log_path, format)
    else
      return error(&quot;A path to the Apache log file wasn't provided.&quot;,&quot;Please provide the full path to the Apache log file to analyze (ie - /var/www/apps/APP_NAME/log/access_log)&quot;)
    end
  end

  private

  def silence
    old_verbose, $VERBOSE, $stdout = $VERBOSE, nil, StringIO.new
    yield
  ensure
    $VERBOSE, $stdout = old_verbose, STDOUT
  end

  def generate_log_analysis(log_path, format)
    # decide if it's time to run the analysis yet today
    if option(:rla_run_time) =~ /\A\s*(0?\d|1\d|2[0-3]):(0?\d|[1-4]\d|5[0-9])\s*\z/
      run_hour    = $1.to_i
      run_minutes = $2.to_i
    else
      run_hour    = 23
      run_minutes = 45
    end
    now = Time.now
    if last_summary = memory(:last_summary_time)
      if now.hour &gt; run_hour       or
        ( now.hour == run_hour     and
          now.min  &gt;= run_minutes ) and
         %w[year mon day].any? { |t| last_summary.send(t) != now.send(t) }
        remember(:last_summary_time, now)
      else
        remember(:last_summary_time, last_summary)
        return
      end
    else
      last_summary = now - ONE_DAY
      remember(:last_summary_time, last_summary)
    end
    # make sure we get a full run
    if now - last_summary &lt; 60 * 60 * 22
      last_summary = now - ONE_DAY
    end

    self.class.class_eval(RLA_EXTS)

    analysis = analyze(last_summary, now, log_path, format)

    summary( :command =&gt; &quot;request-log-analyzer --after '&quot;                   +
                         last_summary.strftime('%Y-%m-%d %H:%M:%S')         +
                         &quot;' --before '&quot; + now.strftime('%Y-%m-%d %H:%M:%S') +
                         &quot;' --apache-format &quot;+format +
                         &quot; '#{log_path}'&quot;,
             :output  =&gt; analysis )
  rescue Exception =&gt; error
    error(&quot;#{error.class}:  #{error.message}&quot;, error.backtrace.join(&quot;\n&quot;))
  end

  def analyze(last_summary, stop_time, log_path, format)
    log_file = read_backwards_to_timestamp(log_path, last_summary)
    summary = StringIO.new
    RequestLogAnalyzer::Controller.build(
      :format       =&gt; { :apache =&gt; format },
      :output       =&gt; EmbeddedHTML,
      :file         =&gt; summary,
      :after        =&gt; last_summary,
      :before       =&gt; stop_time,
      :source_files =&gt; log_file
    ).run!
    summary.string.strip
  end

  def patch_elif
    if Elif::VERSION &lt; &quot;0.2.0&quot;
      Elif.send(:define_method, :pos) do
        @current_pos +
        @line_buffer.inject(0) { |bytes, line| bytes + line.size }
      end
    end
  end

  def read_backwards_to_timestamp(path, timestamp)
    start = nil
    Elif.open(path) do |elif|
      elif.each do |line|
        if line =~ /\AProcessing .+ at (\d+-\d+-\d+ \d+:\d+:\d+)\)/
          time_of_request = Time.parse($1)
          if time_of_request &lt; timestamp
            break
          else
            start = elif.pos
          end
        end
      end
    end

    file = open(path)
    file.seek(start) if start
    file
  end

  RLA_EXTS = &lt;&lt;-'END_RUBY'
  class EmbeddedHTML &lt; RequestLogAnalyzer::Output::Base

    include RequestLogAnalyzer::Output::FixedWidth::Monochrome

    def print(str)
      @io &lt;&lt; str
    end
    alias_method :&lt;&lt;, :print

    def puts(str = &quot;&quot;)
      @io &lt;&lt; &quot;#{str}&lt;br/&gt;\n&quot;
    end

    def title(title)
      @io.puts(tag(:h2, title))
    end

    def line(*font)
      @io.puts(tag(:hr))
    end

    def link(text, url = nil)
      url = text if url.nil?
      tag(:a, text, :href =&gt; url)
    end

    def table(*columns, &amp;block)
      rows = Array.new
      yield(rows)

      @io &lt;&lt; tag(:table, :cellspacing =&gt; 0) do |content|
        if table_has_header?(columns)
          content &lt;&lt; tag(:tr) do
            columns.map { |col| tag(:th, col[:title]) }.join(&quot;\n&quot;)
          end
        end

        odd = false
        rows.each do |row|
          odd = !odd
          content &lt;&lt; tag(:tr) do
            if odd
              row.map { |cell| tag(:td, cell, :class =&gt; &quot;alt&quot;) }.join(&quot;\n&quot;)
            else
              row.map { |cell| tag(:td, cell) }.join(&quot;\n&quot;)
            end
          end
        end
      end
    end

    def header
    end

    def footer
      @io &lt;&lt; tag(:hr) &lt;&lt; tag(:p, &quot;Powered by request-log-analyzer v#{RequestLogAnalyzer::VERSION}&quot;)
    end

    private

    def tag(tag, content = nil, attributes = nil)
      if block_given?
        attributes = content.nil? ? &quot;&quot; : &quot; &quot; + content.map { |(key, value)| &quot;#{key}=\&quot;#{value}\&quot;&quot; }.join(&quot; &quot;)
        content_string = &quot;&quot;
        content = yield(content_string)
        content = content_string unless content_string.empty?
        &quot;&lt;#{tag}#{attributes}&gt;#{content}&lt;/#{tag}&gt;&quot;
      else
        attributes = attributes.nil? ? &quot;&quot; : &quot; &quot; + attributes.map { |(key, value)| &quot;#{key}=\&quot;#{value}\&quot;&quot; }.join(&quot; &quot;)
        if content.nil?
          &quot;&lt;#{tag}#{attributes} /&gt;&quot;
        else
          if content.class == Float
            &quot;&lt;#{tag}#{attributes}&gt;&lt;div class='color_bar' style=\&quot;width:#{(content*200).floor}px;\&quot;/&gt;&lt;/#{tag}&gt;&quot;
          else
            &quot;&lt;#{tag}#{attributes}&gt;#{content}&lt;/#{tag}&gt;&quot;
          end
        end
      end
    end
  end
  END_RUBY
end
</code>
    <created-at type="datetime">2009-10-22T00:09:34Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>h2. Overview

Provides statistics from an Apache access log: request distribution by hour, most popular URIs, traffic sorted by sum, and traffic sorted by mean. Just install this plugin in Scout and provide the full path to the Apache access log file. The plugin uses the &quot;Request Log Analyzer gem&quot;:http://github.com/wvanbergen/request-log-analyzer/tree/master to generate reports on Apache log every 24 hours. When first installed, it will generate the report immediately.

Note that the Apache Log Analyzer may take a couple of minutes to run on large log files. 

h2. Dependencies

Requires:

&quot;elif gem&quot;:http://elif.rubyforge.org :

&lt;div class=&quot;terminal&quot;&gt;
sudo gem install elif
&lt;/div&gt;

&quot;request-log-analyzer gem&quot;:http://github.com/wvanbergen/request-log-analyzer/tree/master :

&lt;div class=&quot;terminal&quot;&gt;
sudo gem install request-log-analyzer
&lt;/div&gt;

h2. Compatibility 

Requires the Scout Agent version 4.0 or greater.</description>
    <featured type="boolean">false</featured>
    <id type="integer">201</id>
    <metadata type="yaml">--- &quot;options:\n  log:\n    name: Full Path to Apache Log File\n    notes: \&quot;The full path to the Apache log file you wish to analyze (ex: /var/www/apps/APP_NAME/current/log/access_log).\&quot;\n  format:\n    name: Apache Log format\n    notes: defaults to 'common'. Or specify custom log format, like %v %h %l %u %t \\\&quot;%r\\\&quot; %&gt;s %b time:%D\n    default: common\n  rla_run_time:\n    name: Request Log Analyzer Run Time (HH:MM)\n    notes: It's best to schedule these summaries about fifteen minutes before any logrotate cron job you have set would kick in.\n    default: '23:45'\n\n\
metadata:\n  request_rate:\n    precision: 2\n    label: Requests\n    units: req/min    &quot;
</metadata>
    <name>Apache Log Analyzer</name>
    <plugins-count type="integer">55</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Apache Log Analyzer Plugin
======================
Created by [Scout](http://scoutapp.com)

Overview
------------

Provides statistics from an Apache access log: request distribution by hour, most popular URIs, traffic sorted by sum, and traffic sorted by mean. Just install this plugin in Scout and provide the full path to the Apache access log file. The plugin uses the [Request Log Analyzer gem](http://github.com/wvanbergen/request-log-analyzer/tree/master) to generate reports on Apache log every 24 hours. When first installed, it will generate the report immediately.

Note that the Apache Log Analyzer may take a couple of minutes to run on large log files.

Where to find your Apache access log
------------
The location of your Apache log file depends on your Apache configuration. In Ubuntu, the access log defaults to `/var/log/httpd/access_log`. Typically, you will configure a separate access log for each virtual host. Check in your virtual host config for a CustomLog directive.

Advanced: Specifying an Apache log format
------------
If you're not sure what your Apache log format is, it's probably the default [Common Log Format (CLF)](http://httpd.apache.org/docs/2.2/logs.html#accesslog) -- in which case you can safely skip this section.

By default, this plugin expects the Common Log Format. If you have specified a different format in your Apache configuration, you'll need to tell this plugin what format you're using. A format string looks something like `%h %l %u %t &quot;%r&quot; %&gt;s %b`. Again, if you're not sure, just let the plugin run with the default settings.


Dependencies
------------

Requires:

[elif gem](http://elif.rubyforge.org/):

sudo gem install elif

[request-log-analyzer gem](http://github.com/wvanbergen/request-log-analyzer/tree/master)

sudo gem install request-log-analyzer

Compatibility
-------------

Tested on Linux, OSX, and Solaris. Requires the Scout Agent version 4.0 or greater.
</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">4</scout-version>
    <short-description>Provides statistics from an Apache access log: request distribution by hour, most popular URIs, traffic sorted by sum, and traffic sorted by mean. Just install this plugin in Scout and provide the full path to the Apache access log file.</short-description>
    <tested-platforms>Ubuntu, Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T02:03:27Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/2a2e0d8b06c293903abe3aa0d2de46f1a60016ab/apache_analyzer/apache_analyzer.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Lukas Rieder, Alexander Lang &amp; Eric Lindvall</author>
    <cached-tag-list>delayed_job</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>$VERBOSE=false

class MonitorDelayedJobs &lt; Scout::Plugin
  ONE_DAY    = 60 * 60 * 24
  
  OPTIONS=&lt;&lt;-EOS
  path_to_app:
    name: Full Path to the Rails Application
    notes: &quot;The full path to the Rails application (ex: /var/www/apps/APP_NAME/current).&quot;
  rails_env:
    name: Rails environment that should be used
    default: production
  EOS
  
  
  needs 'active_record', 'yaml', 'erb'

  require 'active_record'
  class DelayedJob &lt; ActiveRecord::Base; end
  
  def build_report
    
    app_path = option(:path_to_app)
    
    # Ensure path to db config provided
    if !app_path or app_path.empty?
      return error(&quot;The path to the Rails Application wasn't provided.&quot;,&quot;Please provide the full path to the Rails Application (ie - /var/www/apps/APP_NAME/current)&quot;)
    end
    
    db_config_path = app_path + '/config/database.yml'
    
    if !File.exist?(db_config_path)
      return error(&quot;The database config file could not be found.&quot;, &quot;The database config file could not be found at: #{db_config_path}. Please ensure the path to the Rails Application is correct.&quot;)
    end
    
    db_config = YAML::load(ERB.new(File.read(db_config_path)).result)
    ActiveRecord::Base.establish_connection(db_config[option(:rails_env)])
        
    report_hash = Hash.new
    
    # ALl jobs
    report_hash[:total]     = DelayedJob.count
    # Jobs that are currently being run by workers
    report_hash[:running]   = DelayedJob.count(:conditions =&gt; 'locked_at IS NOT NULL')
    # Jobs that are ready to run but haven't ever been run
    report_hash[:waiting]   = DelayedJob.count(:conditions =&gt; [ 'run_at &lt;= ? AND locked_at IS NULL AND attempts = 0', Time.now.utc ])
    # Jobs that haven't ever been run but are not set to run until later
    report_hash[:scheduled] = DelayedJob.count(:conditions =&gt; [ 'run_at &gt; ? AND locked_at IS NULL AND attempts = 0', Time.now.utc ])
    # Jobs that aren't running that have failed at least once
    report_hash[:failing]   = DelayedJob.count(:conditions =&gt; 'attempts &gt; 0 AND failed_at IS NULL AND locked_at IS NULL')
    # Jobs that have permanently failed
    report_hash[:failed]    = DelayedJob.count(:conditions =&gt; 'failed_at IS NOT NULL')
    
    # The oldest job that hasn't yet been run, in minutes
    if oldest = DelayedJob.find(:first, :conditions =&gt; [ 'run_at &lt;= ? AND locked_at IS NULL AND attempts = 0', Time.now.utc ], :order =&gt; :run_at)
      report_hash[:oldest] = (Time.now.utc - oldest.run_at) / 60
    else
      report_hash[:oldest] = 0
    end
    
    report(report_hash)
  end
end
</code>
    <created-at type="datetime">2010-02-02T01:15:36Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>!http://img.skitch.com/20100202-bwq87hym88cbahr635n8gqthq3.png!

Monitors &quot;Delayed Job&quot;:http://github.com/tobi/delayed_job, a Database-backed asynchronous priority queue.

The following metrics are tracked:

* Failed Jobs
* Failing Jobs
* Oldest Waiting Job in Minutes
* Running Jobs
* Scheduled Jobs
* Total Jobs
* Waiting Jobs

h2. Installation

Install the plugin on scoutapp.com and provide the full path to your Rails application.</description>
    <featured type="boolean">false</featured>
    <id type="integer">281</id>
    <metadata type="yaml">--- |
metadata: 
  failed:
    units: &quot;jobs&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Failed
  running:
    units: &quot;jobs&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Running
  waiting:
    units: &quot;jobs&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Waiting
  total: 
    units: &quot;jobs&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Total
  scheduled: 
    units: &quot;jobs&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Scheduled
  failing: 
    units: &quot;jobs&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Failing
  oldest: 
    units: &quot;minutes&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Oldest Waiting

</metadata>
    <name>Delayed Job</name>
    <plugins-count type="integer">43</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors Delayed Job, a Database-backed asynchronous priority queue.</short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-08T19:41:10Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/delayed_job/monitor_delayed_jobs.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Adam Parrott</author>
    <cached-tag-list>mongrel, monitor, process</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class MongrelClusterMonitor &lt; Scout::Plugin
  def run
    mongrel_configuration_dir = @options[&quot;mongrel_cluster_configuration_dir&quot;] || &quot;/etc/mongrel_cluster/&quot;
    mongrel_rails_command = @options[&quot;mongrel_rails_command&quot;] || &quot;mongrel_rails&quot;
    to_return = {:alerts =&gt; [], :report =&gt; {}, :memory =&gt; {}}
    Dir.chdir(mongrel_configuration_dir) do
      configs = Dir.glob(&quot;*.{yml,conf}&quot;)

      unless configs.empty?        
        configs.each do |config|
          application_name = config.gsub(&quot;.conf&quot;, &quot;&quot;).gsub(&quot;.yml&quot;, &quot;&quot;)
          mongrel_status = `#{mongrel_rails_command} cluster::status -C #{mongrel_configuration_dir}/#{config}`
          if mongrel_status.empty? 
            raise &quot;mongrel_rails command: `#{mongrel_rails_command}` not found or no status information available&quot;
          elsif mongrel_status.include?(&quot;missing&quot;)
            if @memory[application_name]
              to_return[:alerts] &lt;&lt; {:subject =&gt; &quot;#{application_name} is still down. Attempting Start.&quot;}
              mongrel_start = `#{mongrel_rails_command} cluster::start -C #{mongrel_configuration_dir}/#{config}`
            else
              to_return[:alerts] &lt;&lt; {:subject =&gt; &quot;#{application_name} is down.&quot;}
              to_return[:memory][application_name] = Time.now
            end
            to_return[:report][application_name] = 0
          else
            to_return[:report][application_name] = 1
            to_return[:memory][application_name] = nil
          end
        end
      else
        to_return[:alerts] &lt;&lt; {:subject =&gt; &quot;No mongrel configuration files found.&quot;}
      end
    end
    return to_return  
  rescue Exception
    { :error =&gt; { :subject =&gt; &quot;Couldn't monitor the server.&quot;,
                  :body    =&gt; &quot;An exception was thrown:  #{$!.message}&quot; } }
  end
end
</code>
    <created-at type="datetime">2008-02-01T20:55:26Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors mongrel clusters, reports uptime, and attempts restarts of down mongrels. 

Given a directory of mongrel configuration yaml files, it will systematically go through each application and report if the actual mongrels specified in the configuration file are running.  It will also attempt a restart (or rather, a start) of down mongrels.</description>
    <featured type="boolean">false</featured>
    <id type="integer">11</id>
    <metadata type="yaml">--- |+
options:
  mongrel_cluster_configuration_dir:
    name: Mongrel Cluster Configuration Directory
    notes: The directory where mongrel configurations are stored.
    default: /etc/mongrel_cluster
  mongrel_rails_command:
    name: Mongrel Rails Command
    notes: The full path to the mongrel_rails command.
    default: /usr/bin/mongrel_rails
    

</metadata>
    <name>Mongrel Cluster Monitor</name>
    <plugins-count type="integer">42</plugins-count>
    <rating-avg type="decimal" nil="true"></rating-avg>
    <rating-count type="integer" nil="true"></rating-count>
    <rating-total type="integer" nil="true"></rating-total>
    <readme>Mongrel Cluster Monitor
======================
Created by 
 * Adam Parrott [Plexus Web Creations](http://www.plexusweb.com/)
 * [Highgroove Studios LLC](http://www.highgroove.com)

Summary
------------

This plugin will monitor a directory of mongrel_cluster configuration files and attempt to run the &quot;status&quot; command using:

mongrel_rails cluster::status -C application.yml

If it finds a down mongrel (a search for the word &quot;missing&quot;), it will send an Alert.  On the subsequent run, if the mongrel is still down, it will attempt a &quot;start&quot; using:

mongrel_rails cluster::start -C application.yml

On the next subsequent run, if the mongrel is still down, it will continue to send Alerts, and repeat the process.

Dependencies
------------

Requires mongrel and mongrel_cluster [mongrel](http://mongrel.rubyforge.org/):

	sudo gem install mongrel mongrel_cluster
	
Options
-------

Mongrel Configuration Directory.  This is usually /etc/mongrel_cluster, the path that stores application .yml files for mongrel's cluster startup options.

Compatibility 
-------------

Works on Linux and OSX.


</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Monitors mongrel clusters, reports uptime, and attempts restarts of down mongrels. </short-description>
    <tested-platforms>mac os x, linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:12Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/mongrel_cluster_monitor/mongrel_cluster_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Will Ronco</author>
    <cached-tag-list>apache</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class ApacheLoad &lt; Scout::Plugin
  needs &quot;net/http&quot;, &quot;uri&quot;
	def build_report
    url = URI.parse(option(&quot;server_url&quot;))
		req = Net::HTTP::Get.new(url.path + &quot;?&quot; + url.query.to_s)
    res = Net::HTTP.start(url.host, url.port) {|http|
      http.request(req)
    }
		values = {}
		res.body.split(&quot;\n&quot;).each do |item|
			k, v = item.split(&quot;: &quot;)
			values[k] = v
		end
		total_accesses = values['Total Accesses'].to_i
		if (memory(:last_run_total_accesses) &amp;&amp; memory(:last_run_time))
			accesses_since_last_run = total_accesses - memory(:last_run_total_accesses)
			seconds_since_last_run = Time.now - memory(:last_run_time)
		else
			accesses_since_last_run = total_accesses
			seconds_since_last_run = values['Uptime'].to_i
		end
		
		current_accesses_per_second = accesses_since_last_run / seconds_since_last_run
		
		report(:current_load =&gt; current_accesses_per_second)
    remember(:last_run_time =&gt; Time.now)
    remember(:last_run_total_accesses =&gt; total_accesses)
  end
end</code>
    <created-at type="datetime">2009-12-08T21:48:36Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>h2. Overview

Reports Apache Throughput in requests per-second. This plugin parses the output of the Apache Server Status Page and requires the &quot;@mod_status@&quot;:http://httpd.apache.org/docs/2.0/mod/mod_status.html Apache module.

h2. Configuration

*Enable mod_status*

The Apache Server Status page (&quot;sample&quot;:http://www.apache.org/server-status?auto) must be accessible for the plugin to report stats. See &quot;this guide&quot;:http://www.debian-administration.org/article/Monitoring_Apache_with_mod_status for instructions on configuring the status page.

*Provide the URL to the machine-readable format*

Scout requires the machine-readable format of the status page. If @ExtendedStatus@ is set to @On@, you'll need to explicitly specify the machine-readable format of the page: 

!http://img.skitch.com/20100212-8cd2b6qs4umgi467hcf681y8ea.png!

To access the machine-readable page, just add the following parameter to the status page URL in your Scout settings: @?auto@. </description>
    <featured type="boolean">false</featured>
    <id type="integer">221</id>
    <metadata type="yaml">--- |-
options:
  server_url:
    name: Server Status URL
    notes: Specify URL of the server-status page to check. Scout requires the machine-readable format of the status page (just add '?auto' to the server-status page URL).
    default: &quot;http://localhost/server-status?auto&quot;

metadata:
  current_load:          
    label: Requests Per Second
    units: req/s
    precision: 2
</metadata>
    <name>Apache Load</name>
    <plugins-count type="integer">28</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Apache Load Plugin
======================
Created by [Will Ronco](http://awesome-software.net)

Overview
------------

Reports Apache Throughput in requests per-second. This plugin parses the output of the Apache Server Status Page and requires the [mod_status](http://httpd.apache.org/docs/2.0/mod/mod_status.html
) Apache module.

Configuration
------------

The Apache Server Status page ([sample:](http://www.apache.org/server-status?auto
)) must be accessible for the plugin to report stats. See [this guide](http://www.debian-administration.org/article/Monitoring_Apache_with_mod_status
) for instructions on configuring the status page.


</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors Apache traffic, reporting throughput in requests per-second.

</short-description>
    <tested-platforms>Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-16T16:19:03Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/apache_load/apache_load.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Sam Sinensky</author>
    <cached-tag-list>sphinx</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># Created by Sam Sinensky (http://github.com/samsinensky) at Code and Beats (http://codeandbeats.com/) 12/29/09
class SphinxMonitor &lt; Scout::Plugin
  
  needs 'elif'
  needs 'time'
  
  OPTIONS=&lt;&lt;-EOS
  search_log_path:
    name: Searchd log path
    notes: This is the path to the log file
  query_log_path:
    name: Query log path
    notes: This is the path to the query log
  EOS
  
  def build_report
    
    #test command  = scout test sphinx_monitor.rb query_log_path=/Users/sam/Desktop/query.log.bak search_log_path=/Users/sam/Desktop/searchd.log.bak
     
     search_log_path = option(:search_log_path)
     
     query_log_path =  option(:query_log_path)
     
     unless search_log_path and not search_log_path.empty? and query_log_path and not query_log_path.empty?
       return error(&quot;Full paths to the searchd log and/or searchd query file(s) were not provided.&quot;,&quot;Please provide the full paths to the log files in the plugin settings.&quot;)
     end
     
     last_run = memory(:last_request_time) || Time.now

     #in seconds or amount/second
     report_data = {
       :query_rate =&gt; 0,
       :average_query_time =&gt; 0,
       :average_results_returned =&gt; 0,
       :index_rebuilds =&gt; 0,
       :average_time_per_rebuild =&gt; 0
     }
     
     #calculate the stats based on queries, rate, avg_time and average results returned
     
     #Load each line from the log in if it happened after the last request used in the previous report
     queries = 0
     total_query_time = 0
     total_results_returned = 0
     begin
       Elif.foreach(query_log_path) do |line|
         #extract the date form the line and make sure it occured after last_run
         line_data = parse_query_line(line)
         if line_data.timestamp.to_f &lt;= last_run.to_f
           break
         else
           queries+=1
           total_query_time += line_data.time_spent
           total_results_returned += line_data.results_returned
         end
       end
     
       if queries &gt; 0 
         # calculate the time btw runs in minutes
         interval = (Time.now-last_run)
         interval &lt; 1 ? inteval = 1 : nil # if the interval is less than 1 second (may happen on initial run) set to 1 second
         interval = interval/60 # convert to minutes
         interval = interval.to_f
         # determine the rate of queries in queries/min
         query_rate                             = queries / interval
         report_data[:query_rate]               = sprintf(&quot;%.2f&quot;, query_rate)
         report_data[:average_query_time]       = sprintf(&quot;%.4f&quot;, total_query_time/queries)
         report_data[:average_results_returned] = sprintf(&quot;%.4f&quot;, total_results_returned/queries)
       end
     rescue Errno::ENOENT =&gt; error
       return error(&quot;Unable to find the query log file&quot;, &quot;Could not find the query log at the specified path: #{option(:query_log_path)}.&quot;)
     rescue Exception =&gt; error
       return error(&quot;Error while processing query log:\n#{error.class}: #{error.message}&quot;, error.backtrace.join(&quot;\n&quot;))
     end
     
     #calculate the index rotation stats, only for index rotations that occur completely in the interval
     total_rotations = 0
     total_length_rotations = 0
     finish_time = nil
     begin
       Elif.foreach(search_log_path) do |line|
         line_data = parse_log_line(line)
         if line_data.timestamp.to_f &lt;= last_run.to_f
           break
         else
           if finish_time
             if line_data.step == :start
               total_rotations += 1
               total_length_rotations += finish_time.to_f - line_data.timestamp.to_f
               finish_time = nil
             end
           else
             finish_time = line_data.timestamp if line_data.step == :finish
           end
         end
       end
       
       if total_rotations &gt; 0
         report_data[:index_rebuilds] = total_rotations
         report_data[:average_time_per_rebuild] = sprintf(&quot;%.4f&quot;, total_length_rotations/total_rotations)
       end
     rescue Errno::ENOENT =&gt; error
       return error(&quot;Unable to find the searchd log file&quot;, &quot;Could not find the searchd log at the specified path: #{option(:query_log_path)}.&quot;)
     rescue Exception =&gt; error
       return error(&quot;Error while processing searchd log:\n#{error.class}: #{error.message}&quot;, error.backtrace.join(&quot;\n&quot;))
     end
     # the time
     # should be fixed so that it stores the time of the last log entry from both logs
     remember(:last_request_time, Time.now)
     report(report_data)
  end
private

  QueryData = Struct.new(:timestamp, :time_spent, :results_returned)
  
  LogData = Struct.new(:timestamp, :step)
  
  #based off of http://kobesearch.cpan.org/htdocs/Sphinx-Log-Parser/Sphinx/Log/Parser.pm.html
  def parse_query_line(line)
    time = line.match(/\[(.*?)\]/).captures.first
    time_spent = line.match(/\]\s([\d\.]+).*?\[/).captures.first
    results_returned = line.match(/\s(\d+)\s\(/).captures.first
    QueryData.new(Time.parse(time), time_spent.to_f, results_returned.to_i)
  end
  
  def parse_log_line(line)
    time = line.match(/\[(.*?)\]/).captures.first    
    step = if line.match('rotating finished')
      :finish
    elsif line.match('rotating indices')
      :start
    else
      :intermediate
    end
    LogData.new(Time.parse(time), step)
  end
  
end</code>
    <created-at type="datetime">2010-01-04T01:52:22Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors &quot;Sphinx&quot;:http://www.sphinxsearch.com/, an open-source SQL full-text search engine, reporting the metrics below:

* Queries per-minute
* Average query time 
* Average time per rebuild
* Index rebuilds
* Average results returned

h2. Installing

Just provide the path to the searchd log files. Note that the first run will not return any data.

h2. Example Data

!http://img.skitch.com/20100104-1isag92chgygd9mgxsnkfappw5.png!

h2. Alerts

Two default triggers -- which monitor trends in the _query rate_ and _average query time_ -- are installed with this plugin. These triggers can be adjusted to your system. An example alert:

!http://img.skitch.com/20100104-xbkjq182m4ehctf1wk4tinfmw5.png!

</description>
    <featured type="boolean">false</featured>
    <id type="integer">241</id>
    <metadata type="yaml">--- |-
metadata:
  query_rate:
    precision: 2
    label: Queries
    units: queries/min
  average_query_time:
    precision: 2
    units: sec
  average_time_per_rebuild:
    precision: 2
    units: req/min

triggers:
  - type: trend
    dname: query_rate
    direction: UP
    percentage_change: 300
    duration: 60
    window_reference: LAST_WEEK
    min_value: 3
  - type: trend
    dname: average_query_time
    direction: UP
    percentage_change: 200
    duration: 60
    window_reference: LAST_WEEK
    min_value: 0.01
</metadata>
    <name>Sphinx Monitoring</name>
    <plugins-count type="integer">27</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Monitors Sphinx, an open-source SQL full-text search engine (http://www.sphinxsearch.com/) for the following metrics by looking at the searchd logs:

* Queries per-minute
* Average query time 
* Average time per rebuild
* Index rebuilds
* Average results returned

Note that the first run will not return any data.

----

Created by Sam Sinensky (http://github.com/samsinensky) at Code and Beats (http://codeandbeats.com/) 12/29/09</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors Sphinx, an open-source SQL full-text search engine.</short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-01-04T23:04:15Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/sphinx_monitor/sphinx_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Luc Castera</author>
    <cached-tag-list>nginx</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require 'open-uri'

class NginxReport &lt; Scout::Plugin

  def build_report	
	  url = option(:url) || 'http://127.0.0.1/nginx_status'

  	total, requests, reading, writing, waiting = nil

  	open(url) {|f|
  	  f.each_line do |line|
  		total = $1 if line =~ /^Active connections:\s+(\d+)/
  		if line =~ /^Reading:\s+(\d+).*Writing:\s+(\d+).*Waiting:\s+(\d+)/
  		  reading = $1
  		  writing = $2
  		  waiting = $3
  		end
  		requests = $3 if line =~ /^\s+(\d+)\s+(\d+)\s+(\d+)/  
  	  end
  	}
	
	  report({:total =&gt; total, :reading =&gt; reading, :writing =&gt; writing, :waiting =&gt; waiting, :requests =&gt; requests})
  end
end
</code>
    <created-at type="datetime">2008-08-08T18:39:41Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors &quot;Nginx&quot;:http://wiki.codemongers.com/Main, reporting the total # of requests, the total number of connections, and the number of connections reading, writing, and waiting.

&lt;p&gt;In order to have this plugin running, you need to make sure that your  version of Nginx was compiled with the Stub Status module.&lt;/p&gt;

&lt;p&gt;On Ubuntu Hardy, the Nginx package comes with Stub Status compiled in so if you installed Nginx via apt-get or aptitude, you should have it.&lt;/p&gt;

&lt;p&gt;Make sure you have the following in your Nginx config file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
location /nginx_status {
  stub_status on;
  access_log   off;
  allow 127.0.0.1;
  deny all;
}
&lt;/code&gt;&lt;/pre&gt;
</description>
    <featured type="boolean">false</featured>
    <id type="integer">72</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Nginx monitoring</name>
    <plugins-count type="integer">25</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>* Description

This is a Scout (http://scoutapp.com) plugin that monitors nginx and 
sends the data back to scout.

For more info, visit:
https://scoutapp.com/plugin_urls/static/creating_a_plugin

In order to have this plugin running, you need to make sure that your 
version of Nginx was compiled with the Stub Status module.

On Ubuntu Hardy, the nginx package comes with Stub Status compiled in so 
if you installed Nginx via apt-get or aptitude, you should have it.

Make sure you have the following in your nginx config file:

location /nginx_status {
	stub_status on;
	access_log   off;
	allow 127.0.0.1;
	deny all;
}

---- History ----

Created on July 30, 2008 by Luc Castera</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors Nginx, reporting the total # of requests, the total number of connections, and the number of connections reading, writing, and waiting.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-04T20:49:20Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/nginx_report/nginx_report.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Andre Lewis</author>
    <cached-tag-list>EC2 CloudWatch, EC2, cloud</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class E2Cloudwatch &lt; Scout::Plugin
  TIME_FORMAT='%Y-%m-%dT%H:%M:%S+00:00' unless const_defined?('TIME_FORMAT')

  def build_report
    aws_access_key = option(:aws_access_key)
    aws_secret = option(:aws_secret)
    dimension = option(:dimension)
    namespace = 'AWS/EC2'

    # Available measures for EC2 instances:
    # NetworkIn NetworkOut DiskReadOps DiskWriteOps DiskReadBytes DiskWriteBytes CPUUtilization
    measures=%w(NetworkIn NetworkOut DiskReadOps DiskWriteOps DiskReadBytes DiskWriteBytes CPUUtilization)

    # validate access keys
    if aws_access_key.to_s == '' or aws_secret.to_s == ''
      error(:subject=&gt;'Cloudwatch AWS access not set', :body=&gt;'Ensure your AWS access info is set in plugin options')
      return
    end

    # validate dimension option
    if dimension.to_s == ''
      error(:subject=&gt;'Cloudwatch options not set properly', :body=&gt;'You need a value for InstanceID (dimension)')
      return
    elsif dimension.include? '='
      dimension_name, dimension_value=dimension.split('=',2)
    else
      dimension_name='InstanceId'
      dimension_value=dimension
    end

    aws = CloudWatch::AWSAuthConnection.new(aws_access_key, aws_secret)

    # Figure out a start and end time for the stats query. If we ran previously and remember the last_run_time,
    # then we just query from then to now. We also set the period to the DIFFERENCE so we only get one report during
    # that timeframe. Well, technically we make the period the closest multiple of 60 smaller than the difference,
    # because AWS needs the period to be a multiple of 60.
    #
    # If we can't remember the last_run_time, just use 300 seconds (five minutes)
    #
    # Note: Period must be multiple of 60. AWS will group the response into (end_time - start_time)/period groups.
    # Meaning, response.structure[2] (an array) will have more elements if you make period smaller. We're always
    # making the period the same as the query duration, so we always get only one group back.
    time = Time.now.utc

    if memory(:last_run_time)
      start_time = Time.parse(memory(:last_run_time))
      sample_period = ((time-start_time).to_i / 60)*60 # a multiple of 60. Will be 0 if less than 60
    end

    if memory(:last_run_time).nil? || sample_period &lt;= 0
      sample_period = 300 # in seconds
      start_time = time - sample_period
    end
    remember(:last_run_time, time.to_s)

    # There will be one web service call for each measure
    measures.each do |measure|
      params = {
        :StartTime =&gt; start_time.strftime(TIME_FORMAT),
        :EndTime =&gt; time.strftime(TIME_FORMAT),
        :MeasureName =&gt; measure,
        :Period =&gt; sample_period.to_s,
        :Namespace =&gt; namespace,
        &quot;Statistics.member.1&quot; =&gt; &quot;Average&quot;,
        &quot;Statistics.member.2&quot; =&gt; &quot;Maximum&quot;,
        #&quot;Statistics.member.3&quot; =&gt; &quot;Minimum&quot;,
        #&quot;Statistics.member.4&quot; =&gt; &quot;Sum&quot;,
        &quot;Dimensions.member.1.Name&quot; =&gt; dimension_name,
        &quot;Dimensions.member.1.Value&quot; =&gt; dimension_value
      }

      # logger.debug (&quot;getMetricStatistics with parameters: #{params.inspect}&quot;)
      response = aws.getMetricStatistics(params)
      # logger.debug response.structure      
      # response looks like:
      # [&quot;CPUUtilization&quot;, [{:average=&gt;&quot;1.43&quot;, :timestamp=&gt;&quot;2009-08-16T06:40:00Z&quot;, :unit=&gt;&quot;Percent&quot;, :maximum=&gt;&quot;3.57&quot;, :samples=&gt;&quot;5.0&quot;}]]
      if response.is_error?
        error(:subject=&gt;&quot;AWS getMetricStatistic error&quot;, :body=&gt;response.inspect )
        return
      end
      label, stats = response.structure

      if !stats.is_a?(Array) || stats.empty?
        error(:subject=&gt;&quot;Something went wrong with AWS getMetricStatistics&quot;, :body=&gt;response.inspect )
      end

      report(label+&quot; max&quot;=&gt;stats.first[:maximum], label+&quot; avg&quot;=&gt;stats.first[:average])

    end
  end
end


# =======================================================================
# Below here is EC2 web service library code
# =======================================================================

# -----------------------------------------------------------------------

#
# NOTE: This is based on the Amazon Web Services EC2 Query API Ruby
# Library This library has been packaged as a Ruby Gem by Glenn Rempe
# ( glenn @nospam@ elasticworkbench.com ).
#
# Source code and gem hosted on RubyForge
# under the Ruby License as of 12/14/2006:
# http://amazon-ec2.rubyforge.org

# Original Amazon Web Services Notice
# This software code is made available &quot;AS IS&quot; without warranties of any
# kind.  You may copy, display, modify and redistribute the software
# code either by itself or as incorporated into your code; provided that
# you do not remove any proprietary notices.  Your use of this software
# code is at your own risk and you waive any claim against Amazon Web
# Services LLC or its affiliates with respect to your use of this software
# code. (c) 2006 Amazon Web Services LLC or its affiliates.  All rights
# reserved.

require 'base64'
require 'cgi'
require 'openssl'
require 'digest/sha1'
require 'net/https'
require 'rexml/document'
require 'time'

module CloudWatch

  # Which host FQDN will we connect to for all API calls to AWS?
  DEFAULT_HOST = 'monitoring.amazonaws.com'

  # Define the ports to use for SSL(true) or Non-SSL(false) connections.
  PORTS_BY_SECURITY = { true =&gt; 443, false =&gt; 80 }

  # This is the version of the API as defined by Amazon Web Services
  API_VERSION = '2009-05-15'

  module VERSION #:nodoc:
    MAJOR = 0
    MINOR = 0
    TINY  = 1

    STRING = [MAJOR, MINOR, TINY].join('.')
  end

  # This release version is passed in with each request as part of the
  # HTTP 'User-Agent' header.  Set this be the same value as what is
  # stored in the lib/CloudWatch/version.rb module constant instead.
  # This way we keep it nice and DRY and only have to define the
  # version number in a single place.
  RELEASE_VERSION = CloudWatch::VERSION::STRING

  ###########################################################################
  #
  # Builds the canonical string for signing. This strips out all '&amp;',
  # '?', and '=' from the query string to be signed.
  #
  # NOTE: The parameters in the path passed in must already be sorted in
  #       case-insensitive alphabetical order and must not be url encoded.
  #
  def CloudWatch.canonical_string(path)
    buf = &quot;&quot;
    path.split('&amp;').each { |field|
      buf &lt;&lt; field.gsub(/\&amp;|\?/,&quot;&quot;).sub(/=/,&quot;&quot;)
    }
    return buf
  end

  ###########################################################################
  #
  # Encodes the given string with the aws_secret_access_key, by taking the
  # hmac-sha1 sum, and then base64 encoding it.  Optionally, it will also
  # url encode the result of that to protect the string if it's going to
  # be used as a query string parameter.
  #
  def CloudWatch.encode(aws_secret_access_key, str, urlencode=true)
    digest = OpenSSL::Digest::Digest.new('sha1')
    b64_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest,
                                                    aws_secret_access_key,
                                                    str)).strip
    if urlencode
      return CGI::escape(b64_hmac)
    else
      return b64_hmac
    end
  end

  ###########################################################################
  ###########################################################################
  #
  class Response
    attr_reader :http_response
    attr_reader :http_xml
    attr_reader :structure

    ERROR_XPATH = &quot;ErrorResponse/Error&quot;

    ######################################################################
    #
    def initialize(http_response)
      @http_response = http_response
      @http_xml = http_response.body
      @is_error = false
      if http_response.is_a? Net::HTTPSuccess
        @structure = parse
      else
        @is_error = true
        @structure = parse_error
      end
    end

    ######################################################################
    #
    def is_error?
      @is_error
    end

    ######################################################################
    #
    def parse_error
      doc = REXML::Document.new(@http_xml)
      element = REXML::XPath.first(doc, ERROR_XPATH)

      errorCode = REXML::XPath.first(element, &quot;Code&quot;).text
      errorMessage = REXML::XPath.first(element, &quot;Message&quot;).text

      [[&quot;#{errorCode}: #{errorMessage}&quot;]]
    end

    ######################################################################
    #
    def parse
      # Placeholder -- this method should be overridden in child classes.
      nil
    end

    ######################################################################
    #
    def to_s
      res = &quot;&quot;
      @structure.each do |line|
        line.each do |k,v|
          res &lt;&lt; &quot;#{k}: #{v}\t&quot;
        end
        res &lt;&lt; &quot;\n&quot;
      end
      return res
    end
  end

  ######################################################################
  ######################################################################
  #
  class GetMetricStatisticsResponse &lt; Response
    ELEMENT_XPATH = &quot;GetMetricStatisticsResponse/GetMetricStatisticsResult/Datapoints/member&quot;
    LABEL_XPATH = &quot;GetMetricStatisticsResponse/GetMetricStatisticsResult/Label&quot;

    ######################################################################
    #
    def parse
      doc = REXML::Document.new(@http_xml)
      label = REXML::XPath.first(doc, LABEL_XPATH).text
      lines = []

      doc.elements.each(ELEMENT_XPATH) do |datapoint|
        data = { }
        datapoint.each do |element|
          next if element.class == REXML::Text
          data[element.name.downcase.to_sym] = element.text
        end
        lines &lt;&lt; data
      end
      return [label, lines]
    end
  end

  ######################################################################
  ######################################################################
  #
  class ListMetricsResponse &lt; Response
    ELEMENT_XPATH = &quot;ListMetricsResponse/ListMetricsResult/Metrics/member&quot;

    ######################################################################
    #
    def parse
      doc = REXML::Document.new(@http_xml)
      lines = []

      doc.elements.each(ELEMENT_XPATH) do |element|
        measure_name = REXML::XPath.first(element, 'MeasureName').text
        namespace = REXML::XPath.first(element, 'Namespace').text

        ds = []
        REXML::XPath.each(element, &quot;Dimensions/member&quot;) do |member|
            dim_name = REXML::XPath.first(member, 'Name').text
            dim_value = REXML::XPath.first(member, 'Value').text
            ds &lt;&lt; [dim_name, dim_value]
        end

        lines &lt;&lt; { :measure_name =&gt; measure_name,
          :namespace =&gt; namespace,
          :dimensions =&gt; ds,
        }
      end
      return lines
    end
  end

  ###########################################################################
  ###########################################################################
  #
  # The library exposes one main interface class, 'AWSAuthConnection'.
  # This class performs all the operations for using the CloudWatch service
  # including header signing.  This class uses Net::HTTP to interface
  # with CloudWatch Query API interface.
  class AWSAuthConnection

    # Allow viewing, or turning on and off, the verbose mode of the
    # connection class.  If 'true' some 'puts' are done to view variable
    # contents.
    #
    attr_accessor :verbose

    ########################################################################
    #
    def initialize(aws_access_key_id, aws_secret_access_key, is_secure=true,
                   server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure])

      @aws_access_key_id = aws_access_key_id
      @aws_secret_access_key = aws_secret_access_key
      @http = Net::HTTP.new(server, port)
      @http.use_ssl = is_secure
      # Don't verify the SSL certificates.  Avoids SSL Cert warning on every
      # GET.
      #
      @http.verify_mode = OpenSSL::SSL::VERIFY_NONE

      @verbose = false
    end

    ########################################################################
    #
    def getMetricStatistics(kwargs)

      # Stringify the input argument keys.
      #
      args = { }
      kwargs.each do |k,v|
        args[k.to_s] = v
      end

      GetMetricStatisticsResponse.new(make_request(&quot;GetMetricStatistics&quot;, args))
    end

    ########################################################################
    #
    def listMetrics()
      ListMetricsResponse.new(make_request(&quot;ListMetrics&quot;, { }))
    end

    private

    ########################################################################
    #
    # pathlist is a utility method which takes a key string and and array
    # as input.  It converts the array into a Hash with the hash key being
    # 'Key.n' where 'n' increments by 1 for each iteration.  So if you pass
    # in args (&quot;ImageId&quot;, [&quot;123&quot;, &quot;456&quot;]) you should get
    # {&quot;ImageId.1&quot;=&gt;&quot;123&quot;, &quot;ImageId.2&quot;=&gt;&quot;456&quot;} returned.
    def pathlist(key, arr)
      params = {}
      arr.each_with_index do |value, i|
        params[&quot;#{key}.#{i+1}&quot;] = value
      end
      params
    end

    ########################################################################
    #
    # Make the connection to AWS CloudWatch passing in our request.  This is
    # generally called from within a 'Response' class object or one of its
    # sub-classes so the response is interpreted in its proper context.  See
    # lib/CloudWatch/responses.rb
    #
    def make_request(action, params, data='')

      @http.start do

        params.merge!({ &quot;Action&quot;=&gt;action,
                        &quot;SignatureVersion&quot;=&gt;&quot;1&quot;,
                        &quot;AWSAccessKeyId&quot;=&gt;@aws_access_key_id,
                        &quot;Version&quot;=&gt;API_VERSION,
                        &quot;Timestamp&quot;=&gt;Time.now.getutc.iso8601})
        p(params) if @verbose

        sigpath = &quot;?&quot; + params.sort_by { |param| param[0].downcase }.collect { |param| param.join(&quot;=&quot;) }.join(&quot;&amp;&quot;)

        sig = get_aws_auth_param(sigpath, @aws_secret_access_key)

        path = &quot;?&quot; + params.sort.collect do |param|
          CGI::escape(param[0]) + &quot;=&quot; + CGI::escape(param[1])
        end.join(&quot;&amp;&quot;) + &quot;&amp;Signature=&quot; + sig

        puts path if @verbose

        req = Net::HTTP::Get.new(&quot;/#{path}&quot;)

        # Ruby will automatically add a random content-type on some verbs, so
        # here we add a dummy one to 'supress' it.  Change this logic if
        # having an empty content-type header becomes semantically meaningful
        # for any other verb.
        #
        req['Content-Type'] ||= ''
        req['User-Agent'] = &quot;ruby-cloudwatch-query-api v-#{RELEASE_VERSION}&quot;

        data = nil unless req.request_body_permitted?
        @http.request(req, data)

      end
    end

    ########################################################################
    #
    # Set the Authorization header using AWS signed header authentication
    def get_aws_auth_param(path, aws_secret_access_key)
      canonical_string =  CloudWatch.canonical_string(path)
      encoded_canonical = CloudWatch.encode(aws_secret_access_key, canonical_string)
    end
  end
end
</code>
    <created-at type="datetime">2009-08-18T00:17:34Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Graph CloudWatch metrics, create alerts on CloudWatch, track trends  on CloudWatch, etc. Your CloudWatch data will appear alongside all the other data collected by the Scout agent.

This plugin captures NetworkIn, NetworkOut, DiskReadOps, DiskWriteOps, DiskReadBytes, DiskWriteBytes, and CPUUtilization from EC2 CloudWatch. 

Get metrics from a single instance, an autoscaling group, an instance type, or all instances created from a given image (AMI).</description>
    <featured type="boolean">false</featured>
    <id type="integer">171</id>
    <metadata type="yaml">--- |-
options:
  aws_access_key:
    name: AWS Access Key
    notes: Your Amazon Web Services Access key. 20-char alphanumeric, looks like 022QF06E7MXBSH9DHM02
  aws_secret:
    name: AWS Secret
    notes: Your Amazon Web Services Secret key. 40-char alphanumeric, looks like kWcrlUX5JEDGMLtmEENIaVmYvHNif5zBd9ct81S
  dimension:
    name: EC2 InstanceId or dimension
    notes: Get your InstanceId from the AWS web console or command line tools. It looks like i-48ac4920. OR, specify any dimension as key=value. For example, AutoScalingGroupName=YOUR_GROUP_NAME. See README.


metadata:
  CPUUtilization max:
    label: CPU Utilization (max)
    units: %
    precision: 2
  CPUUtilization avg:
    label: CPU Utilization (avg)
    units: %
    precision: 2
  NetworkIn max:
    label: Network In (max)
    units: bytes
    precision: 0
  NetworkIn avg:
    label: Network In (avg)
    units: bytes
    precision: 0
  NetworkOut max:
    label: Network Out (max)
    units: bytes
    precision: 0
  NetworkOut avg:
    label: Network Out (avg)
    units: bytes
    precision: 0
  DiskReadBytes max:
    label: Disk Reads (max)
    units: bytes
    precision: 0
  DiskReadBytes avg:
    label: Disk Reads (avg)
    units: bytes
    precision: 0
  DiskWriteBytes max:
    label: Disk Writes (max)
    units: bytes
    precision: 0
  DiskWriteBytes avg:
    label: Disk Writes (avg)
    units: bytes
    precision: 0
  DiskWriteOps avg:
    label: Disk Write Ops (avg)
    units:
    precision: 0
  DiskWriteOps max:
    label: Disk Write Ops (max)
    units: 
    precision: 0
  DiskReadOps avg:
    label: Disk Read Ops (avg)
    units:
    precision: 0
  DiskReadOps max:
    label: Disk Read Ops (max)
    units:
    precision: 0
</metadata>
    <name>EC2 CloudWatch</name>
    <plugins-count type="integer">19</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>EC2 CloudWatch plugin
=====================
Created by Andre Lewis

This plugin uses AWS web service calls to fetch the following CloudWatch metrics for your EC2 instances:

  NetworkIn NetworkOut DiskReadOps DiskWriteOps DiskReadBytes DiskWriteBytes CPUUtilization

Using this plugin, you can graph CloudWatch data, create alerts on CloudWatch, track trends  on CloudWatch, etc.
Your Cloudwatch data will appear alongside all the other data collected by the Scout agent.

Note, this plugin does not fetch EC2 Load Balancer Metrics. This plugin is in beta, and we appreciate you feedback
at support@scoutapp.com.


Fetching metrics for one instance
----------------------------------

By default, the value you put in the &quot;EC2 InstanceId or dimension&quot; plugin option is treated as an EC2 InstanceId.
EC2 InstanceIds currently look like this: i-48ac4920. Providing an InstanceID will fetch metrics for that instance alone.

Providing the InstanceID is the easiest way to get started. You can get your InstanceID from the AWS web console
(https://console.aws.amazon.com/ec2/home), or through the command line tools



Autoscaling groups, etc
----------------------------------

Alterntively, you can fetch metrics by autoscaling group name, image id, or instance type. You will still get one set
of numbers, but the numbers will be averaged from all the instances in the dimension you specifiy.

To fetch Cloudwatch data across a different dimension, enter a key=value string in the &quot;EC2 InstanceId or dimension&quot;.
You can use:
  
  AutoScalingGroupName=YOUR_AUTOSCALING_GROUP_NAME
  ImageId=YOUR_IMAGE_ID
  InstanceType=YOUR_INSTANCE_TYPE
  InstanceId=YOUR_IMAGE_ID (this is the same as providing the ImageId alone)

</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Get graphs, alerts, and trends on your CloudWatch data. Captures NetworkIn, NetworkOut, DiskReadOps, DiskWriteOps, DiskReadBytes, DiskWriteBytes, and CPUUtilization on a single instance or an autoscaling group. </short-description>
    <tested-platforms>Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T05:17:10Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/ec2_cloudwatch/ec2_cloudwatch.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>process, monitoring, restart</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># TODO: use alternate process open to catch STDOUT, STDERR for those 
# processes that use
class KeepProcessRunning &lt; Scout::Plugin

  def run
    report = {:report =&gt; {}, :alerts =&gt; [], :memory =&gt; {}}
    process_to_monitor = @options[&quot;process_name&quot;] || &quot;&quot;
    report[:report][process_to_monitor] = 0
    restart_action     = @options[&quot;restart_action&quot;] || process_to_monitor
    
    # Search all running processes for the process (do not match the grep 
    # process nor the locally running scout client).
    ps_output = `ps auxww | grep &quot;#{process_to_monitor}&quot; | grep -v &quot;grep&quot; | grep -v &quot;scout&quot;`
    unless process_match = ps_output.to_a.first  # process not found
      # attempt to restart the process
      restart_output = `#{restart_action}`
      report[:alerts] &lt;&lt; {:subject =&gt; &quot;#{process_to_monitor} is not running. Restart reported: #{restart_output}&quot;}
    else # process is running
      # if we wanted to parse fields we could:
      # fields = process_match.downcase.split
      report[:report][process_to_monitor] = 1
    end    
    return report  
  rescue Exception
    { :error =&gt; { :subject =&gt; &quot;Could not keep the process running.&quot;,
                  :body    =&gt; &quot;An exception was thrown:  #{$!.message}&quot; } }
  end
end
</code>
    <created-at type="datetime">2008-04-23T16:18:46Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>&lt;p&gt;This plugin simply monitors the active running processes to see if a specific process is running.&lt;/p&gt;
&lt;p&gt;If it is not running, the restart action is taken.  If a restart action is not specified, or left blank, it simply will attempt to re-run the process (as the current running user).  
&lt;/p&gt;

&lt;p&gt;This allows you to specify a startup script or other process to allow startup as a different user.
&lt;/p&gt;

&lt;p&gt;Takes in a Process to Monitor: the full path to a process to monitor, for example:
&lt;/p&gt;
&lt;code&gt;
ruby script/runner script/ferret_start
&lt;/code&gt;
&lt;p&gt;
Also takes in a Restart Action: the optional command to run (if no restart action given, the process itself is used) to restart the process if it is not running, for example:
&lt;/p&gt;
&lt;code&gt;
cd /path/to/rails/app &amp;&amp; /usr/bin/ruby /path/to/rails/appscript/runner /path/to/rails_app/script/ferret_start
&lt;/code&gt;

</description>
    <featured type="boolean">false</featured>
    <id type="integer">20</id>
    <metadata type="yaml">--- |
options:
  process_name:
    name: Process Name
    notes: The full name of the process to keep running.
  restart_action:
    name: Restart Action
    notes: The full command to restart the process, if not running. If left blank, the Process Name will be used.

</metadata>
    <name>Keep Process Running</name>
    <plugins-count type="integer">16</plugins-count>
    <rating-avg type="decimal">4.0</rating-avg>
    <rating-count type="integer">1</rating-count>
    <rating-total type="integer">4</rating-total>
    <readme>Keep Process Running
======================
Created by 
 * [Highgroove Studios LLC](http://www.highgroove.com)

Dependencies
------------

No dependencies.
	
Options
-------

Process to Monitor: takes in the full path to a process to monitor, i.e.:

  ruby script/runner script/ferret_start
  
Restart Action: the optional command to run (if no restart action given, the process itself is used) to restart the process if it is not running, i.e.:

  cd /path/to/rails/app &amp;&amp; /usr/bin/ruby /path/to/rails/appscript/runner /path/to/rails_app/script/ferret_start

Compatibility 
-------------

Works on Linux and OSX.


</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>This plugin simply monitors the active running processes to see if a specific process is running.
</short-description>
    <tested-platforms>OSX, Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:18Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/keep_process_running/keep_process_running.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mark Hasse</author>
    <cached-tag-list>disk</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># =================================================================================
# mdstat
# 
# Created by Mark Hasse on 2008-04-15.
# =================================================================================

=begin
Personalities : [raid1] 
md1 : active raid1 sda1[0] sdc1[2](S) sdb1[1]
      244195904 blocks [2/2] [UU]
      
unused devices: &lt;none&gt;
=end

class MdStat &lt; Scout::Plugin
  def build_report
    data          = Hash.new 
    data = Hash.new
         
    mdstat = IO.readlines('/proc/mdstat')
    
    spares = mdstat[1].scan(/\(S\)/).size
    failed = mdstat[1].scan(/\(F\)/).size

    mdstat[2] =~ /\[(\d*\/\d*)\].*\[(.+)\]/
    counts = $1
    status = $2
    
    disk_counts = counts.split('/').map { |x| x.to_i } 
    disk_status = status.squeeze
    
    if disk_counts[0].class == Fixnum &amp;&amp; disk_counts[1].class == Fixnum
      data[:active_disks] = disk_counts[0]
      data[:spares]       = spares
      data[:failed_disks] = failed
    else
      raise &quot;Unexpected mdstat file format&quot;
    end 
    
    if disk_counts[0] != disk_counts[1] || disk_status != 'U' || failed &gt; 0 
      if memory(:mdstat_ok)
        remember(:mdstat_ok,false)
        alert(:subject =&gt; 'Disk failure detected')
      end
    else
      remember(:mdstat_ok,true)
    end

    report(data)
  rescue
    error(:subject =&gt; &quot;Couldn't parse /proc/mdstat as expected.&quot;, :body =&gt; $!.message)
  end
end</code>
    <created-at type="datetime">2008-04-22T14:00:07Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors /proc/mdstat for disk failures.  Tested on a Debian Linux host running kernel 2.6.18-6-amd64 SMP with mdadm v2.5.6.  

The host has two drives configured in a RAID1 configuration. 

Obviously, I don't have a sufficient testbed, please let me know if you find errors with your configuration.  I can be reached at mark -at- bluezucchini -dot- com.</description>
    <featured type="boolean">false</featured>
    <id type="integer">17</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Monitor /proc/mdstat</name>
    <plugins-count type="integer">13</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors /proc/mdstat for disk failures.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:17Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/3261402f00904fa835285388100b68832ad6cd20/mdstat/mdstat.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mike Mangino</author>
    <cached-tag-list>starling</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class MissingLibrary &lt; StandardError; end
class StarlingMonitor &lt; Scout::Plugin

  
  attr_accessor :connection
  
  
  def setup_starling
    begin
      require 'starling'
    rescue LoadError
      begin
        require &quot;rubygems&quot;
        require 'starling'
      rescue LoadError
        raise MissingLibrary
      end
    end
    self.connection=Starling.new(&quot;#{option(:host)}:#{option(:port)}&quot;)
    @report = {}
  end
  
    
  
  def build_report
    begin
      setup_starling
      connection.sizeof(:all).each do |queue_name,item_count|
        check_queue(queue_name,item_count) if should_check_queue?(queue_name)
      end
      report(@report)
    rescue  MissingLibrary=&gt;e
      error(&quot;Could not load all required libraries&quot;,
            &quot;I failed to load the starling library. Please make sure it is installed.&quot;)
    rescue Exception=&gt;e
      error(&quot;Got unexpected error: #{e} #{e.class}&quot;)
    end
  end

  def should_check_queue?(name)
    option(:queue_re).nil? or /#{option(:queue_re)}/ =~ name
  end
  
  def check_queue(name,depth)
    q_depth = (depth||0).to_i
    @report ||= {}
    @report[name] = q_depth
    if q_depth &gt; option(:max_depth).to_i
      alert(&quot;Max Queue Depth for #{name} exceeded&quot;,&quot;#{q_depth} items is more than the max allowed #{option(:max_depth)}&quot;)
    end
  end

end</code>
    <created-at type="datetime">2008-08-08T16:42:03Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors the number of items in a starling queue, generating an alert if the maximum queue depth is exceeded for a given queue. </description>
    <featured type="boolean">false</featured>
    <id type="integer">52</id>
    <metadata type="yaml">--- |
options:
  host:
    name: Host
    notes: The host to monitor
    default: 127.0.0.1
  port:
    name: Port
    notes: The port starling is running on
    default: 61613
  queue_re:
    name: Name Reqular Expresssion
    notes: Pattern to test against queue names to select queues to monitor 
    default: 
  max_depth: 
    name: Maximum Items
    notes: Alert if the queue contains more items than this
    default: 4000
  

</metadata>
    <name>Starling Monitor</name>
    <plugins-count type="integer">10</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Monitor the number of items in a starling queue</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors the number of items in a starling queue, generating an alert if the maximum queue depth is exceeded for a given queue. </short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:25Z</updated-at>
    <url>http://github.com/itsderek23/er-scout-plugins/raw/57d26e85056c6f22e6b72d37b18f799203011a36/starling_monitor/starling_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mark Hasse</author>
    <cached-tag-list>logins</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Moved Temporarily&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY BGCOLOR=&quot;#FFFFFF&quot; TEXT=&quot;#000000&quot;&gt;
&lt;H1&gt;Moved Temporarily&lt;/H1&gt;
The document has moved &lt;A HREF=&quot;http://sites.google.com/a/bluezucchini.com/www/active_logins.rb&quot;&gt;here&lt;/A&gt;.
&lt;/BODY&gt;
&lt;/HTML&gt;
</code>
    <created-at type="datetime">2008-04-22T01:26:34Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Track the number of people logged into your server (via console, ssh, telnet, etc.) at a particular time.</description>
    <featured type="boolean">false</featured>
    <id type="integer">16</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Active Logins</name>
    <plugins-count type="integer">9</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Track the number of people logged into your server (via console, ssh, telnet, etc.) at a particular time.</short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:16Z</updated-at>
    <url>http://www.bluezucchini.com/active_logins.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Tim Morgan</author>
    <cached-tag-list>ruby on rails, sessions</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class RailsSessionMonitor &lt; Scout::Plugin
  TEST_USAGE = &quot;#{File.basename($0)} days_for_old_sessions DAYS_FOR_OLD_SESSIONS path_to_app PATH_TO_APP rails_env RAILS_ENV&quot;

  def run
    ENV['RAILS_ENV'] = @options['rails_env']
    # Ensure require options are provided
    if @options['rails_env'].nil?
      return { :error =&gt; {:subject =&gt; &quot;Required option not provided&quot;,
                          :body    =&gt; &quot;Please specify the Rails environment (ie: production, development, test).&quot;}}
    elsif @options['path_to_app'].nil?
      return { :error =&gt; {:subject =&gt; &quot;Required option not provided&quot;,
                          :body    =&gt; &quot;The full path to your Rails application is required (ex: /var/www/apps/APP_NAME/current).&quot;}}
    elsif @options['days_for_old_sessions'].nil?
      return { :error =&gt; {:subject =&gt; &quot;Required option not provided&quot;,
                          :body    =&gt; &quot;The Days for Old Sessions option must be provided. Sessions older than this amount will be deleted.&quot;}}
    end
    # Load the Rails Env
    require &quot;#{@options['path_to_app']}/config/environment&quot;
    
    total = CGI::Session::ActiveRecordStore::Session.count
    old = CGI::Session::ActiveRecordStore::Session.count(:conditions =&gt; [&quot;updated_at &lt; ?&quot;, @options['days_for_old_sessions'].to_i.days.ago ])
    
    {
      :report =&gt; {
        :total =&gt; total,
        :old =&gt; old
      }
    }
  rescue
    { :error =&gt; {:subject =&gt; &quot;Unable to Monitor Rails Sessions&quot;, 
      :body =&gt; &quot;The following exception was raised:\n\n#{$!.message}\n\n#{$!.backtrace}&quot;}}
  end
end</code>
    <created-at type="datetime">2008-04-07T17:10:49Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Checks for old Ruby on Rails sessions in your database, reporting the number of total sessions and old sessions. 

You define the number of days that constitutes an &quot;old session&quot; (default is 30 days). </description>
    <featured type="boolean">false</featured>
    <id type="integer">14</id>
    <metadata type="yaml">--- |
options:
  days_for_old_sessions:
    name: Days for Old Sessions
    notes: Sessions older than this amount (in days) will be deleted.
    default: 30
  path_to_app:
    name: Full Path to Rails Application
    notes: The full path to the Rails application you wish to monitor sessions for. Omit the trailing slash.
    default: /var/www/apps/APP_NAME/current
  rails_env:
    name: Rails Environment
    notes: 'The Rails environment to run the plugin under (ie: production, development, test).'
    default: production

</metadata>
    <name>Rails Session Monitoring</name>
    <plugins-count type="integer">8</plugins-count>
    <rating-avg type="decimal">5.0</rating-avg>
    <rating-count type="integer">1</rating-count>
    <rating-total type="integer">5</rating-total>
    <readme>Rails Session Monitoring Plugin
=====================
Created by [Highgroove Studios LLC](http://www.highgroove.com)

Compatibility 
-------------
Works fully on Linux and OSX. 

Functionality
-------------
Given a path to a Rails application, this plugin returns the total number of sessions and the number of sessions 
that haven't been updated a specified number of days. 

This requires database-based sessions storage.</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Checks for old Ruby on Rails sessions in your database, reporting the number of total sessions and old sessions. </short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:15Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/rails_session_monitor/rails_session_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mike Mangino</author>
    <cached-tag-list>mysql</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require 'time'
require 'date'
class MissingLibrary &lt; StandardError; end
class MysqlReplicationMonitor &lt; Scout::Plugin

  
  attr_accessor :connection
  
  
  def setup_mysql
    begin
      require 'mysql'
    rescue LoadError
      begin
        require &quot;rubygems&quot;
        require 'mysql'
      rescue LoadError
        raise MissingLibrary
      end
    end
    self.connection=Mysql.new(option(:host),option(:username),option(:password))
  end
  
  def build_report
    begin
      setup_mysql
      h=connection.query(&quot;show slave status&quot;).fetch_hash
      if h.nil? 
        error(&quot;Replication not configured&quot;) 
      elsif h[&quot;Slave_IO_Running&quot;] == &quot;Yes&quot; and h[&quot;Slave_SQL_Running&quot;] == &quot;Yes&quot;
        report(&quot;Seconds Behind Master&quot;=&gt;h[&quot;Seconds_Behind_Master&quot;])
      else
        alert(&quot;Replication not running&quot;,
          &quot;IO Slave: #{h[&quot;Slave_IO_Running&quot;]}\nSQL Slave: #{h[&quot;Slave_SQL_Running&quot;]}&quot;) unless in_ignore_window?
      end
    rescue  MissingLibrary=&gt;e
      error(&quot;Could not load all required libraries&quot;,
            &quot;I failed to load the mysql library. Please make sure it is installed.&quot;)
    rescue Mysql::Error=&gt;e
      error(&quot;Unable to connect to mysql: #{e}&quot;)
    rescue Exception=&gt;e
      error(&quot;Got unexpected error: #{e} #{e.class}&quot;)
    end
  end

  def in_ignore_window?
    if s=option(:ignore_window_start) &amp;&amp; e=option(:ignore_window_end)
      start_time = Time.parse(&quot;#{Date.today} #{s}&quot;)
      end_time = Time.parse(&quot;#{Date.today} #{e}&quot;)
      
      if start_time&lt;end_time
        return(Time.now &gt; start_time and Time.now &lt; end_time)
      else
        return(Time.now &gt; start_time or Time.now &lt; end_time)
      end
    else
      false  
    end
  end

end</code>
    <created-at type="datetime">2008-08-08T16:36:26Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>&lt;p&gt;Monitors the replication for a master-slave MySQL database setup reporting the number of seconds the slave is behind the master. &lt;/p&gt;

&lt;p&gt;If replication is not running an alert is generated. An ignore window can also be provided.&lt;/p&gt;</description>
    <featured type="boolean">false</featured>
    <id type="integer">32</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>MySQL Replication Monitor</name>
    <plugins-count type="integer">7</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors the replication for a master-slave MySQL database setup reporting the number of seconds the slave is behind the master. </short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:22Z</updated-at>
    <url>http://github.com/mmangino/er-scout-plugins/blob/master/mysql_replication_monitor/mysql_replication_monitor.rb?raw=true</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mike Mangino</author>
    <cached-tag-list>memcached</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
  &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html;charset=UTF-8&quot; /&gt;
    &lt;title&gt;GitHub - File Not Found&lt;/title&gt;
    &lt;link href=&quot;http://github.com/stylesheets/bundle_common.css&quot; media=&quot;screen&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
    &lt;link href=&quot;http://github.com/stylesheets/bundle_github.css&quot; media=&quot;screen&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;main&quot;&gt;
      &lt;div id=&quot;header&quot; class=&quot;basic&quot;&gt;

        &lt;div class=&quot;site&quot;&gt;
          &lt;div class=&quot;logo&quot;&gt;
            &lt;a href=&quot;/&quot;&gt;&lt;img src=&quot;/images/modules/header/logov3.png&quot; alt=&quot;git-hub&quot; /&gt;&lt;/a&gt;
          &lt;/div&gt;
          &lt;div class=&quot;actions&quot;&gt;
            &lt;a href=&quot;/&quot;&gt;home&lt;/a&gt;
            &lt;a href=&quot;/login&quot;&gt;login&lt;/a&gt;
            &lt;a href=&quot;/signup&quot;&gt;signup!&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class=&quot;site&quot;&gt;
        &lt;div id=&quot;error&quot; class=&quot;status404&quot;&gt;
          &lt;img src=&quot;/images/error/octocat_happy.gif&quot; alt=&quot;Octocat is sad&quot; /&gt;
          &lt;h1&gt;That page doesn't exist!&lt;/h1&gt;

          &lt;div class=&quot;status500&quot;&gt;
            &lt;style type=&quot;text/css&quot;&gt;
              #goog-wm { }
              #goog-wm h3.closest-match { }
              #goog-wm h3.closest-match a { }
              #goog-wm h3.other-things { }
              #goog-wm ul { }
              #goog-wm ul li { margin:5px 0; list-style-type:disc; }
              #goog-wm li.search-goog { }
            &lt;/style&gt;
            &lt;script type=&quot;text/javascript&quot;&gt;
              var GOOG_FIXURL_LANG = 'en';
              var GOOG_FIXURL_SITE = 'http://github.com/';
            &lt;/script&gt;
            &lt;script type=&quot;text/javascript&quot; src=&quot;http://linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js&quot;&gt;&lt;/script&gt;
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class=&quot;push&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;

    &lt;div id=&quot;footer&quot;&gt;
      &lt;div class=&quot;site&quot;&gt;

        &lt;div class=&quot;info&quot;&gt;
          &lt;div class=&quot;links&quot;&gt;
            &lt;a href=&quot;http://github.com/blog/148-github-shirts-now-available&quot;&gt;T-Shirts&lt;/a&gt; |
            &lt;a href=&quot;http://github.com/blog&quot;&gt;Blog&lt;/a&gt; |
            &lt;a href=&quot;http://support.github.com/&quot;&gt;Support&lt;/a&gt; |
            &lt;a href=&quot;http://github.com/training&quot;&gt;Git Training&lt;/a&gt; |
            &lt;a href=&quot;http://github.com/contact&quot;&gt;Contact&lt;/a&gt; |
            &lt;a href=&quot;http://groups.google.com/group/github/&quot;&gt;Google Group&lt;/a&gt; |
            &lt;a href=&quot;http://status.github.com&quot;&gt;Status&lt;/a&gt;
          &lt;/div&gt;
          &lt;div class=&quot;company&quot;&gt;
            &amp;copy;
            2010
            GitHub Inc.
            All rights reserved.
            | &lt;a href=&quot;http://github.com/site/terms&quot;&gt;Terms of Service&lt;/a&gt; | &lt;a href=&quot;http://github.com/site/privacy&quot;&gt;Privacy Policy&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sponsor&quot;&gt;
          &lt;div&gt;
            Powered by the &lt;a href=&quot;http://www.rackspace.com &quot;&gt;Dedicated
            Servers&lt;/a&gt; and&lt;br/&gt; &lt;a href=&quot;http://www.rackspacecloud.com&quot;&gt;Cloud
            Computing&lt;/a&gt; of Rackspace Hosting&lt;span&gt;&amp;reg;&lt;/span&gt;
          &lt;/div&gt;
          &lt;a href=&quot;http://www.rackspace.com&quot;&gt;
            &lt;img src=&quot;/images/modules/footer/rackspace_logo.png&quot; alt=&quot;Dedicated Server&quot; /&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;script type=&quot;text/javascript&quot;&gt;
    var gaJsHost = ((&quot;https:&quot; == document.location.protocol) ? &quot;https://ssl.&quot; : &quot;http://www.&quot;);
    document.write(unescape(&quot;%3Cscript src='&quot; + gaJsHost + &quot;google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E&quot;));
    &lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
    var pageTracker = _gat._getTracker(&quot;UA-3769691-2&quot;);
    pageTracker._initData();
    pageTracker._trackPageview();
    &lt;/script&gt;

  &lt;/body&gt;
&lt;/html&gt;
</code>
    <created-at type="datetime">2008-08-08T16:39:15Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitor the response of a memcached server. Sets a value and gets it back, generating an alert if the response time exceeds a given threshold.</description>
    <featured type="boolean">false</featured>
    <id type="integer">42</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Memcached Monitor</name>
    <plugins-count type="integer">7</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Monitor the response of a memcached server. Sets a value and gets it back, generating an alert if the response time exceeds a given threshold.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-05-03T13:50:31Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/memcached_monitor/memcached_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Jason Lee</author>
    <cached-tag-list>phusion, passenger</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class PassengerStatus &lt; Scout::Plugin
  def build_report
    cmd  = option(:passenger_status_command) || &quot;passenger-status&quot;
    data = `#{cmd} 2&gt;&amp;1`
    if $?.success?
      stats = parse_data(data)
      report(stats)
    else
      error &quot;Could not get data from command&quot;, &quot;Error:  #{data}&quot;
    end
  end

  private

  def parse_data(data)
    stats = {}
    
    data.each_line do |line|
      #line = line.gsub(/\e\[\d+m/,'')
      if line =~ /^max\s+=\s(\d+)/
        stats[&quot;max&quot;] = $1
      elsif line =~ /^count\s+=\s(\d+)/
        stats[&quot;current&quot;] = $1
      elsif line =~ /^active\s+=\s(\d+)/
        stats[&quot;active&quot;] = $1
      elsif line =~ /^inactive\s+=\s(\d+)/
        stats[&quot;inactive&quot;] = $1
      elsif line =~ /^Waiting on global queue: (\d+)/
        stats[&quot;gq_wait&quot;] = $1

      end
    end

    stats
  end

end
</code>
    <created-at type="datetime">2009-06-12T21:43:50Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Provides metrics on Passengers internal state, including the number of application instances that are currently alive, the number of instances that are currently processing requests, and the number of idle instances. See &quot;the passenger manual&quot;:http://www.modrails.com/documentation/Users%20guide.html#_inspecting_phusion_passenger_8217_s_internal_status for details on the values provided by the passenger-status command line.

&lt;p&gt;
*Note that you need to edit the sudoers file on your server to allow the Scout agent to run @passenger-status@ without a password*. You will need to address this access issue on your server. &quot;Learn how here&quot;:https://scoutapp.com/plugin_urls/141-passenger-status/help_entries/171.
 &lt;/p&gt;</description>
    <featured type="boolean">false</featured>
    <id type="integer">141</id>
    <metadata type="yaml">--- |-
options:
  passenger_status_command:
    name: The Passenger Status Command
    notes: The full path to the passenger-status command (possibly with sudo).
    default: sudo /usr/bin/passenger-status

schema:
  - current
  - max
  - active
  - inactive
  - gq_wait

metadata:
  current: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Current Passengers
  max: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Max Passengers
  active: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Active Passengers
  inactive: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Inactive Passengers    
  gq_wait: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Req. waiting on global queue
</metadata>
    <name>Passenger Status</name>
    <plugins-count type="integer">7</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Passenger Status
======================

Based on passenger_memory_stats

Compatibility 
-------------

Works on Linux and Solaris.

Sudo Usage
----------

The passenger-status program recommends that you run it would super user privileges to gain more information.  This plugin is usable without the extra access rights, but you will need to add them if you want the full details.

It's important to note though that it is not safe for you to transmit your super user password to us.  You will need to address this access issue on your server.

Our recommended procedure to handle this is:

1. Edit the sudoers file on your server to allow the user that runs the scout client listed in your crontab to be able to run passenger-status without a password. e.g.  
     daemon  ALL=NOPASSWD: /usr/bin/passenger-status
2. Login into Scout and edit your plugin settings to add sudo in front of the command name. e.g
     sudo /usr/bin/passenger-status
</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Provides metrics on Passengers internal state, including the number of application instances that are currently alive, the number of instances that are currently processing requests, and the number of idle instances. </short-description>
    <tested-platforms>Ubunto 8.04</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T02:10:49Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/passenger_status/passenger_status.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Doug Barth</author>
    <cached-tag-list>RabbitMQ</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># Created by Doug Barth. 
# http://github.com/dougbarth/
class RabbitmqOverall &lt; Scout::Plugin
  OPTIONS = &lt;&lt;-EOS
  rabbitmqctl:
    name: rabbitmqctl command
    notes: The command used to run the rabbitctl program, minus arguments
    default: rabbitmqctl
  queue:
    name: Queue
    notes: The name of the queue to collect detailed metrics for
  vhost:
    name: Virtual host
    notes: The name of the virtual host to collect detailed metrics for
    default: /
  EOS

  QUEUE_INFO_ITEMS = %w(name messages_ready messages_unacknowledged messages_uncommitted messages acks_uncommitted consumers transactions memory)

  def build_report
    rabbitmqctl_script = option('rabbitmqctl')
    queue_name = option('queue')
    vhost = option('vhost')

    unless queue_name
      error(&quot;Queue name not specified&quot;, &quot;You must specify the queue to get details for.&quot;)
      return
    end

    queue_stats_line = get_queue_stats_line(rabbitmqctl_script, queue_name, vhost)

    unless queue_stats_line
      error(&quot;\&quot;#{queue_name}\&quot; queue not found&quot;, &quot;Please check the queue name for potential errors.&quot;)
      return
    end

    report(extract_stats(queue_stats_line))
  end

  private
    def get_queue_stats_line(rabbitmqctl_script, queue_name, vhost)
      cmd = vhost.nil? ? &quot;#{rabbitmqctl_script} -q list_queues &quot; : &quot;#{rabbitmqctl_script} -q list_queues -p '#{vhost}' &quot;
      all_queue_stats = `#{cmd} #{QUEUE_INFO_ITEMS.join(' ')}`.to_a
      all_queue_stats.detect do |line|
        line.split[0] == queue_name
      end
    end

    def extract_stats(queue_stats_line)
      queue_stats = queue_stats_line.split

      report_data = {}
      QUEUE_INFO_ITEMS.each_with_index do |item, i|
        next if item == 'name'
        report_data[item] = queue_stats[i]

        if item == 'memory'
          # Convert from bytes to megabytes
          report_data[item] = report_data[item].to_f / (1024 * 1024)
        end
      end
      report_data
    end
end</code>
    <created-at type="datetime">2010-03-05T23:25:12Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>!http://img.skitch.com/20100305-pyhg467seg9nbt1d4k2haqqxu7.png!

&quot;RabbitMQ&quot;:http://www.rabbitmq.com/ is an enterprise messaging system based on the emerging AMQP standard. This plugin monitors a given RabbitMQ Queue. To monitor overall RabbitMQ metrics, &quot;checkout the RabbitMQ Overall Monitoring Plugin&quot;:http://scoutapp.com/plugin_urls/301-rabbitmq-overall-monitoring. 

The plugin reports the following metrics for the given queue:

* # of Messages
* # of Messages Ready
* # of Messages Uncommitted
* # Messages Unacked
* # of Transactions
* # of Consumers
* # of Acks Uncommitted
* Memory Usage of the Queue
</description>
    <featured type="boolean">false</featured>
    <id type="integer">311</id>
    <metadata type="yaml">--- |-
metadata:
  messages_ready:
    units: &quot;msg&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Messages Ready
  messages_unacknowledged:
    units: &quot;msg&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Messages Unacked
  messages_uncommitted:
    units: &quot;msg&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Messages Uncommitted
  messages:
    units: &quot;msg&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Messages
  acks_uncommitted:
    units: &quot;acks&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Acks Uncommitted
  consumers:
    units: &quot;consumers&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Consumers
  transactions:
    units: &quot;txns&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Transactions
  memory:
    units: &quot;MB&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Memory
</metadata>
    <name>RabbitMQ Queue Monitoring</name>
    <plugins-count type="integer">7</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors a given RabbitMQ Queue</short-description>
    <tested-platforms>Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-05T23:31:08Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/rabbitmq_queue_details/rabbitmq_queue_details.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Jacob Harris</author>
    <cached-tag-list>mongo, mongodb</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;time&quot;
require &quot;digest/md5&quot;

# MongoDB Slow Queries Monitoring plug in for scout.
# Created by Jacob Harris, based on the MySQL slow queries plugin

class ScoutMongoSlow &lt; Scout::Plugin
  needs &quot;mongo&quot;

  OPTIONS=&lt;&lt;-EOS
    database:
      name: Mongo Database
      notes: Name of the MongoDB database to profile
    server:
      name: Mongo Server
      notes: Where mongodb is running
      default: localhost
    threshold:
      name: Threshold (millisecs)
      notes: Slow queries are &gt;= this time in milliseconds to execute (min. 100)
      default: 100
  EOS

  def enable_profiling(db)
    # set to slow_only or higher (&gt;100ms)
    if db.profiling_level == :off
      db.profiling_level = :slow_only
    end
  end
  
  def build_report
    database = option(&quot;database&quot;).to_s.strip
    server = option(&quot;server&quot;).to_s.strip
    
    if server.empty?
      server ||= &quot;localhost&quot;
    end
    
    if database.empty?
      return error( &quot;A Mongo database name was not provided.&quot;,
                    &quot;Slow query logging requires you to specify the database to profile.&quot; )
    end

    threshold_str = option(&quot;threshold&quot;).to_s.strip
    if threshold_str.empty?
      threshold = 100
    else
      threshold = threshold_str.to_i
    end

    db = Mongo::Connection.new(server).db(database)
    enable_profiling(db)

    slow_queries = []
    last_run = memory(:last_run) || Time.now
    current_time = Time.now
    
    # info
    selector = { 'millis' =&gt; { '$gte' =&gt; threshold } }
    cursor = Mongo::Cursor.new(Mongo::Collection.new(db, Mongo::DB::SYSTEM_PROFILE_COLLECTION), :selector =&gt; selector).limit(20).sort([[&quot;$natural&quot;, &quot;descending&quot;]])
    
    # reads most recent first
    # {&quot;ts&quot;=&gt;Wed Dec 16 02:44:03 UTC 2009, &quot;info&quot;=&gt;&quot;query twitter_follow.system.profile ntoreturn:0 reslen:1236 nscanned:8  \nquery: { query: { millis: { $gte: 5 } }, orderby: { $natural: -1 } }  nreturned:8 bytes:1220&quot;, &quot;millis&quot;=&gt;57.0}
    cursor.each do |prof|
      ts = prof['ts']
      break if ts &lt; last_run
      
      slow_queries &lt;&lt; prof
    end

    elapsed_seconds = current_time - last_run
    elapsed_seconds = 1 if elapsed_seconds &lt; 1
    # calculate per-second
    report(:slow_queries =&gt; slow_queries.size/(elapsed_seconds/60.to_f))
    
    if slow_queries.any?
      alert(build_alert(slow_queries))
    end
    remember(:last_run,Time.now)
  rescue Mongo::MongoDBError =&gt; error
    error(&quot;A Mongo DB error has occurred.&quot;, &quot;A Mongo DB error has occurred&quot;)    
  end
  
  def build_alert(slow_queries)
    subj = &quot;Maximum Query Time exceeded on #{slow_queries.size} #{slow_queries.size &gt; 1 ? 'queries' : 'query'}&quot;
    
    body = String.new
    slow_queries.each do |sq|
      body &lt;&lt; &quot;&lt;strong&gt;#{sq[&quot;millis&quot;]} millisec query on #{sq['ts']}:&lt;/strong&gt;\n&quot;
      body &lt;&lt; sq['info']
      body &lt;&lt; &quot;\n\n&quot;
    end # slow_queries.each
    {:subject =&gt; subj, :body =&gt; body}
  end # build_alert
end
</code>
    <created-at type="datetime">2010-02-25T23:53:13Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>!http://img.skitch.com/20100226-tt6f6bm79992747x33hxkmu63c.png!

Reports slow queries based on the threshold (100ms or greater) you specify. Provides details on queries that are slow. 

h2. Dependencies

The &quot;mongo&quot;:http://github.com/mongodb/mongo-ruby-driver (minimum version  0.18.3) and &quot;mongo_ext&quot;:http://rubygems.org/gems/mongo_ext (minimum version  0.18.3) gems.

&lt;div class=&quot;terminal&quot;&gt;
gem install mongo
gem install mongo_ext
&lt;/div&gt;
</description>
    <featured type="boolean">false</featured>
    <id type="integer">291</id>
    <metadata type="yaml">--- |-
metadata:
  slow_queries:
    units: /min
    precision: 2
</metadata>
    <name>MongoDB Slow Queries</name>
    <plugins-count type="integer">5</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Monitors for slow MongoDB queries and generates an alert (containing the queries) whey they occur.

The plugin has two options, the database and a threshold for slow query times

It automatically sets the profiling level of the named database to slow_queries only or above.

Dependencies: the mongo and mongo_ext gems (gem install mongo; gem install mongo_ext)</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">5</scout-version>
    <short-description>Reports slow queries based on the threshold (100ms or greater) you specify. Provides details on queries that are slow. This plugin is BETA.</short-description>
    <tested-platforms>Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-04T02:14:30Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/mongo_slow_queries/mongo_slow_queries.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Chad Woolley</author>
    <cached-tag-list>timestamp, file</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class CheckTimestamp &lt; Scout::Plugin
  def build_report
    begin
      threshold = option(:threshold).to_f
      path = option(:path)
      timestamp = File.new(path).mtime
      current_time = Time.now
      difference = ((current_time - timestamp) / 60).round.to_f
      output = &quot;Path: #{path}, Threshold: #{threshold} minutes, Path Timestamp: #{timestamp}, Current Time: #{current_time}, Difference: #{difference}&quot;
      report(:difference =&gt; difference, :threshold =&gt; threshold)
      if difference &gt; threshold
        alert(:subject =&gt; &quot;File #{path} was #{difference} minutes old, which is over the threshold of #{threshold} minutes&quot;, :body =&gt; output)
      end
      return difference
    rescue Exception =&gt; e
      error(:subject =&gt; 'Error running Check Timestamp plugin', :body =&gt; e)
      return -1
    end
  end
end</code>
    <created-at type="datetime">2008-11-19T07:51:19Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Checks the timestamp on a given file, generating an alert if the timestamp of the file is older than a given threshold.

</description>
    <featured type="boolean">false</featured>
    <id type="integer">92</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Timestamp Monitor</name>
    <plugins-count type="integer">5</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Checks the timestamp on a given file, generating an alert if the timestamp of the file is older than a given threshold.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:27Z</updated-at>
    <url>http://github.com/thewoolleyman/scout_plugin_check_timestamp/blob/master%2Fcheck_timestamp.rb?raw=true</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Matt Todd and Ches Martin</author>
    <cached-tag-list>redis</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class RedisMonitor &lt; Scout::Plugin
  needs 'redis', 'yaml'

  OPTIONS = &lt;&lt;-EOS
  client_port:
    name: Port
    notes: Redis port to pass to the client library.
    default: 6379
  client_db:
    name: Database
    notes: Redis database ID to pass to the client library.
    default: 0
  client_password:
    name: Password
    notes: If you're using Redis' password authentication.
  lists:
    name: Lists to monitor
    notes: A comma-separated list of list keys to monitor the length of.
  EOS

  KILOBYTE = 1024
  MEGABYTE = 1048576

  def build_report
    redis = Redis.new :port     =&gt; option(:client_port),
                      :db       =&gt; option(:db),
                      :password =&gt; option(:password)
    begin
      info = redis.info
    rescue Errno::ECONNREFUSED =&gt; error
      return error( &quot;Could not connect to Redis.&quot;,
                    &quot;Make certain you've specified correct port, DB and password.&quot; )
    end

    report(:uptime_in_hours   =&gt; info[:uptime_in_seconds].to_f / 60 / 60)
    report(:used_memory_in_mb =&gt; info[:used_memory].to_i / MEGABYTE)
    report(:used_memory_in_kb =&gt; info[:used_memory].to_i / KILOBYTE)

    counter(:connections_per_sec, info[:total_connections_received].to_i, :per =&gt; :second)
    counter(:commands_per_sec,    info[:total_commands_processed].to_i,   :per =&gt; :second)

    # General Stats
    %w(changes_since_last_save connected_clients connected_slaves bgsave_in_progress).each do |key|
      report(key =&gt; info[key.intern])
    end

    if option(:lists)
      lists = option(:lists).split(',')
      lists.each do |list|
        report(&quot;#{list} list length&quot; =&gt; redis.llen(list))
      end
    end
  end

  private

  # Borrowed shamelessly from Eric Lindvall:
  # http://github.com/eric/scout-plugins/raw/master/iostat/iostat.rb
  def counter(name, value, options = {}, &amp;block)
    current_time = Time.now

    if data = memory(name)
      last_time, last_value = data[:time], data[:value]
      elapsed_seconds       = current_time - last_time

      # We won't log it if the value has wrapped or enough time hasn't
      # elapsed
      unless value &lt;= last_value || elapsed_seconds &lt;= 1
        if block
          result = block.call(last_value, value)
        else
          result = value - last_value
        end

        case options[:per]
        when :second, 'second'
          result = result / elapsed_seconds.to_f
        when :minute, 'minute'
          result = result / elapsed_seconds.to_f / 60.0
        else
          raise &quot;Unknown option for ':per': #{options[:per].inspect}&quot;
        end

        if options[:round]
          # Backward compatibility
          options[:round] = 1 if options[:round] == true

          result = (result * (10 ** options[:round])).round / (10 ** options[:round]).to_f
        end

        report(name =&gt; result)
      end
    end

    remember(name =&gt; { :time =&gt; current_time, :value =&gt; value })
  end
end</code>
    <created-at type="datetime">2010-01-28T20:55:57Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>!http://img.skitch.com/20100128-x7gi48qp1p6bfe96jkfsiwgf1f.png!

Monitors a &quot;Redis&quot;:http://code.google.com/p/redis/ database, reporting the metrics below:

* Background save in progress
* Changes since last save
* Commands Per-Second
* Connected clients
* Connected slaves
* Connections Per-Second
* Uptime in hours
* Used Memory in KB
* Used Memory in MB

h2. Installation

* Install the @redis@ gem (@sudo gem install redis@)
* Install the plugin on scoutapp.com
* Provide the Redis port (default is 6379), client database id (default is 0), and client password (default is none).</description>
    <featured type="boolean">false</featured>
    <id type="integer">271</id>
    <metadata type="yaml">--- |
metadata:
  uptime_in_hours:
    units: hours
    larger_is_better: 1
    precision: 2
    label: Uptime
  used_memory_in_mb:
    units: MB
    larger_is_better: 0
    precision: 0
    label: Used Memory (MB)
  used_memory_in_kb:
    units: KB
    larger_is_better: 0
    precision: 0
    label: Used Memory (KB)
  connections_per_sec:
    units: conn/sec
    larger_is_better: 0
    precision: 2
    label: Connections
  commands_per_sec:
    units: com/sec
    larger_is_better: 0
    precision: 2
    label: Commands
  changes_since_last_save:
    larger_is_better: 0
    precision: 0
  connected_clients:
    larger_is_better: 0
    precision: 0
  connected_slaves:
    larger_is_better: 0
    precision: 0
  bgsave_in_progress:
    larger_is_better: 0
    precision: 0
    label: Background Save in Progress?

</metadata>
    <name>Redis Monitoring</name>
    <plugins-count type="integer">5</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>Monitors a Redis database, reporting commands per-second, connections per-second, Used Memory, and more.</short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-02-02T01:08:49Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/redis-info/redis-info.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Doug Barth</author>
    <cached-tag-list>rabbitmq</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code># Created by Doug Barth. 
# http://github.com/dougbarth/
class RabbitmqOverall &lt; Scout::Plugin
  OPTIONS = &lt;&lt;-EOS
  rabbitmqctl:
    name: rabbitmqctl command
    notes: The command used to run the rabbitctl program, minus arguments
    default: rabbitmqctl
  EOS

  def build_report
    begin
      report_data = {}

      connection_stats = `#{rabbitmqctl} -q list_connections`.to_a
      report_data['connections'] = connection_stats.size

      report_data['queues'] = report_data['messages'] = report_data['queue_mem'] = 0
      report_data['exchanges'] = 0
      report_data['bindings'] = 0
      vhosts.each do |vhost|
        queue_stats = `#{rabbitmqctl} -q list_queues -p '#{vhost}' messages memory`.to_a
        report_data['queues'] += queue_stats.size
        report_data['messages'] += queue_stats.inject(0) do |sum, line|
          sum += line.split[0].to_i
        end

        report_data['queue_mem'] += queue_stats.inject(0) do |sum, line|
          sum += line.split[1].to_i
        end

        exchange_stats = `#{rabbitmqctl} -q list_exchanges -p #{vhost}`.to_a
        report_data['exchanges'] += exchange_stats.size

        binding_stats = `#{rabbitmqctl} -q list_bindings -p #{vhost}`.to_a
        report_data['bindings'] += binding_stats.size
      end

      # Convert queue memory from bytes to MB.
      report_data['queue_mem'] = report_data['queue_mem'].to_f / (1024 * 1024)

      report(report_data)
    rescue RuntimeError =&gt; e
      add_error(e.message)
    end
  end

  def rabbitmqctl
    option('rabbitmqctl')
  end

  def vhosts
    @vhosts ||= `#{rabbitmqctl} -q list_vhosts`.to_a
  end

  def `(command)
    result = super(command)
    if ($? != 0)
      raise &quot;&lt;#{command}&gt; exited with a non-zero value: #{$?}&quot;
    end
    result
  end
end</code>
    <created-at type="datetime">2010-03-05T23:16:18Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>!http://img.skitch.com/20100305-pyhg467seg9nbt1d4k2haqqxu7.png!

Monitors &quot;RabbitMQ&quot;:http://www.rabbitmq.com/, an enterprise messaging system based on the emerging AMQP standard. To monitor a specific RabbitMQ queue, &quot;checkout the RabbitMQ Queue Monitoring Plugin&quot;:http://scoutapp.com/plugin_urls/311-rabbitmq-queue-monitoring.

!http://img.skitch.com/20100305-qdxaeusr38ix3tdddueywnyfq3.png!

The following metrics are reported:

* # of Queues
* # of Messages
* # of Connections
* # of Bindings
* # of Exchanges
* Queue Memory Usage</description>
    <featured type="boolean">false</featured>
    <id type="integer">301</id>
    <metadata type="yaml">--- |-
metadata:
  connections:
    units: &quot;connections&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Connections
  queues:
    units: &quot;queues&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Queues
  messages:
    units: &quot;msg&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Messages
  queue_mem:
    units: &quot;MB&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Queue Memory Used
  exchanges:
    units: &quot;exchanges&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Exchanges
  bindings:
    units: &quot;bindings&quot;
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Bindings
</metadata>
    <name>RabbitMQ Overall Monitoring</name>
    <plugins-count type="integer">4</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">3</scout-version>
    <short-description>Monitors RabbitMQ, an enterprise messaging system based on the emerging AMQP standard.</short-description>
    <tested-platforms>Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-05T23:55:36Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/rabbitmq_overall/rabbitmq_overall.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>google analytics, popularity</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;time&quot;

class GoogleAnalytics &lt; Scout::Plugin
  
  TEST_USAGE = &quot;#{File.basename($0)} user USER password PASSWORD account ACCOUNT profile PROFILE offset OFFSET&quot;
  
  USERAGENT = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1'
  LANGUAGE = 'en-US'
  
  def require_libs
    require 'net/http'
    require 'net/https'
    require 'uri'
    require 'hpricot'
  end
  
  def run
    begin
      require_libs
    rescue LoadError
      begin
        require &quot;rubygems&quot;       
        require_libs
      rescue LoadError
        return { :error =&gt; { :subject =&gt; &quot;Couldn't load required libraries.&quot;,
                             :body    =&gt; &quot;Please see the required libaries in the README file&quot; } }
      end
    end

    # The following attributes are required:
    # - user
    # - password
    # - account
    # - profile
    if [@options[&quot;account&quot;],@options[&quot;profile&quot;],@options[&quot;user&quot;],@options[&quot;password&quot;]].map { |opt| opt.strip.length}.find { |v| v.zero? }
      return { :error =&gt; { :subject =&gt; &quot;The user, password, account, and profile must be provided.&quot; } }
    end
    
    init_request_vars
    unless login
      return { :error =&gt; { :subject =&gt; &quot;The user and/or password is invalid.&quot; } }
    end
    
    # grabs data from the current day
    data = visit_data(@options[&quot;account&quot;],@options[&quot;profile&quot;],Time.parse(Date.today.to_s).utc-(@options[&quot;offset&quot;].to_i*60*60),Time.parse(Date.today.to_s).utc-(@options[&quot;offset&quot;].to_i*60*60))
    
    { :report =&gt; data }
  rescue
    { :error =&gt; {:subject =&gt; &quot;Google Analytics data could not be collected&quot;,
                 :body    =&gt; &quot;#{$!.message}\n\n#{$!.backtrace}&quot;}
    }
  end # run

  # Vars that will be sent along with the request
  def init_request_vars
    @user = @options[&quot;user&quot;]
    @pass = @options[&quot;password&quot;]
  end
  
  # Logs into Google Analytics. 
  # Returns true if successful, false otherwise. 
  # Sets +@cookies+ for future requests.
  def login
    par = {'continue' =&gt;        'https://www.google.com/analytics/home/?et=reset&amp;hl=' + LANGUAGE,
     'service' =&gt;         'analytics',
     'nui' =&gt;	          'hidden',
     'hl' =&gt;              LANGUAGE,
     'GA3T'	=&gt;	  'ouVrvynQwUs',
     'Email' =&gt;           @user,
     'PersistentCookie'=&gt; 'yes',
     'Passwd' =&gt;          @pass}
  
    http = Net::HTTP.new(&quot;www.google.com&quot;, 443)
    http.use_ssl = true
    resp = nil
    http.start do |http|
      req = Net::HTTP::Post.new(&quot;/accounts/ServiceLoginBoxAuth&quot;)
      req.set_form_data(par)

      resp = http.request(req)
    end
   
    @cookies = resp.response['set-cookie'].split('; ')[0]
 
    if resp.code.to_i != 200
      false
    else
      true
    end
  end
  
  # Grabs the list of accounts for this user. Returns an Array of Hashes
  # that contains the account value and name.
  def list_accounts
    req = Hpricot(make_request('/analytics/home/?et=reset&amp;hl=' + LANGUAGE))
    # some logins are redirected
    title = req.search(&quot;title/text()&quot;).first
    options = if title.to_s =~ /301/           
                url = req.search(&quot;a&quot;).first['href']
                req = Hpricot(make_request(url))
                req.search(&quot;//select[@id='account']/option&quot;)
              else
                req.search(&quot;select[@name='account_list']/option&quot;)
              end
   if options.empty?
     if req.search(&quot;iframe[@id='login']&quot;)
       raise &quot;Unable to login to the Google Analytics with user [#{@options['user']}]. Please ensure the login and password is correct.&quot;
     end
   end
   accounts = []
   options.each do |opt|
   if opt['value'] != &quot;0&quot;
    acc = {}
    acc['value'] = opt['value']
    acc['name'] = opt.inner_html
    accounts &lt;&lt; acc
   end
   end
   accounts
  end
  
  # Lists profiles available under the +account_id+.
  def list_profiles_for_account(account_id)
    req = Hpricot(make_request(&quot;/analytics/home/admin?vid=1100&amp;scid=#{account_id}&quot;))
    find_profiles(req)
  end
  
  def find_profiles(req)
    options = req.search(&quot;select[@name='profile_list']/option&quot;)
     profiles = []
     options.each do |opt|
     if opt['value'] != &quot;0&quot;
      prof = {}
      prof['value'] = opt['value']
      prof['name'] = opt.inner_html
      profiles &lt;&lt; prof
     end
     end
     profiles
  end
  
  # Returns a 2-element hash with the number of visits and page_views over the specified range.
  def visit_data(account_name,profile_name,start_date,end_date)
    accounts = list_accounts
    account = accounts.find { |pair| pair[&quot;name&quot;] == account_name }
    
    if account.nil?
      error = &quot;Couldn't find the account with name: #{account_name}.&quot;
      if !accounts.any?
        error &lt;&lt; &quot; No accounts are available with the provided login information. Please ensure the user #{@options['user']} has access.&quot;
      else
        error &lt;&lt; &quot; #{accounts.size} Possible accounts: #{accounts.join(', ')}&quot;
      end
      raise error
    end
    
    account_id = account[&quot;value&quot;]
    
    profiles = list_profiles_for_account(account_id)
    profile  = profiles.find { |pair| pair[&quot;name&quot;] == profile_name }
    
    raise &quot;Couldn't find the profile with name: #{profile_name}&quot; if profile.nil?
          
    profile_id = profile[&quot;value&quot;]
    
    start_date = start_date.strftime(&quot;%Y%m%d&quot;)
    end_date   = end_date.strftime(&quot;%Y%m%d&quot;)
    
    req = Hpricot(make_request(&quot;/analytics/reporting/dashboard?id=#{profile_id}&amp;pdr=#{start_date}-#{end_date}&amp;cmp=average&quot;))
    
    visits = (req/&quot;//div[@id='VisitsSummary']//span[@class='primary_value']&quot;).inner_html.strip.gsub(/\D/,'').to_i
    page_views = (req/&quot;//div[@id='PageviewsSummary']//span[@class='primary_value']&quot;).inner_html.strip.gsub(/\D/,'').to_i
    
    {&quot;visits&quot; =&gt; visits, &quot;page_views&quot; =&gt; page_views}
  end
  
  def make_request(address)
    raise ScriptError, &quot;You should already be logged in!&quot; unless @cookies
      
    headers = {
       'Cookie' =&gt; @cookies,
       'User-Agent' =&gt; USERAGENT
  	}
    response, body = nil
    http = Net::HTTP.new(&quot;www.google.com&quot;, 443)
    http.use_ssl = true
    http.start do |http|
     req = Net::HTTP::Get.new(address, headers)
     response = http.request(req)
     body = response.body
    end
  
   body
  end
  
  
    
    
end # GoogleAnalytics
</code>
    <created-at type="datetime">2007-12-30T03:58:48Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Returns the number of page views and visits for the current day.&lt;br/&gt;

Code (and inspiration) taken and updated from Burnalytics:
http://www.eribium.org/blog/?p=51&lt;br/&gt;

*Dependencies*&lt;br/&gt;

Requires the following libraries:&lt;br/&gt;

require 'net/http'
require 'net/https'
require 'uri'
require 'rubygems'
require 'hpricot'</description>
    <featured type="boolean">false</featured>
    <id type="integer">9</id>
    <metadata type="yaml">--- |
options:
  user:
  password:
  account:
    name: Account
    notes: The name of the Google Analytics Account
  profile:
    name: Profile
    notes: The name of the profile
  offset:
    name: Offset
    notes: Time in hours that should be subtracted from UTC when grabbing the date

</metadata>
    <name>Google Analytics</name>
    <plugins-count type="integer">3</plugins-count>
    <rating-avg type="decimal" nil="true"></rating-avg>
    <rating-count type="integer" nil="true"></rating-count>
    <rating-total type="integer" nil="true"></rating-total>
    <readme>Google Analytics Plugin
======================
Created by [Highgroove Studios LLC](http://www.highgroove.com)

Returns the number of page views and visits for the current day. 

Code (and inspiration) taken and updated from [Burnalytics](http://www.eribium.org/blog/?p=51)

Dependencies
------------

Requires the [hpricot library](http://code.whytheluckystiff.net/hpricot/):

	sudo gem install hpricot

Compatibility 
-------------
Works fully on Linux and OSX. 



</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Returns the number of page views and visits for the current day. 

</short-description>
    <tested-platforms>linux macosx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:11Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/google_analytics/google_analytics.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mike Mangino</author>
    <cached-tag-list>facebook</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class PageLoadFailed &lt; StandardError; end
class MissingLibrary &lt; StandardError; end
class CantLoginError &lt; StandardError; end
class FacebookContentMonitor &lt; Scout::Plugin

  
  attr_accessor :agent

  def login
    return if @logged_in
    3.times do
      begin
      puts &quot;Trying to login!&quot;
      login_page = agent.get(&quot;http://www.facebook.com&quot;)
      login_form = login_page.forms.first
      login_form['email']=option(:username)
      login_form['pass']=option(:password)
      login_page = agent.submit(login_form)
      if login_page.body.match(/Status Updates/)
        @logged_in = true
        return
      end
      rescue Errno::ECONNRESET,Errno::EPIPE
       sleep 2
      end
    end 
    raise CantLoginError,login_page.body
  end
  
  
  def setup_agent
    begin
      require &quot;mechanize&quot;
    rescue LoadError
      begin
        require &quot;rubygems&quot;
        require &quot;mechanize&quot;
      rescue LoadError
        raise MissingLibrary
      end
    end
    @agent = WWW::Mechanize.new
  end
  
  def build_report
    begin
      setup_agent
      login
      url = option(:url)
      content=option(:content)
      check_status(url,content)
      report(url=&gt;&quot;OK&quot;)
      remember(url=&gt;true)
    rescue  Net::HTTPNotFound=&gt;e
      error(&quot;Not Found&quot;)
    rescue Net::HTTPServiceUnavailable=&gt;e
      error(&quot;Service unavailable&quot;)
    rescue CantLoginError=&gt;e
      error(&quot;Unable to log in to Facebook&quot;,
            &quot;Check that the username and password were correctly entered&quot;)
    rescue  MissingLibrary=&gt;e
      error(&quot;Could not load all required libraries&quot;,
            &quot;I failed to load the mechanize library. Please make sure it is installed.&quot;)
    rescue  PageLoadFailed=&gt;e
      alert(:subject=&gt;&quot;#{url} check failed&quot;,:body=&gt;&quot;Expected to contain '#{content}' but contained '#{e.to_s}&quot;) if memory(url)
      remember(url=&gt;false)
    end
  end

  def check_status(url_to_monitor,text)
      3.times do
       begin
        puts &quot;Checking status of #{url_to_monitor}&quot;
        main_page =agent.get(url_to_monitor)
        unless main_page.body.match(/#{text}/)
          raise PageLoadFailed,main_page.body
        end
        return true

        rescue  Errno::ECONNRESET,Errno::EPIPE
          sleep 2
        end
      end
    end
  
end</code>
    <created-at type="datetime">2008-08-08T16:46:31Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>&lt;p&gt;A simple monitor that will login to [Facebook](http://www.facebook.com) and then fetch a given URL and make sure it contains a string. This is useful for making sure you don't get a maintenance page or an error page.&lt;/p&gt;

&lt;p&gt;This plugin requires that the [mechanize library](http://mechanize.rubyforge.org/mechanize/) be installed. Your Facebook user must have the application installed.&lt;/p&gt;</description>
    <featured type="boolean">false</featured>
    <id type="integer">62</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>Facebook Content Monitor</name>
    <plugins-count type="integer">3</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">2</scout-version>
    <short-description>A simple monitor that will login to Facebook and then fetch a given URL and make sure it contains a string. This is useful for making sure you don't get a maintenance page or an error page. </short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:25Z</updated-at>
    <url>http://github.com/mmangino/er-scout-plugins/blob/master/facebook_content_monitor/facebook_content_monitor.rb?raw=true</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>ruby on rails, web requests</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;time&quot;

class RailsSingleRequests &lt; Scout::Plugin
  
  TEST_USAGE = &quot;#{File.basename($0)} log LOG max_request_length MAX_REQUEST_LENGTH path PATH last_run LAST_RUN&quot;
  
  def run
    begin
      require &quot;elif&quot;
    rescue LoadError
      begin
        require &quot;rubygems&quot;
        require &quot;elif&quot;
      rescue LoadError
        return { :error =&gt; { :subject =&gt; &quot;Couldn't load Elif.&quot;,
                             :body    =&gt; &quot;The Elif library is required by &quot; +
                                         &quot;this plugin.&quot; } }
      end
    end
    
    if @options[&quot;log&quot;].strip.length == 0
      return { :error =&gt; { :subject =&gt; &quot;A path to the Rails log file wasn't provided.&quot; } }
    end
    if @options[&quot;path&quot;].strip.length == 0
      return { :error =&gt; { :subject =&gt; &quot;A path to analyze must be provided.&quot; } }
    end

    report = { :report =&gt; { :slow_request_count =&gt; 0,
                            :request_count =&gt; 0,
                            :average_request_length =&gt; nil},
               :alerts =&gt; Array.new }
    
    last_completed = nil
    slow_requests = ''
    total_request_time = 0.0
    Elif.foreach(@options[&quot;log&quot;]) do |line|
      if line =~ /\ACompleted in (\d+\.\d+) .+ \[(\S+)\]\Z/
        last_completed = [$1.to_f, $2]
      elsif last_completed and
            line =~ /\AProcessing .+ at (\d+-\d+-\d+ \d+:\d+:\d+)\)/
          time_of_request = Time.parse($1)
          if time_of_request &lt; (@last_run || (@options[&quot;last_run&quot;] ? Time.parse(@options[&quot;last_run&quot;]) : Time.now))
            break
          elsif last_completed.last =~ /#{@options[&quot;path&quot;]}/
            report[:report][:request_count] += 1
            total_request_time += last_completed.first.to_f
            if @options[&quot;max_request_length&quot;].to_f &gt; 0 and last_completed.first.to_f &gt; @options[&quot;max_request_length&quot;].to_f
              report[:report][:slow_request_count] += 1
              slow_requests += '[' + time_of_request.strftime(&quot;%m/%d/%y %I:%M %p&quot;) + '] '
              slow_requests += last_completed.first.to_s + &quot; sec&quot; + &quot;\n\n&quot;
            end
          end # request should be analyzed
      end
    end
    
    # Create a single alert that holds all of the requests that exceeded the +max_request_length+.
    if report[:report] and (count = report[:report][:slow_request_count].to_i and count &gt; 0)
      report[:alerts] &lt;&lt; {:subject =&gt; &quot;Maximum Time(#{@options[&quot;max_request_length&quot;].to_s} sec) exceeded on #{count} #{count &gt; 1 ? 'requests' : 'request'} for \&quot;#{@options['path']}\&quot;&quot;,
                          :body =&gt; slow_requests}
    end
    # Calculate the average request time if there are any requests
    if report[:report][:request_count] &gt; 0
      avg = total_request_time/report[:report][:request_count]
      report[:report][:average_request_length] = sprintf(&quot;%.2f&quot;, avg)
    end
    report
  rescue
    { :error =&gt; { :subject =&gt; &quot;Couldn't parse log file.&quot;,
                  :body    =&gt; &quot;#{$!.message}\n\n#{$!.backtrace}&quot; } }
  end
end
</code>
    <created-at type="datetime">2008-01-08T03:31:53Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Monitors requests to a SINGLE PATH (ie - /forums/show) in a Ruby on Rails web application, alerting when slow web requests occur. 
&lt;br/&gt;
Reports the total number of requests matching the path, the number of slow requests, and the average execution time.
&lt;br/&gt;
Requires the elif library
sudo gem install elif
&lt;br/&gt;
Options:

* Location of Ruby on Rails log file
* Maximum request length
* Path of URL to match
</description>
    <featured type="boolean">false</featured>
    <id type="integer">10</id>
    <metadata type="yaml">--- |
options:
  log:
    name: Log
    notes: The Rails log file to process
  path:
    name: Path
    notes: The path to monitor (ie - /reports/create)
  max_request_length:
    name: Max Request Length (sec)
    notes: If any request length is larger than this amount, an alert is generated
    default: 3

</metadata>
    <name>Ruby on Rails Single Path Request Monitoring</name>
    <plugins-count type="integer">2</plugins-count>
    <rating-avg type="decimal" nil="true"></rating-avg>
    <rating-count type="integer" nil="true"></rating-count>
    <rating-total type="integer" nil="true"></rating-total>
    <readme>Rails Single Requests Plugin
======================
Created by [Highgroove Studios LLC](http://www.highgroove.com)

Monitors a single Rails action.

Dependencies
------------

Requires the [elif library](http://elif.rubyforge.org/):

	sudo gem install elif
	
Options
-------
All of the options are required.

Compatibility 
-------------

Works on Linux and OSX.


</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Monitors requests to a SINGLE PATH (ie - /forums/show) in a Ruby on Rails web application, alerting when slow web requests occur. </short-description>
    <tested-platforms>linux macosx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:11Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/rails_single_request/rails_single_request.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mark Hasse</author>
    <cached-tag-list>time</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Moved Temporarily&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY BGCOLOR=&quot;#FFFFFF&quot; TEXT=&quot;#000000&quot;&gt;
&lt;H1&gt;Moved Temporarily&lt;/H1&gt;
The document has moved &lt;A HREF=&quot;http://sites.google.com/a/bluezucchini.com/www/time_drift.rb&quot;&gt;here&lt;/A&gt;.
&lt;/BODY&gt;
&lt;/HTML&gt;
</code>
    <created-at type="datetime">2008-04-22T14:02:09Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Checks time with NIST using daytime and calculates drift with the host being monitored.  Alerts based on a user settable value indicating maximum drift. </description>
    <featured type="boolean">false</featured>
    <id type="integer">18</id>
    <metadata type="yaml">--- |
options:
  max_drift:
    name: Maximum Drift
    notes: Specify the maximum allowable drift in seconds.
    default: 120

</metadata>
    <name>Monitor time drift from official NIST time</name>
    <plugins-count type="integer">2</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Checks time with NIST using daytime and calculates drift with the host being monitored.  Alerts based on a user settable value indicating maximum drift.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:17Z</updated-at>
    <url>http://www.bluezucchini.com/time_drift.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Jens-Christian Fischer</author>
    <cached-tag-list>url monitoring</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require 'net/http'
require 'uri'

class UrlMonitor &lt; Scout::Plugin
  include Net
  
  TEST_USAGE = &quot;#{File.basename($0)} url URL pattern PATTERN last_run LAST_RUN&quot;
  TIMEOUT_LENGTH = 50 # seconds
  
  def run
    url = @options[:url] || @options[&quot;url&quot;]
    pattern = @options[:pattern] || @options[&quot;pattern&quot;]

    if url.strip.length == 0
      return { :error =&gt; { :subject =&gt; &quot;A url wasn't provided.&quot; } }
    end
    
    unless (url.index(&quot;http://&quot;) == 0 || url.index(&quot;https://&quot;) == 0)
      url = &quot;http://&quot; + url
    end

    report = { :report =&gt; { :up     =&gt; 0, # 1 if working, 0 if not
                            :match  =&gt; 0, # if the pattern matched
                            :status =&gt; nil # the HTTP status
                          },
               :alerts =&gt; Array.new }
    
    response = http_response
    report[:report][:status] = response.class.to_s
    body = response.body

    if valid_http_response?(response)
      report[:report][:up] = 1
      if body =~ /#{pattern}/
        report[:report][:match] = 1
      else
        report[:report][:match] = 0
        report[:alerts] &lt;&lt; {:subject =&gt; &quot;The pattern [#{pattern}] was not detected on the website&quot;,
                            :body =&gt; &quot;URL: #{url}\n\nStatus: #{report[:report][:status]}&quot;}
      end
    else 
      report[:report][:up] = 0
      report[:alerts] &lt;&lt; {:subject =&gt; &quot;The URL [#{url}] is not responding&quot;,
                          :body =&gt; &quot;URL: #{url}\n\nStatus: #{report[:report][:status]}&quot;}
    end
    report
  rescue
    { :error =&gt; { :subject =&gt; &quot;Error monitoring url [#{url}]&quot;,
                  :body    =&gt; $!.message } }
  end
  
  def valid_http_response?(result)
    [HTTPOK,HTTPFound].include?(result.class) 
  end
  
  # returns the http response (string) from a url
  def http_response  
    url = @options['url'] || @options[:url]

    uri = URI.parse(url)

    response = nil
    retry_url_trailing_slash = true
    retry_url_execution_expired = true
    begin
      Net::HTTP.start(uri.host) {|http|
            http.open_timeout = TIMEOUT_LENGTH
            req = Net::HTTP::Get.new((uri.path != '' ? uri.path : '/' ) + (uri.query ? ('?' + uri.query) : ''))
            if uri.user &amp;&amp; uri.password
              req.basic_auth uri.user, uri.password
            end
            response = http.request(req)
      }
    rescue Exception =&gt; e
      # forgot the trailing slash...add and retry
      if e.message == &quot;HTTP request path is empty&quot; and retry_url_trailing_slash
        url += '/'
        uri = URI.parse(url)
        h = Net::HTTP.new(uri.host)
        retry_url_trailing_slash = false
        retry
      elsif e.message =~ /execution expired/ and retry_url_execution_expired
        retry_url_execution_expired = false
        retry
      else
        response = e.to_s
      end
    end
        
    return response
  end
  
  
end

</code>
    <created-at type="datetime">2008-12-05T16:25:52Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>This plugin looks for a given piece of text on a web page. If it's not found, an alert is generated. 

Very useful for when a URL isn't returning an error code (ex: HTTP Status code 200) when it should be or if a web page is being used to indicate the status of a system. 

Alerts are also generated if an error code is returned.</description>
    <featured type="boolean">false</featured>
    <id type="integer">122</id>
    <metadata type="yaml" nil="true"></metadata>
    <name>URL Content Monitor</name>
    <plugins-count type="integer">2</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>This plugin looks for a given piece of text on a web page. If it's not found, an alert is generated. </short-description>
    <tested-platforms>linux osx</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:29Z</updated-at>
    <url>http://github.com/jcfischer/scout-plugins/blob/master/urlcontent/urlcontent.rb?raw=true</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>mongrel, rails, mongrel_cluster</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class MongrelClusterMonitor &lt; Scout::Plugin
  def build_report
    mongrel_configuration_dir = option(:mongrel_cluster_configuration_dir) ||  &quot;/etc/mongrel_cluster/&quot;
    mongrel_rails_command = option(:mongrel_rails_command) || &quot;mongrel_rails&quot;
    res={}
    if !File.exist?(mongrel_configuration_dir)
      error(:subject=&gt;&quot;mongrel_configuration_dir: #{mongrel_configuration_dir} does not exist -- check options&quot;)
      return
    end
    Dir.chdir(mongrel_configuration_dir) do
      configs = Dir.glob(&quot;*.{yml,conf}&quot;)

      unless configs.empty?        
        configs.each do |config|
          application_name = config.gsub(&quot;.conf&quot;, &quot;&quot;).gsub(&quot;.yml&quot;, &quot;&quot;)
          mongrel_status = `#{mongrel_rails_command} cluster::status -C #{mongrel_configuration_dir}/#{config}`
          if mongrel_status.empty? 
            raise &quot;mongrel_rails command: `#{mongrel_rails_command}` not found or no status information available&quot;
          elsif mongrel_status.include?(&quot;missing&quot;)
            if memory(application_name)
              alert(:subject=&gt;&quot;Still down: one  or more mongrels for #{application_name}. Attempting Start.&quot;, :body=&gt;mongrel_status)
              mongrel_start = `#{mongrel_rails_command} cluster::start -C #{mongrel_configuration_dir}/#{config}`
            else
              alert(:subject =&gt; &quot;Down: one or more mongrels for #{application_name}&quot;, :body=&gt;mongrel_status)
              remember(application_name,Time.now)
            end
            res[application_name] = 0
          else
            res[application_name] = 1
            remember(application_name,nil)
          end
        end
      else
        alert(:subject =&gt; &quot;No mongrel configuration files found.&quot;)
      end
    end
  report(res)     
  rescue Exception =&gt; e
    error &quot;Encounterd an exception. #{e}&quot;
  end
end
</code>
    <created-at type="datetime">2009-11-18T18:48:01Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>This plugin will monitor a directory of mongrel_cluster configuration files and attempt to run the &quot;status&quot; command using:

&lt;div class=&quot;terminal&quot;&gt;
mongrel_rails cluster::status -C application.yml
&lt;/div&gt;

If it finds a down mongrel (a search for the word &quot;missing&quot;), it will send an Alert.  On the subsequent run, if the mongrel is still down, it will attempt a &quot;start&quot; using:

&lt;div class=&quot;terminal&quot;&gt;
mongrel_rails cluster::start -C application.yml
&lt;/div&gt;

On the next subsequent run, if the mongrel is still down, it will continue to send Alerts, and repeat the process.</description>
    <featured type="boolean">false</featured>
    <id type="integer">211</id>
    <metadata type="yaml">--- |+
options:
  mongrel_cluster_configuration_dir:
    name: Mongrel Cluster Configuration Directory
    notes: The directory where mongrel configurations are stored.
    default: /etc/mongrel_cluster
  mongrel_rails_command:
    name: Mongrel Rails Command
    notes: The full path to the mongrel_rails command.
    default: /usr/bin/mongrel_rails
    

</metadata>
    <name>Mongrel Cluster Monitor</name>
    <plugins-count type="integer">2</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme>Mongrel Cluster Monitor
======================
Created by 
 * Adam Parrott [Plexus Web Creations](http://www.plexusweb.com/)
 * [Highgroove Studios LLC](http://www.highgroove.com)

Summary
------------

This plugin will monitor a directory of mongrel_cluster configuration files and attempt to run the &quot;status&quot; command using:

mongrel_rails cluster::status -C application.yml

If it finds a down mongrel (a search for the word &quot;missing&quot;), it will send an Alert.  On the subsequent run, if the mongrel is still down, it will attempt a &quot;start&quot; using:

mongrel_rails cluster::start -C application.yml

On the next subsequent run, if the mongrel is still down, it will continue to send Alerts, and repeat the process.

Dependencies
------------

Requires mongrel and mongrel_cluster [mongrel](http://mongrel.rubyforge.org/):

	sudo gem install mongrel mongrel_cluster
	
Options
-------

Mongrel Configuration Directory.  This is usually /etc/mongrel_cluster, the path that stores application .yml files for mongrel's cluster startup options.

Compatibility 
-------------

Works on Linux and OSX.


</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">4</scout-version>
    <short-description>Uses mongrel_rails cluster::status to determine if any mongrels in your cluster have gone down. Sends alerts and attempts to restart when mongrels go down.</short-description>
    <tested-platforms>OSX, Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-11-18T18:55:30Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/mongrel_cluster_monitor/mongrel_cluster_monitor.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>feedburner, blog, analytics, popularity</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;time&quot;

class Feedburner &lt; Scout::Plugin
  
  TEST_USAGE = &quot;#{File.basename($0)} feed FEED&quot;
  
  def require_libs
    require 'open-uri'
    require 'hpricot'
  end
  
  def run
    begin
      require_libs
    rescue LoadError
      begin
        require &quot;rubygems&quot;       
        require_libs
      rescue LoadError
        return { :error =&gt; { :subject =&gt; &quot;Couldn't load required libraries.&quot;,
                             :body    =&gt; &quot;Please see the required libaries in the README file&quot; } }
      end
    end
    
    # The following attributes are required:
    # - feed
    if [@options[&quot;feed&quot;]].map { |opt| opt.strip.length}.find { |v| v.zero? }
      return { :error =&gt; { :subject =&gt; &quot;The feed must be provided.&quot; } }
    end
    
    # grabs data from the current day
    data = get_data(@options[&quot;feed&quot;])
    { :report =&gt; data.merge({:scout_time =&gt; Time.parse(data['date'])}) }
  rescue
    { :error =&gt; {:subject =&gt; &quot;FeedBurner data could not be collected&quot;,
                 :body    =&gt; &quot;#{$!.message}\n\n#{$!.backtrace}&quot;}
    }
  end # run
  
  private
  
  # Returns a 2-element hash with the circulation and feed hits
  def get_data(feed)
    res = open(&quot;https://feedburner.google.com/api/awareness/1.0/GetFeedData?uri=#{feed}&quot;).read
    hp = Hpricot(res)
    if hp.at(&quot;rsp&quot;).attributes['stat'] == &quot;ok&quot;
      parse_feedburner(res)
    else
      err = hp.at(&quot;err&quot;).attributes[&quot;msg&quot;]
      raise &quot;Unable to get data: #{err}&quot;
    end
  end
  
  def parse_feedburner(data)
   doc = Hpricot.parse(data)
   result = {}

   entry = (doc/&quot;rsp/feed/entry&quot;).first

   result['date'] = entry.attributes['date']
   result['circulation'] = entry.attributes['circulation']
   result['hits'] = entry.attributes['hits']

   result
  end
    
end # Feedburner
</code>
    <created-at type="datetime">2007-12-29T19:37:40Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Returns the feed circulation and hits from yesterday for the given feed.
&lt;br/&gt;
*Requirements*

FeedBurner Account w/awareness turned on (http://feedburner.com)
&lt;br/&gt;
*Dependencies*

Requires the following libraries:

require 'open-uri'
require 'hpricot'
&lt;br/&gt;
Code (and inspiration) taken and updated from Burnalytics:
http://www.eribium.org/blog/?p=51</description>
    <featured type="boolean">false</featured>
    <id type="integer">7</id>
    <metadata type="yaml">--- |+
options:
  feed:
    name: Feed Name
    notes: The name of the feed. Awareness must be activated.

</metadata>
    <name>FeedBurner Stats</name>
    <plugins-count type="integer">1</plugins-count>
    <rating-avg type="decimal" nil="true"></rating-avg>
    <rating-count type="integer" nil="true"></rating-count>
    <rating-total type="integer" nil="true"></rating-total>
    <readme>Feedburner Plugin
======================
Created by [Highgroove Studios LLC](http://www.highgroove.com)

Returns the feed circulation and hits from yesterday for the given feed.

Dependencies
------------
Requires the [hpricot library](http://code.whytheluckystiff.net/hpricot/):

	sudo gem install hpricot

Compatibility 
-------------
Works fully on Linux and OSX. 

Requirements
------------
FeedBurner Account w/awareness turned on (http://feedburner.com)


Compatibility 
-------------
Works fully on Linux and OSX.

Thanks
------
Code (and inspiration) taken and updated from [Burnalytics](http://www.eribium.org/blog/?p=51)
</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Returns the feed circulation and hits from yesterday for the given feed. </short-description>
    <tested-platforms>linux macox</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:09Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/feedburner/feedburner.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>yahoo, popularity</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class YahooTotalEntries &lt; Scout::Plugin
  
  TEST_USAGE = &quot;#{File.basename($0)} terms TERMS&quot;
  
  def require_libs
    require 'net/http'
    require 'hpricot'
    require 'cgi'
  end
  
  def run
    begin
      require_libs
    rescue LoadError
      begin
        require &quot;rubygems&quot;       
        require_libs
      rescue LoadError
        return { :error =&gt; { :subject =&gt; &quot;Couldn't load required libraries.&quot;,
                             :body    =&gt; &quot;Please see the required libaries in the README file&quot; } }
      end
    end
    
    # The following attributes are required:
    # - term
    if [@options[&quot;terms&quot;]].map { |opt| opt.strip.length}.find { |v| v.zero? }
      return { :error =&gt; { :subject =&gt; &quot;A search term must be provided.&quot; } }
    end
    
    # grabs data from the current day
    data = get_data(@options[&quot;terms&quot;])
    { :report =&gt; data }
  rescue
    { :error =&gt; {:subject =&gt; &quot;Yahoo! data could not be collected&quot;,
                 :body    =&gt; &quot;#{$!.message}\n\n#{$!.backtrace}&quot;}
    }
  end # run
  
  private
  
  # Returns a 2-element hash with the circulation and feed hits
  def get_data(terms)
    # don't think a unique id is required
    app_id = &quot;unique_app_id&quot;
    
    terms = terms.split(',')
    results = {}
    
    terms.each do |t|
      query = CGI::escape(t)
      url =&quot;http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=#{app_id}&amp;query=#{query}&quot;
      res = Net::HTTP.get_response(URI.parse(url))
      doc = Hpricot(res.body)
      
      total = doc.at(&quot;resultset&quot;)['totalresultsavailable']
      
      results[t.gsub(&quot;\&quot;&quot;,'').strip] = total
      
    end # terms.each
    
    results
  end
    
end # Feedburner
</code>
    <created-at type="datetime">2007-12-29T20:39:02Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Returns the total number of entries for each of the provided search terms. Separate multiple terms with a &quot;,&quot;. 

For example, to return the total number of entries for each of these two terms:&lt;br/&gt;

- Bill Clinton
- George Bush&lt;br/&gt;

Specify this as the term: &quot;Bill Clinton&quot;, &quot;George Bush&quot;

Which return 2 fields in the report:&lt;br/&gt;

Bill Clinton: 854,554,545
George Bush: 765,345,434&lt;br/&gt;

If you want all results that match those terms:&lt;br/&gt;

Term: &quot;Bill Clinton&quot; OR &quot;George Bush&quot;

Total Entries: 854,554,545 + 765,345,434&lt;br/&gt;

Code (and inspiration) taken and updated from:

http://kfahlgren.com/blog/2005/12/10/why-does-the-google-search-api-suck/
&lt;br/&gt;
*Dependencies*

Requires the following libraries:

require 'net/http'
require 'hpricot'
require 'cgi'
</description>
    <featured type="boolean">false</featured>
    <id type="integer">8</id>
    <metadata type="yaml">--- |+
options:
  terms:
    name: Term(s)
    notes: The terms to search for. Separate multiple terms with a comma.

</metadata>
    <name>Yahoo Total Entries</name>
    <plugins-count type="integer">1</plugins-count>
    <rating-avg type="decimal" nil="true"></rating-avg>
    <rating-count type="integer" nil="true"></rating-count>
    <rating-total type="integer" nil="true"></rating-total>
    <readme>Yahoo! Total Entries Count Plugin
=================================
Created by [Highgroove Studios LLC](http://www.highgroove.com)

Returns the total number of entries for each of the provided search terms. Separate multiple terms with a &quot;,&quot;. 

Dependencies
------------
Requires the [hpricot library](http://code.whytheluckystiff.net/hpricot/):

	sudo gem install hpricot
	
Usage Notes
-----------

To return the total number of entries for each of these two terms:

* Bill Clinton
* George Bush

Specify this as the term: &quot;Bill Clinton&quot;, &quot;George Bush&quot;

Which return 2 fields in the report:

* Bill Clinton: 854,554,545
* George Bush: 765,345,434

If you want all results that match those terms:

Term: &quot;Bill Clinton&quot; OR &quot;George Bush&quot;

Total Entries: 854,554,545 + 765,345,434

Code (and inspiration) taken and updated from:

http://kfahlgren.com/blog/2005/12/10/why-does-the-google-search-api-suck/

Compatibility 
-------------

Works on Linux and OSX. 

</readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Returns the total number of entries for each of the provided search terms. Separate multiple terms with a &quot;,&quot;. </short-description>
    <tested-platforms>linux macox</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:09Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/yahoo_total_entries/yahoo_total_entries.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Mark Hasse</author>
    <cached-tag-list>IP Address</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Moved Temporarily&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY BGCOLOR=&quot;#FFFFFF&quot; TEXT=&quot;#000000&quot;&gt;
&lt;H1&gt;Moved Temporarily&lt;/H1&gt;
The document has moved &lt;A HREF=&quot;http://sites.google.com/a/bluezucchini.com/www/dyndns.rb&quot;&gt;here&lt;/A&gt;.
&lt;/BODY&gt;
&lt;/HTML&gt;
</code>
    <created-at type="datetime">2008-04-22T14:03:53Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>I've had several times in the past when, for one reason or another, my dynamic DNS entry becomes out of date.  The monitor compares your current IP address to the hostname provided and checks to see that they are equal.   This must be running behind or on the dynamic address.</description>
    <featured type="boolean">false</featured>
    <id type="integer">19</id>
    <metadata type="yaml">--- |
options:
  hostname:
    name: External Hostname
    notes: Specify the fully qualified external hostname (e.g. dyndns.example.com).

</metadata>
    <name>Monitor that a dynamic DNS address is current</name>
    <plugins-count type="integer">1</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Compares your current IP address to the hostname provided and checks to see that they are equal. This must be running behind or on the dynamic address.</short-description>
    <tested-platforms>linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:18Z</updated-at>
    <url>http://www.bluezucchini.com/dyndns.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Highgroove Studios</author>
    <cached-tag-list>permissions</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>require &quot;etc&quot;

class CheckPermissions &lt; Scout::Plugin
  TEST_USAGE = &quot;#{File.basename($0)} directory DIRECTORY [owner OWNER] &quot;  +
                                                         &quot;[group GROUP] &quot; +
                                                         &quot;[mode MODE]&quot;

  def run
    report = {:files_tested =&gt; 0}
    failed = Array.new
    
    # adds a trailing '/' to the directory, which is appended
    # to the file page. 
    dir = @options[&quot;directory&quot;]
    unless dir =~ /\/$/
      dir &lt;&lt; '/'
    end
    
    Dir.foreach(@options[&quot;directory&quot;]) do |file|
      next if File.directory? file
      st = File.stat(dir + file)
      unless @options[&quot;owner&quot;].nil? or @options[&quot;owner&quot;].empty? or
             @options[&quot;owner&quot;] == Etc.getpwuid(st.uid).name
        failed &lt;&lt; &quot;File '#{file}' didn't have owner &quot; +
                                &quot;'#{@options['owner']}'&quot;
      end
      unless @options[&quot;group&quot;].nil? or @options[&quot;group&quot;].empty? or
             @options[&quot;group&quot;] == Etc.getgrgid(st.uid).name
        failed &lt;&lt; &quot;File '#{file}' didn't have group &quot; +
                                &quot;'#{@options['group']}'&quot; 
      end
      
      unless @options[&quot;mode&quot;].nil? or @options[&quot;mode&quot;].empty?
        expected = @options[&quot;mode&quot;].gsub(/[-rwx]{3}/) do |mode_str|
          mode_str.split(&quot;&quot;).inject(0) do |hex, m|
            hex + Hash[*%w[_ 0 r 4 w 2 x 1]][m].to_i
          end
        end
        actual = st.mode.to_s(8)[-expected.size..-1]
        unless actual == expected
          failed &lt;&lt; &quot;File '#{file}' had a mode of '#{actual}' &quot; +
                                  &quot;instead of the expected '#{expected}'&quot; 
        end
      end
      
      report[:files_tested] += 1
    end
    alerts = Array.new
    if failed.any?
      alerts &lt;&lt; {:subject =&gt; &quot;#{failed.size} file(s) failed permission checks&quot;,
                 :body =&gt; &quot;Directory: #{dir}&lt;br/&gt;&lt;br/&gt;&quot; + failed.join('&lt;br/&gt;&lt;br/&gt;')}
    end
    report[:failures] = failed.size
    {:report =&gt; report, :alerts =&gt; alerts}
  rescue
    { :error =&gt; { :subject =&gt; &quot;Couldn't determine file stats.&quot;,
                  :body    =&gt; $!.message + '&lt;br/&gt;&lt;br/&gt;' + $!.backtrace.join.to_s } }
  end
end
</code>
    <created-at type="datetime">2008-02-12T16:57:07Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>Looks at all files in a directory and ensures that each has the specified owner, group, and mode. 

One or all of the permission options can be used (owner, group, mode). </description>
    <featured type="boolean">false</featured>
    <id type="integer">13</id>
    <metadata type="yaml">--- |
options:
  directory:
    name: Directory
    notes: The directory to monitor
  owner:
    name: Owner
    notes: The expected login name for file owners
  group:
    name: Group
    notes: The expected login name for file groups
  mode:
    name: Mode
    notes: &quot;The permissions expected for files (format: rwxr--r--)&quot;

</metadata>
    <name>Check Permissions</name>
    <plugins-count type="integer">0</plugins-count>
    <rating-avg type="decimal" nil="true"></rating-avg>
    <rating-count type="integer" nil="true"></rating-count>
    <rating-total type="integer" nil="true"></rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">1</scout-version>
    <short-description>Looks at all files in a directory and ensures that each has the specified owner, group, and mode. </short-description>
    <tested-platforms>osx linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2009-09-24T06:03:14Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/7d13f07023d2d284fefceca078a86718e928f4d0/check_permissions/check_permissions.rb</url>
  </plugin-url>
  <plugin-url>
    <approved type="boolean">true</approved>
    <author>Jesse Newland</author>
    <cached-tag-list>memcache, memcached</cached-tag-list>
    <canonical-name nil="true"></canonical-name>
    <code>class MemcachedStats &lt; Scout::Plugin
  needs 'memcache', 'yaml'

  OPTIONS = &lt;&lt;-EOS
  host:
    name: Host
    notes: The host to monitor
    default: 127.0.0.1
  port:
    name: Port
    notes: The port memcached is running on
    default: 11211
  EOS

  KILOBYTE = 1024
  MEGABYTE = 1048576

  def build_report
    connection = MemCache.new &quot;#{option(:host)}:#{option(:port)}&quot;
    begin
      stats = connection.stats[&quot;#{option(:host)}:#{option(:port)}&quot;]
    rescue [Errno::ECONNREFUSED, MemCache::MemCacheError] =&gt; error
      return error( &quot;Could not connect to Memcached.&quot;,
                    &quot;Make certain you've specified correct host and port&quot; )
    end

    report(:uptime_in_hours   =&gt; stats['uptime'].to_f / 60 / 60)
    report(:used_memory_in_mb =&gt; stats['bytes'].to_i / MEGABYTE)
    report(:limit_in_mb       =&gt; stats['limit_maxbytes'].to_i / MEGABYTE)

    counter(:gets_per_sec,          stats['cmd_get'].to_i,       :per =&gt; :second)
    counter(:sets_per_sec,          stats['cmd_set'].to_i,       :per =&gt; :second)
    counter(:hits_per_sec,          stats['get_hits'].to_i,      :per =&gt; :second)
    counter(:misses_per_sec,        stats['get_misses'].to_i,    :per =&gt; :second)
    counter(:evictions_per_sec,     stats['evictions'].to_i,     :per =&gt; :second)

    counter(:kilobytes_read_per_sec,    (stats['bytes_read'].to_i / KILOBYTE),    :per =&gt; :second)
    counter(:kilobytes_written_per_sec, (stats['bytes_written'].to_i / KILOBYTE), :per =&gt; :second)

    # General Stats
    %w(curr_items total_items curr_connections threads).each do |key|
      report(key =&gt; stats[key])
    end
  end

  private

  # Borrowed shamelessly from Eric Lindvall:
  # http://github.com/eric/scout-plugins/raw/master/iostat/iostat.rb
  def counter(name, value, options = {}, &amp;block)
    current_time = Time.now

    if data = memory(name)
      last_time, last_value = data[:time], data[:value]
      elapsed_seconds       = current_time - last_time

      # We won't log it if the value has wrapped or enough time hasn't
      # elapsed
      unless value &lt;= last_value || elapsed_seconds &lt;= 1
        if block
          result = block.call(last_value, value)
        else
          result = value - last_value
        end

        case options[:per]
        when :second, 'second'
          result = result / elapsed_seconds.to_f
        when :minute, 'minute'
          result = result / elapsed_seconds.to_f / 60.0
        else
          raise &quot;Unknown option for ':per': #{options[:per].inspect}&quot;
        end

        if options[:round]
          # Backward compatibility
          options[:round] = 1 if options[:round] == true

          result = (result * (10 ** options[:round])).round / (10 ** options[:round]).to_f
        end

        report(name =&gt; result)
      end
    end

    remember(name =&gt; { :time =&gt; current_time, :value =&gt; value })
  end
end
</code>
    <created-at type="datetime">2010-03-10T21:30:10Z</created-at>
    <default-triggers type="yaml" nil="true"></default-triggers>
    <description>&lt;img src=&quot;http://img.skitch.com/20100310-bxhhk7nus9w8fchptg1651j67t.png&quot; /&gt;

This plugin provides stats on your memcached instance:

* Current connections
* Current items
* Evictions per second
* Gets per second
* Sets per second
* Hits per second
* Misses per second
* Read per second
* Kb written per second
* Limit
* Threads
* Total items
* Uptime
* Used memory

h2. Dependencies

Requires the memcache gem.

&lt;div class=&quot;terminal&quot;&gt;
sudo gem install memcache
&lt;/div&gt;</description>
    <featured type="boolean">false</featured>
    <id type="integer">321</id>
    <metadata type="yaml">--- |-
metadata: 
  uptime_in_hours: 
    units: hours
    larger_is_better: &quot;1&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Uptime
  used_memory_in_mb: 
    units: mb
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Used memory
  sets_per_sec: 
    units: per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Sets
  threads: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Threads
  limit_in_mb: 
    units: mb
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Limit
  misses_per_sec: 
    units: per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Misses
  hits_per_sec: 
    units: per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Hits
  gets_per_sec: 
    units: per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Gets
  kilobytes_written_per_sec: 
    units: kb per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Written
  curr_items: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Current items
  curr_connections: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Current connections
  total_items: 
    units: &quot;&quot;
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;0&quot;
    label: Total items
  kilobytes_read_per_sec: 
    units: kb per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Read per sec
  evictions_per_sec: 
    units: per second
    larger_is_better: &quot;0&quot;
    delimiter: &quot;,&quot;
    precision: &quot;2&quot;
    label: Evictions
</metadata>
    <name>Memcached Monitor</name>
    <plugins-count type="integer">0</plugins-count>
    <rating-avg type="decimal">0.0</rating-avg>
    <rating-count type="integer">0</rating-count>
    <rating-total type="integer">0</rating-total>
    <readme nil="true"></readme>
    <schema type="yaml" nil="true"></schema>
    <scout-version type="integer">5</scout-version>
    <short-description>Provides stats on your memcached instance, including gets/ sets/ hits/ misses/ evictions/ per second, uptime, memory used, KB read per second, KB written per second, and more.</short-description>
    <tested-platforms>Linux</tested-platforms>
    <total-usage-count type="integer">0</total-usage-count>
    <updated-at type="datetime">2010-03-10T21:49:07Z</updated-at>
    <url>http://github.com/highgroove/scout-plugins/raw/master/memcached_stats/memcached_stats.rb</url>
  </plugin-url>
</plugin-urls>
