From ec71a8463ca092367847d6bfc40c20805b3cdb29 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Fri, 10 Aug 2012 22:44:43 -0700 Subject: [PATCH] add errors module (sys.excepthook), made win32 filemon use it --- edbob/errors.py | 72 +++++++++++++++++++++++++++++++++++ edbob/filemon/win32_server.py | 37 ++++++++++++++++-- 2 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 edbob/errors.py diff --git a/edbob/errors.py b/edbob/errors.py new file mode 100644 index 0000000..66a1ab6 --- /dev/null +++ b/edbob/errors.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +################################################################################ +# +# edbob -- Pythonic Software Framework +# Copyright © 2010-2012 Lance Edgar +# +# This file is part of edbob. +# +# edbob is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# edbob 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 Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with edbob. If not, see . +# +################################################################################ + +""" +``edbob.errors`` -- Error Alert Emails +""" + +import sys +import socket +import logging +from traceback import format_exception +from cStringIO import StringIO + +import edbob +from edbob.mail import sendmail_with_config + + +log = logging.getLogger(__name__) + + +def init(config): + """ + Creates a system-wide exception hook which logs exceptions and emails them + to configured recipient(s). + """ + + def excepthook(type, value, traceback): + log.exception("An exception occurred") + email_exception(type, value, traceback) + sys.__excepthook__(type, value, traceback) + + sys.excepthook = excepthook + + +def email_exception(type, value, traceback): + """ + Sends an email containing a traceback to the configured recipient(s). + """ + + body = StringIO() + + hostname = socket.gethostname() + body.write("An exception occurred.\n") + body.write("\n") + body.write("Machine Name: %s (%s)\n" % (hostname, socket.gethostbyname(hostname))) + body.write("Local Time: %s\n" % (edbob.local_time().strftime('%Y-%m-%d %H:%M:%S %Z%z'))) + body.write("\n") + body.write("%s\n" % ''.join(format_exception(type, value, traceback))) + + sendmail_with_config('errors', body.getvalue()) + body.close() diff --git a/edbob/filemon/win32_server.py b/edbob/filemon/win32_server.py index 8e5c150..03e5c0a 100644 --- a/edbob/filemon/win32_server.py +++ b/edbob/filemon/win32_server.py @@ -27,16 +27,17 @@ """ import os.path +import sys import socket import time import Queue +from traceback import format_exception import edbob from edbob.filemon import MonitorProfile from edbob.filemon.win32 import WatcherWin32, ACTION_CREATE, ACTION_UPDATE from edbob.win32 import file_is_free -import sys if sys.platform == 'win32': # docs should build for everyone import win32serviceutil import win32service @@ -94,8 +95,9 @@ class FileMonitorService(win32serviceutil.ServiceFramework): except Queue.Empty: pass else: - if ftype == 'file' and action in ( - ACTION_CREATE, ACTION_UPDATE): + # if ftype == 'file' and action in ( + # ACTION_CREATE, ACTION_UPDATE): + if ftype == 'file' and action == ACTION_CREATE: self.do_actions(key, fpath) win32api.SleepEx(250, True) @@ -118,7 +120,34 @@ class FileMonitorService(win32serviceutil.ServiceFramework): func = action args = [] func = edbob.load_spec(func) - func(path, *args) + + try: + func(path, *args) + except: + + exc_info = sys.exc_info() + + # Call the system exception hook in case anything special has + # been registered there, e.g. if edbob.errors.init() has + # happened. Note that this is especially necessary since + # PythonService.exe doesn't seem to honor sys.excepthook. + sys.excepthook(*exc_info) + + # Go ahead and write exception info to the Windows Event Log + # while we're at it. + msg = "File monitor action failed.\n" + msg += "\n" + msg += "Profile: %s\n" % key + msg += "Action: %s\n" % action + msg += "File Path: %s\n" % path + msg += "\n" + msg += ''.join(format_exception(*exc_info)) + servicemanager.LogErrorMsg(msg) + + # Don't re-raise the exception since the service should + # continue running despite any problems it encounters. But + # this file probably shouldn't be processed any further. + break if __name__ == '__main__':