Skip to content

Instantly share code, notes, and snippets.

@lottspot
Last active October 1, 2015 05:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lottspot/987c630941226c80bee1 to your computer and use it in GitHub Desktop.
Save lottspot/987c630941226c80bee1 to your computer and use it in GitHub Desktop.
A nagios-like HTTP check which can import a python callable to handle a critical threshold
#!/usr/bin/python
import Queue
import threading
import time
import sys, os
from urllib import urlopen
import logger
# check_http.py
# $1: SCHEME
# $2: HOST
# $3: TIMEOUT
# $4: RETRY
# $5: CHECK_STRING
MAX_FAILURES = 3
LOG_FILES = (
# Must be specified in LogLevel order
sys.stdout,
)
ACTION_MODULE = ''
ACTION_CALL = ''
ACTION_IS_DEFINED = False
take_action = lambda: None
if ACTION_MODULE is not None and ACTION_CALL is not None and len(ACTION_MODULE) > 0 and len(ACTION_CALL) > 0:
ACTION_IS_DEFINED = True
take_action = getattr(__import__(ACTION_MODULE, fromlist=['']), ACTION_CALL)
class CheckThread(threading.Thread):
def __init__(self, queue, scheme, host, check_string):
self.q = queue
self.scheme = scheme
self.host = host
self.check_string = check_string
threading.Thread.__init__(self)
def run(self):
try:
doc = urlopen('%s://%s' % (self.scheme, self.host)).read()
if self.check_string is not None:
if self.check_string not in doc:
self.q.put(0)
sys.exit(0)
self.q.put(1)
sys.exit(0)
except IOError:
self.q.put(-1)
sys.exit(1)
def do_http_check(scheme, host, timeout, check_string=None):
msgq = Queue.Queue(0)
thread = CheckThread(msgq, scheme, host, check_string)
thread.start()
try:
return msgq.get(timeout=timeout)
except Queue.Empty:
return -2
if __name__ == '__main__':
pid = os.fork()
if pid:
# enter parent
sys.exit('%s forked with PID %s' % (sys.argv[0], pid))
else:
# enter child
min_args = 5
if len(sys.argv) < min_args:
sys.exit(1)
SCHEME = sys.argv[1]
HOST = sys.argv[2]
TIMEOUT = int(sys.argv[3])
RETRY = int(sys.argv[4])
CHECK_STRING = None
if len(sys.argv) > min_args:
# The value of CHECK_STRING is always the final argument
CHECK_STRING = sys.argv[min_args]
failures = 0
logfile = logger.LogFile(*LOG_FILES)
log = logger.Logger(logfile)
level = logger.LogLevel
while True:
result = do_http_check(SCHEME, HOST, TIMEOUT, CHECK_STRING)
if result == -2:
log(level.WARN, 'WARNING - %s : %d second timeout' % (HOST, TIMEOUT))
failures += 1
elif result == -1:
log(level.WARN, 'WARNING - %s : Error receiving HTTP response' % HOST)
failures += 1
elif result == 0:
log(level.WARN, 'WARNING - %s : \'%s\' not in response' % (HOST, CHECK_STRING))
failures += 1
else:
log(level.INFO, 'OK - %s' % HOST)
failures = 0
if failures >= MAX_FAILURES:
action_str = ''
if ACTION_IS_DEFINED:
action_str = ' -- Calling %s.%s' % (ACTION_MODULE, ACTION_CALL)
log(level.ERROR, 'CRITICAL - %s : %d consecutive failures (RETRY=%d)%s' % (HOST, failures, RETRY, action_str))
take_action()
failures = 0
time.sleep(RETRY)
import os, time, socket
class LogLevel:
MAX_LEVEL = 4
NONE, INFO, WARN, ERROR = range(MAX_LEVEL)
class LogFile(object):
def __init__(self, *args):
self.level = LogLevel.NONE
self.log = [ None for i in range(LogLevel.MAX_LEVEL) ]
self.log[LogLevel.NONE] = open(os.devnull, 'w')
i = 0
end_args = len(args)
while i < end_args:
arg = args[i]
log_level = i + 1
if isinstance(arg, file): self.log[log_level] = arg
if isinstance(arg, str) and len(arg) > 0: self.log[log_level] = open(arg, 'a')
if hasattr(arg, 'sendall'): self.log[log_level] = arg
i += 1
last_file = self.log[i]
while i < LogLevel.MAX_LEVEL:
self.log[i] = last_file
i += 1
self.is_active = True
def set_level(self, level):
self.level = level
def get_level(self):
return self.level
def write(self, string):
log = self.log[self.level]
if hasattr(log, 'sendall'):
log.sendall(string)
addr = log.getpeername()
log.close()
log = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
log.connect(addr)
self.log[self.level] = log
log = None
if log is not None:
log.write(string)
log.flush()
return
def close(self):
for i in range(LogLevel.MAX_LEVEL):
log = self.log[i]
if hasattr(log, 'close'): log.close()
class Logger(object):
def __init__(self, LogFile, Lock=None):
self.file = LogFile
self.lock = Lock
def log(self, level, msg):
if hasattr(self.lock, 'acquire'):
self.lock.acquire()
t = time.localtime()
yr, mon, day, hr, min, sec = [ t[i] for i in range(6) ]
prefix = '[%04d-%02d-%02d %02d:%02d:%02d]' % (yr, mon, day, hr, min, sec)
self.barelog(level, msg, prefix)
if hasattr(self.lock, 'release'):
self.lock.release()
def barelog(self, level, msg, msg_prefix=''):
msg = '%s %s\n' % (msg_prefix, msg)
logfile = self.file
logfile.set_level(level)
logfile.write(msg)
def new_file_set(self, *args):
if hasattr(self.lock, 'acquire'):
self.lock.acquire()
logfile = self.file
logfile.close()
LogFile.__init__(logfile, *args)
if hasattr(self.lock, 'release'):
self.lock.release()
def __call__ (self, level, msg):
return self.log(level, msg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment