#!/usr/bin/env python from email.mime.text import MIMEText import os import re import socket import sys import subprocess import time import threading # Add the email address to be notified here. EMAIL_TO = ', '.join([ 'Root ', ]) class Matcher(object): def __init__(self): self.lastseen = 0 self.regexp = re.compile(r'\((\d+): (.*?)\)') self.timeframe = 20 def __call__(self, line): now = time.time() if (now - self.lastseen) > self.timeframe: if ('104: Connection reset by peer' in line) or \ ('111: Connection refused' in line): match = self.regexp.search(line) if match: # sendmail(self.get_message(match)) self.lastseen = time.time() return match def get_message(self, match): hostname = socket.gethostname() message = 'PHP/FastCGI instance on %s is detected dead.\n\n%s' % \ (hostname, match.group(0)) message = MIMEText(message) message['From'] = 'Root ' % (hostname, hostname) message['To'] = EMAIL_TO message['Subject'] = 'Broken PHP detected - %s' % hostname return message class Processor(object): def __init__(self): self.thread = None self.restart = None def __call__(self, matched): if self.thread is None: self.thread = threading.Thread(target=self.run) self.thread.setDaemon(True) self.thread.start() def get_message(self): hostname = socket.gethostname() message = 'PHP/FastCGI instance on %s has been restarted.' % hostname message = MIMEText(message) message['From'] = 'Root ' % (hostname, hostname) message['To'] = EMAIL_TO message['Subject'] = 'PHP restarted - %s' % hostname return message def run(self): initscript = '/etc/init.d/php-fastcgi/' if not os.path.exists(initscript): initscript = '/etc/init.d/php-fastcgi' try: try: subprocess.call(['killall', '-9', 'php5-cgi']) time.sleep(1) subprocess.call([initscript, 'start']) # sendmail(self.get_message()) except Exception, ex: pass finally: self.thread = None def call_devnull(args): proc = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.STDOUT) return proc.wait() def daemonize(): pid = os.fork() if pid == 0: os.setsid() pid = os.fork() if pid == 0: os.chdir('/') os.umask(0) else: os._exit(0) else: os._exit(0) import resource maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] if maxfd == resource.RLIM_INFINITY: maxfd = 1024 for fd in range(0, maxfd): try: os.close(fd) except OSError: pass os.open(os.devnull, os.O_RDWR) os.dup2(0, 1) os.dup2(0, 2) #def sendmail(message): # proc = subprocess.Popen(['/usr/lib/sendmail', '-t'], stdin=subprocess.PIPE) # proc.stdin.write(message.as_string()) # proc.stdin.close() # proc.wait() def main(filename, match, action): try: for line in tailf(filename): matchobj = match(line) if matchobj: action(matchobj) except KeyboardInterrupt: pass def tailf(filename): import cStringIO import os import time lastsize = os.path.getsize(filename) while True: size = os.path.getsize(filename) if size > lastsize: fobj = open(filename, 'r') fobj.seek(lastsize) data = fobj.read(size - lastsize) fobj.close() data = cStringIO.StringIO(data) for line in data: yield line lastsize = size if size < lastsize: lastsize = 0 else: time.sleep(2.0) if __name__ == '__main__': daemonize() filename = sys.argv[1] if len(sys.argv) > 1 else '/var/log/nginx/error.log' main(filename, Matcher(), Processor())