StevenWung
12/17/2010 - 2:50 AM

Supervisor event listener that emails on a proces writing to stderr

Supervisor event listener that emails on a proces writing to stderr

#!/usr/bin/env python

import os
import smtplib
import sys
import time
from optparse import OptionParser

from supervisor import childutils

class ErrorMailer(object):
    def __init__(self, address, processes=None):
        self.address = address
        self.processes = processes
        self.stdin = sys.stdin
        self.stdout = sys.stdout
        self.mailcmd = "mail"

    def run(self):
        last_email = {}
        while True:
            headers, payload = childutils.listener.wait(self.stdin, self.stdout)

            if headers['eventname'] not in ('PROCESS_STATE_EXITED', 'PROCESS_LOG_STDERR'):
                childutils.listener.ok(self.stdout)
                continue

            if headers['eventname'] == 'PROCESS_STATE_EXITED':
                pheaders, pdata = childutils.eventdata(payload+'\n')

                if int(pheaders['expected']):
                    childutils.listener.ok(self.stdout)
                    continue

                msg = ('Process %(processname)s in group %(groupname)s exited '
                       'unexpectedly (pid %(pid)s) from state %(from_state)s' %
                       pheaders)
            
                subject = ' %s crashed at %s' % (pheaders['processname'],
                                                 childutils.get_asctime())

                # self.stderr.write('unexpected exit, mailing\n')
                # self.stderr.flush()

                self.mail(subject, msg)

                childutils.listener.ok(self.stdout)
            else: # PROCESS_LOG_STDERR
                pheaders, pdata = childutils.eventdata(payload)

                name = pheaders['processname']
                now = time.time()
                if now - last_email.get(name, 0) < 30:
                    childutils.listener.ok(self.stdout)
                    continue
                last_email[name] = now

                subject = ('Process %(processname)s in group %(groupname)s wrote to stderr'
                       % pheaders)

                # self.stderr.write('wrote to stderr, mailing\n')
                # self.stderr.flush()

                self.mail(subject, pdata.strip())

                childutils.listener.ok(self.stdout)

    def mail(self, subject, msg):
        fromaddress = "root@localhost"
        body = "\r\n".join((
            "From: %s" % fromaddress,
            "To: %s" % self.address,
            "Subject: %s" % subject,
            "",
            msg,
        ))
        server = smtplib.SMTP('localhost')
        server.sendmail(fromaddress, [self.address], body)
        server.quit()

def build_parser():
    parser = OptionParser(usage="Usage: %prog [options]")
    parser.add_option("-p", "--process", dest="processes", help="Process name", action="append")
    parser.add_option("-m", "--address", dest="address", help="Email address")
    return parser

def main():
    parser = build_parser()
    options, system = parser.parse_args()
    if not options.address:
        parser.error("must specify an email address")

    prog = ErrorMailer(processes=options.processes, address=options.address)
    prog.run()

if __name__ == '__main__':
    main()