Skip to content

Instantly share code, notes, and snippets.

@tmacam
Created November 5, 2012 15:46
Show Gist options
  • Save tmacam/4017891 to your computer and use it in GitHub Desktop.
Save tmacam/4017891 to your computer and use it in GitHub Desktop.
Python decarator that sends backtraces via POST to a remote server
#!/usr/bin/env python -u
# vim:ts=4:sts=4:sw=4:et:wrap:ai:fileencoding=utf-8:
"""Decorator to log a function's backtrace to a remote server.
Based on client/backtrace.py
from http://github.com/tmacam/DistributedCrawler.
"""
from functools import wraps
import json
import StringIO
import sys
import traceback
import urllib
import urllib2
__all__ = ('backtrace_logged', 'exceptions_stripped')
__version__ = "0.4.engine"
__date__ = '2012-11-05 13:19:24 -0200 (Mon, 05 Nov 2012)'
__author__ = "Tiago Alves Macambira"
__copyright__ = 'Copyright (c) 2012 Tiago Alves Macambira'
__license__ = 'X11'
__url__ = 'git://gist.github.com/4017891.git'
def exceptions_stripped(fn):
"""Strips and consumes any exception fn may raise."""
@wraps(fn)
def wrapper_fn(*args, **kwds):
try:
return fn(*args, **kwds)
except:
pass
return wrapper_fn
@exceptions_stripped
def __post_backtrace(url, backtrace_str, extras=None):
form_data = {'backtrace': backtrace_str}
if extras:
form_data.update(extras)
try:
headers = {'Content-Type': 'application/json'}
data = json.dumps(form_data)
except:
# Let's hope form-encoding is more permisive...
headers = None
data = urllib.urlencode(form_data)
req = urllib2.Request(url, data, headers)
res = urllib2.urlopen(req)
res.read()
res.close()
@exceptions_stripped
def __collect_and_log_backtrace(log_to_stderr, log_to_url, extras=None):
# Get backtrace information from stack
backtrace_fn = StringIO.StringIO()
traceback.print_exc(file=backtrace_fn)
backtrace_str = backtrace_fn.getvalue()
# Print and forward the backtrace as requested
if log_to_stderr:
sys.stderr.write("ERROR! BACKTRACE FOLLOWS:\n")
sys.stderr.write(backtrace_str)
sys.stderr.write("\n")
if log_to_url:
__post_backtrace(log_to_url, backtrace_str, extras)
def backtrace_logged(log_to_stderr=True, log_to_url=None, extras=None):
"""Decorator to log a function's backtrace to a remote server.
Args:
log_to_stderr: Whether we should print the backtrace to the stderr.
Defaults to true.
log_to_url: If not None, we will do a POST request of the backtrace
to the provided URL.
extras: dict with extra string values to be sent along backtrace
data in a POST request to `log_to_url`.
"""
def backtrace_wraper(fn):
@wraps(fn)
def new_func(*args, **kwds):
try:
return fn(*args, **kwds)
except:
__collect_and_log_backtrace(log_to_stderr, log_to_url, extras)
# Bubble up the exception
raise
return new_func
return backtrace_wraper
def main():
@backtrace_logged(log_to_stderr=True,
log_to_url="http://localhost:8700/backtrace")
def just_fail():
raise TypeError("Duh!!!")
just_fail()
print "Done"
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment