There is probably a better way to do this, but I was able to throw this together in about two minutes, and I’m writing this here so I can easily reference it no matter where I am. I’ve been writing a lot of REST apis using Django lately, and I need a way to save the exceptions and stack traces to the logs while not giving out too much information to the callers. I can’t use the automatic email admins functionality because the servers are locked down and not allowed to send email. Adding try/except’s to the existing functions and new ones feels ugly and painful. So I’m going with the following decorator. This one just passes the exception through – you’ll want to figure out if that is the right thing for you to do.

def wrap_ex(fn):
    """ Wraps the api function in an exception log. """
    def _dec(view_func):
        def _wrapit(request, *args, **kwargs):
            try:
                return view_func(request, *args, **kwargs)
            except:
                # log
                cla, exc, trbk = sys.exc_info()
                extb = traceback.format_tb(trbk)
                logging.error(u'An error occurred '+unicode(cla)+u': '+unicode(exc)+ u' tb='+unicode(extb))
                raise
        _wrapit.__doc__ = view_func.__doc__
        _wrapit.__dict__ = view_func.__dict__
        return _wrapit
    return _dec(fn)

Usage:

@wrap_ex
@api_login_required
def api_1_0_calculate(request):
    return JsonResponse(...)