As I’ve already said yesterday I’m currently getting warm with Python and for the beginning I’ve ported my sh compliant Apache check plugin for Nagios to a Python script which is now ready for first tests in production.
With options to set a hostname, a port and to define warning/critical thresholds for requests per second only, it got less features than the sh script at the moment. In future releases I’ll integrate more features which are already available in the sh script, but for now that’ll do the job. Feel free to visit NagiosExchange to download the script, check it out via svn or simply get along with the copy’n'paste possibility below.
user@host ~ $ svn co https://svn.matejunkie.com/svn/pp-nagios-plugins/stable/check_apache2/ check_apache2/ A check_apache2/check_apache2.py Checked out revision 14.
The script
#!/usr/bin/env python # Author: Mike Adolphs, 2009 # Blog: http://www.matejunkie.com/ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License only! # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import sys import urllib from optparse import OptionParser, OptionGroup # Nagios return codes OK = 0 WARNING = 1 CRITICAL = 2 UNKNOWN = 3 usage = "Usage: %prog -H HOSTNAME -p PORT [-w] [-c]" parser = OptionParser(usage, version="%prog 1.0") parser.add_option( "-H", "--hostname", type="string", dest="hostname", default="localhost", help="You may define a hostname with the -H option. \ Default is: localhost.") parser.add_option( "-p", "--port", type="int", dest="port", default=80, help="You may define a port with the -p option. \ Default is: 80.") group = OptionGroup(parser, "Warning/critical thresholds", "Use these options to set warning/critical thresholds \ for requests per second served by your Apache.") group.add_option( "-w", "--warning", type="int", dest="warning", default=-2, help="Use this option if you want to use warning/critical \ thresholds. Make sure to set a critical value as \ well. Default is: -1.") group.add_option( "-c", "--critical", type="int", dest="critical", default=-1, help="Use this option if you want to use warning/critical \ thresholds. Make sure to set a warning value as \ well. Default is: -2.") parser.add_option_group(group) (options, args) = parser.parse_args() hostname = options.hostname port = options.port warning = options.warning critical = options.critical def end(status, message): """Exits the script with the first argument as the return code and the second as the message to generate output.""" if status == OK: print "OK: %s" % message sys.exit(0) elif status == WARNING: print "WARNING: %s" % message sys.exit(1) elif status == CRITICAL: print "CRITICAL: %s" % message sys.exit(2) else: print "UNKNOWN: %s" % message sys.exit(3) def validate_thresholds(warning, critical): """Validates warning and critical thresholds in several ways.""" # This is already done by OptionParser. # try: # warning = int(warning) # except ValueError: # end(stateUNK, "Warning threshold must be an integer value.") # try: # critical = int(critical) # except ValueError: # end(stateUNK, "Critical threshold must be an integer value.") if critical != -1 and warning == -2: end(UNKNOWN, "Please also set a warning value when using warning/" + "critical thresholds!") if critical == -1 and warning != -2: end(UNKNOWN, "Please also set a critical value when using warning/" + "critical thresholds!") if critical <= warning: end(UNKNOWN, "When using thresholds the critical value has to be " + "higher than the warning value. Please adjust your " + "thresholds.") def retrieve_status_page(): """Get's the server's status page and raises an exception if it's not accessible.""" statusPage = "http://%s:%s/server-status?auto" % (hostname, port) try: retrPage = urllib.urlretrieve(statusPage, '/tmp/server-status.log') except: end(CRITICAL, "Couldn't fetch the server's status page. Please " + "check given hostname, port or Apache's " + "configuration. We might not be allowed to access " + "server-status due to your server's configuration.") def parse_status_page(): """Main parsing function to put the server-status file's content into a dictionary.""" file = open('/tmp/server-status.log', 'r') line = file.readline() dictStatus = {} counter = 1 while line: if "Total Accesses:" in line: key = "totalAcc" elif "Total kBytes:" in line: key = "totalKb" elif "Uptime:" in line: key = "uptime" elif "ReqPerSec:" in line: key = "reqPSec" elif "BytesPerSec:" in line: key = "bytesPSec" elif "BytesPerReq:" in line: key = "bytesPReq" elif "BusyWorkers:" in line: key = "busyWkrs" elif "IdleWorkers:" in line: key = "idleWkrs" else: key = str(counter) line = line.strip() dictStatus[key] = line counter = counter + 1 line = file.readline() return dictStatus def transform_dict(resParse): """Transforms the dictionary to a list and converts variables to proper types.""" totalAcc = int(resParse['totalAcc'].strip(" Total Accesses:")) totalKb = float(resParse['totalKb'].strip(" Total kBytes:")) uptime = int(resParse['uptime'].strip(" Uptime:")) reqPSec = float(resParse['reqPSec'].strip(" ReqPerSec:")) + 0 bytesPSec = float(resParse['bytesPSec'].strip(" BytesPerSec:")) if resParse.has_key('bytesPReq'): bytesPReq = float(resParse['bytesPReq'].strip(" BytesPerReq:")) busyWkrs = int(resParse['busyWkrs'].strip(" BusyWorkers:")) idleWkrs = int(resParse['idleWkrs'].strip(" IdleWorkers:")) return [reqPSec, busyWkrs, idleWkrs] # main if __name__ == "__main__": if critical != -1 or warning != -2: validate_thresholds(warning, critical) retrieve_status_page() resParse = parse_status_page() result = transform_dict(resParse) if critical != -1 and warning != -2: if result[0] >= critical: end(CRITICAL, "Apache serves %f requests per second, exceeding \ critical threshold! %i busy workers, %i idle workers." % (result[0], \ result[1], result[2])) elif result[0] >= warning and result[0] <= critical: end(WARNING, "Apache serves %f requests per second, exceeding \ warning threshold! %i busy workers, %i idle workers." % (result[0], \ result[1], result[2])) else: end(OK, "Apache serves %f requests per second. %i busy workers, \ %i idle workers." % (result[0], result[1], result[2])) else: end(OK, "Apache serves %f requests per second. %i busy workers, %i \ idle workers." % (result[0], result[1], result[2]))
Example Output
user@host $ ./check_apache2.py --version check_apache2.py 1.0 user@host $ ./check_apache2.py -H localhost -p 7001 OK: Apache serves 9.093710 requests per second. 1 busy workers, 49 idle workers. user@host $ ./check_apache2.py -H localhost -p 7001 -w 2 -c 5 CRITICAL: Apache serves 9.082950 requests per second, exceeding critical threshold! 1 busy workers, 49 idle workers. user@host $ ./check_apache2.py -H localhost -p 7001 -w 2 -c 10 WARNING: Apache serves 9.077650 requests per second, exceeding warning threshold! 1 busy workers, 49 idle workers. user@host $ ./check_apache2.py -H localhost -p 7001 -w 10 -c 20 OK: Apache serves 9.073430 requests per second. 1 busy workers, 49 idle workers. user@host $ ./check_apache2.py -H localhost -p 7001 -w 10 -c 5 UNKNOWN: When using thresholds the critical value has to be higher than the warning value. Please adjust your thresholds. user@host $ ./check_apache2.py -H localhost -p 7001 -w 5 UNKNOWN: Please also set a critical value when using warning/critical thresholds! user@host $ ./check_apache2.py -H localhost -p 7001 -c 5 UNKNOWN: Please also set a warning value when using warning/critical thresholds! user@host $ ./check_apache2.py -H localhost -p 7002 CRITICAL: Couldn't fetch the server's status page. Please check given hostname, port or Apache's configuration. We might not be allowed to access server-status due to your server's configuration.
The License
As always this little script is ment to be sh-compliant and released under the terms of the GPL Version 2 only. Feel free to subscribe via rss to get updates on this one. More options will be added in the future.
Add your comment below, or trackback from your own site.
Subscribe to these comments.
Be nice. Keep it clean. Stay on topic. No spam.
You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">