Created
November 5, 2012 15:46
-
-
Save tmacam/4017891 to your computer and use it in GitHub Desktop.
Python decarator that sends backtraces via POST to a remote server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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