After spending a nontrivial amount of my nights and weekends working on an App Engine app, I wanted a good way to monitor the logs without checking in on them every day. After a particularly frustrating weekend of updates that exposed unnoticed bugs that had yet to be triggered by the app, I set out to find such a way. I set out to find a Pythonic way.
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
with my own
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
I can use the native Python modules
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 <[email protected]_app_id_here.appspotmail.com>' to = 'Robert Admin <[email protected]>, James Nekbehrd <[email protected]>' 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 as not to hold up the handler serving the page. Mission accomplished, right? WRONG!
Exceptions should typically be derived from the
Exceptionclass, 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
Exception's parent class:
from google.appengine.api import mail from google.appengine.ext.deferred import defer from google.appengine.ext.webapp import RequestHandler import sysfrom traceback import format_exception from SOME_APP_SPECIFIC_LIBRARY import serve_500
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.
Make sure to enable the deferred library in your
deferred: on in your builtins.