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 <bob@example.com>, James Nekbehrd <jim@example.com>'
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.
Imports:
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.
No comments:
New comments are not allowed.