Since I knew the App Engine Mail API was super easy to configure, I figured I would just email myself every time there was an exception, before serving my default 500 error page. To do so, I just needed to subclass the default RequestHandler with my own handle_exception method. (OK, prepare yourselves, a bunch of code is about to happen. See the necessary imports at the bottom of the post.)
class ExtendedHandler(RequestHandler): def handle_exception(self, exception, debug_mode): traceback_info = ''.join(format_exception(*sys.exc_info())) email_admins(traceback_info, defer_now=True) serve_500(self)Awesome! By making all my handlers inherit from ExtendedHandler, I can use the native Python modules traceback and sys to get the traceback and my handy dandy
def email_admins(error_msg, defer_now=False): if defer_now: defer(email_admins, error_msg, defer_now=False) return sender = 'YOUR APP Errors <errors@your_app_id_here.appspotmail.com>' to = 'Robert Admin <email@example.com>, James Nekbehrd <firstname.lastname@example.org>' subject = 'YOUR APP Error: Admin Notify' body = '\n'.join(['Dearest Admin,', '', 'An error has occurred in YOUR APP:', error_msg, '']) mail.send_mail(sender=sender, to=to, subject=subject, body=body)to send out the email in the deferred queue** so as not to hold up the handler serving the page. Mission accomplished, right? WRONG!
Unfortunately, handle_exception only handles the "right" kind of exceptions. That is, exceptions which inherit directly from Python's Exception. From the horse's mouth:
Exceptions should typically be derived from the Exception class, either directly or indirectly.But. But! If the app fails because a request times out, a DeadlineExceededError is thrown and handle_exception falls on its face. Why? Because DeadlineExceededError inherits directly from Exception's parent class: BaseException. (Gasp)
It's OK little ones, in my next post I explain how I did it while keeping my code Pythonic by using metaclasses.
from google.appengine.api import mail from google.appengine.ext.deferred import defer from google.appengine.ext.webapp import RequestHandler import sys from traceback import format_exception from SOME_APP_SPECIFIC_LIBRARY import serve_500*Pythonic:
An idea or piece of code which closely follows the most common idioms of the Python language, rather than implementing code using concepts common to other languages.**Deferred Queue: Make sure to enable the deferred library in your app.yaml by using deferred: on in your builtins. About Bossy Lobster