def _ride_the_toad(payload, timeout, use_ssl): """Send a notification (an HTTP POST request) to Hoptoad. Parameters: payload -- the XML payload for the request from _generate_payload() timeout -- the maximum timeout, in seconds, or None to use the default """ headers = {'Content-Type': 'text/xml'} url_template = '%s://hoptoadapp.com/notifier_api/v2/notices' notification_url = url_template % ("https" if use_ssl else "http") # allow the settings to override all urls notification_url = get_hoptoad_settings().get('HOPTOAD_NOTIFICATION_URL', notification_url) r = urllib2.Request(notification_url, payload, headers) try: if timeout: # timeout is 2.6 addition! response = urllib2.urlopen(r, timeout=timeout) else: response = urllib2.urlopen(r) except urllib2.URLError: logger.exception("Caught an exception while delivering payload " "to hoptoad! Discarding..") else: try: # getcode is 2.6 addition!! status = response.getcode() except AttributeError: # default to just code status = response.code logger.debug("Returned %s from hoptoad", status) if status == 403 and use_ssl: if get_hoptoad_settings().get('HOPTOAD_NO_SSL_FALLBACK', False): # if we can not use SSL, re-invoke w/o using SSL _ride_the_toad(payload, timeout, use_ssl=False) if status == 403 and not use_ssl: # we were not trying to use SSL but got a 403 anyway # something else must be wrong (bad API key?) logger.warning( "We weren't using any SSL, but received a " "%s anyway! Maybe bad API key?", status) if status == 422: # couldn't send to hoptoad.. logger.warning("Couldn't send payload to hoptoad!") if status == 500: # hoptoad is down logger.critical("Hoptoad is down! Can't send payload..discarding.")
def _ride_the_toad(payload, timeout, use_ssl): """Send a notification (an HTTP POST request) to Hoptoad. Parameters: payload -- the XML payload for the request from _generate_payload() timeout -- the maximum timeout, in seconds, or None to use the default """ headers = {'Content-Type': 'text/xml'} url_template = '%s://hoptoadapp.com/notifier_api/v2/notices' notification_url = url_template % ("https" if use_ssl else "http") # allow the settings to override all urls notification_url = get_hoptoad_settings().get('HOPTOAD_NOTIFICATION_URL', notification_url) r = urllib2.Request(notification_url, payload, headers) try: if timeout: # timeout is 2.6 addition! response = urllib2.urlopen(r, timeout=timeout) else: response = urllib2.urlopen(r) except urllib2.URLError: logger.exception("Caught an exception while delivering payload " "to hoptoad! Discarding..") else: try: # getcode is 2.6 addition!! status = response.getcode() except AttributeError: # default to just code status = response.code logger.debug("Returned %s from hoptoad", status) if status == 403 and use_ssl: if get_hoptoad_settings().get('HOPTOAD_NO_SSL_FALLBACK', False): # if we can not use SSL, re-invoke w/o using SSL _ride_the_toad(payload, timeout, use_ssl=False) if status == 403 and not use_ssl: # we were not trying to use SSL but got a 403 anyway # something else must be wrong (bad API key?) logger.warning("We weren't using any SSL, but received a " "%s anyway! Maybe bad API key?", status) if status == 422: # couldn't send to hoptoad.. logger.warning("Couldn't send payload to hoptoad!") if status == 500: # hoptoad is down logger.critical("Hoptoad is down! Can't send payload..discarding.")
def _ride_the_toad(payload, timeout, use_ssl): """Send a notification (an HTTP POST request) to Hoptoad. Parameters: payload -- the XML payload for the request from _generate_payload() timeout -- the maximum timeout, in seconds, or None to use the default """ headers = { 'Content-Type': 'text/xml' } url_template = '%s://hoptoadapp.com/notifier_api/v2/notices' notification_url = url_template % ("https" if use_ssl else "http") # allow the settings to override all urls notification_url = get_hoptoad_settings().get('HOPTOAD_NOTIFICATION_URL', notification_url) r = urllib2.Request(notification_url, payload, headers) try: if timeout: # timeout is 2.6 addition! response = urllib2.urlopen(r, timeout=timeout) else: response = urllib2.urlopen(r) except urllib2.URLError, err: pass
def test_api_key_present(self): """Test to make sure an API key is present.""" hoptoad_settings = get_hoptoad_settings() self.assertTrue('HOPTOAD_API_KEY' in hoptoad_settings, msg='The HOPTOAD_API_KEY setting is not present.') self.assertTrue(hoptoad_settings['HOPTOAD_API_KEY'], msg='The HOPTOAD_API_KEY setting is blank.')
def enqueue(self, payload, timeout): use_ssl = get_hoptoad_settings().get('HOPTOAD_USE_SSL', False) rpc = urlfetch.create_rpc(timeout) # this would be beneficial if there was eg. a middleware tracking # rpcs and waiting on them # rpc.callback = lambda: htv2._aftermath(rpc, (payload, urlfetch.create_rpc(timeout)), use_ssl) if self._debug: logging.debug("hoptoad: AsyncNotifier.enqueue") htv2._ride_the_toad(payload, rpc, use_ssl)
def __init__(self): """Initialize the middleware.""" hoptoad_settings = get_hoptoad_settings() if len(hoptoad_settings) == 0: raise MiddlewareNotUsed self._init_middleware(hoptoad_settings)
def _aftermath(rpc, retry, use_ssl): debug = get_hoptoad_settings().get('HOPTOAD_DEBUG', False) try: response = rpc.get_result() except DownloadError, err: if debug: logging.debug(err, exc_info=1) logging.debug("hoptoad: failed to send notification")
def _ride_the_toad(payload, rpc, use_ssl): """Send a notification (an HTTP POST request) to Hoptoad. Parameters: payload -- the XML payload for the request from _generate_payload() rpc -- AppEngine RPC object for urlfetch """ headers = { 'Content-Type': 'text/xml' } url_template = '%s://hoptoadapp.com/notifier_api/v2/notices' notification_url = url_template % ("https" if use_ssl else "http") # allow the settings to override all urls notification_url = get_hoptoad_settings().get('HOPTOAD_NOTIFICATION_URL', notification_url) debug = get_hoptoad_settings().get('HOPTOAD_DEBUG', False) if debug: logging.debug("hoptoad: submitting notification") urlfetch.make_fetch_call(rpc=rpc, url=notification_url, payload=payload, method=urlfetch.POST, headers=headers)
def get_handler(*args, **kwargs): """Returns an initialized handler object""" hoptoad_settings = get_hoptoad_settings() handler = hoptoad_settings.get('HOPTOAD_HANDLER', 'async') if handler.lower() == 'async': return AsyncNotifier(*args, **kwargs) elif handler.lower() == 'deferred': queue = hoptoad_settings.get('HOPTOAD_DEFERRED_QUEUE', _DEFAULT_QUEUE) return DeferredNotifier(queue, *args, **kwargs) elif handler.lower() == 'blocking': return BlockingNotifier(*args, **kwargs) else: _module_name, _class_name = handler.rsplit('.', 1) _module = import_module(_module_name) _class = getattr(_module, _class_name) return _class(*args, **kwargs)
def get_handler(*args, **kwargs): """Returns an initialized handler object""" hoptoad_settings = get_hoptoad_settings() handler = hoptoad_settings.get("HOPTOAD_HANDLER", "threadpool") if handler.lower() == 'threadpool': threads = hoptoad_settings.get("HOPTOAD_THREAD_COUNT", 4) return ThreadedNotifier(threads, *args, **kwargs) elif handler.lower() == 'blocking': return BlockingNotifier(*args, **kwargs) else: _class_module = hoptoad_settings.get('HOPTOAD_HANDLER_CLASS', None) if not _class_module: # not defined, abort setting up hoptoad, skip it. raise MiddlewareNotUsed # module name that we should import from _module_name = os.path.splitext(os.path.basename(handler))[0] # load the module! m = imp.load_module(_module_name, *imp.find_module(_module_name, [os.path.dirname(handler)])) # instantiate the class return getattr(m, _class_module)(*args, **kwargs)
def get_handler(*args, **kwargs): """Returns an initialized handler object""" hoptoad_settings = get_hoptoad_settings() handler = hoptoad_settings.get("HOPTOAD_HANDLER", "threadpool") if handler.lower() == 'threadpool': threads = hoptoad_settings.get("HOPTOAD_THREAD_COUNT", 4) return ThreadedNotifier(threads, *args, **kwargs) elif handler.lower() == 'blocking': return BlockingNotifier(*args, **kwargs) else: _class_module = hoptoad_settings.get('HOPTOAD_HANDLER_CLASS', None) if not _class_module: # not defined, abort setting up hoptoad, skip it. raise MiddlewareNotUsed # module name that we should import from _module_name = os.path.splitext(os.path.basename(handler))[0] # load the module! m = imp.load_module( _module_name, *imp.find_module(_module_name, [os.path.dirname(handler)])) # instantiate the class return getattr(m, _class_module)(*args, **kwargs)
def report(payload, timeout): use_ssl = get_hoptoad_settings().get('HOPTOAD_USE_SSL', False) return _ride_the_toad(payload, timeout, use_ssl)
def __init__(self): self._debug = get_hoptoad_settings().get('HOPTOAD_DEBUG', False)
def report(payload, timeout): use_ssl = get_hoptoad_settings().get('HOPTOAD_USE_SSL', False) rpc = urlfetch.create_rpc(timeout) _ride_the_toad(payload, rpc, use_ssl) _aftermath(rpc, (payload, urlfetch.create_rpc(timeout)), use_ssl)
import traceback import urllib2 from django.views.debug import get_safe_settings from django.conf import settings from hoptoad import get_hoptoad_settings PROTECTED_PARAMS = frozenset(get_hoptoad_settings() .get('HOPTOAD_PROTECTED_PARAMS', [])) def _parse_environment(request): """Return an environment mapping for a notification from the given request. """ env = dict((str(k), str(v)) for (k, v) in get_safe_settings().items()) env.update(dict((str(k), str(v)) for (k, v) in request.META.items())) env['REQUEST_URI'] = request.build_absolute_uri() return env def _parse_traceback(trace): """Return the given traceback string formatted for a notification.""" p_traceback = ["%s:%d:in '%s'" % (filename, lineno, funcname) for filename, lineno, funcname, _
def generate_payload(request_tuple): """Generate an XML payload for a Hoptoad notification. Parameters: request_tuple -- A tuple containing a Django HTTPRequest and a possible response code. """ request, response = request_tuple hoptoad_settings = get_hoptoad_settings() p_error_class, p_message = _handle_errors(request, response) # api v2 from: http://help.hoptoadapp.com/faqs/api-2/notifier-api-v2 xdoc = getDOMImplementation().createDocument(None, "notice", None) notice = xdoc.firstChild # /notice/@version -- should be 2.0 notice.setAttribute('version', '2.0') # /notice/api-key api_key = xdoc.createElement('api-key') api_key_data = xdoc.createTextNode(hoptoad_settings['HOPTOAD_API_KEY']) api_key.appendChild(api_key_data) notice.appendChild(api_key) # /notice/notifier/name # /notice/notifier/version # /notice/notifier/url notifier = xdoc.createElement('notifier') for key, value in zip(["name", "version", "url"], [NAME, VERSION, URL]): key = xdoc.createElement(key) value = xdoc.createTextNode(str(value)) key.appendChild(value) notifier.appendChild(key) notice.appendChild(notifier) # /notice/error/class # /notice/error/message error = xdoc.createElement('error') for key, value in zip(["class", "message"], [p_error_class, p_message]): key = xdoc.createElement(key) value = xdoc.createTextNode(value) key.appendChild(value) error.appendChild(key) # /notice/error/backtrace/error/line backtrace = xdoc.createElement('backtrace') # i do this here because I'm afraid of circular reference.. reversed_backtrace = list( reversed(traceback.extract_tb(sys.exc_info()[2])) ) if reversed_backtrace: for filename, lineno, funcname, text in reversed_backtrace: line = xdoc.createElement('line') line.setAttribute('file', str(filename)) line.setAttribute('number', str(lineno)) line.setAttribute('method', str(funcname)) backtrace.appendChild(line) else: line = xdoc.createElement('line') line.setAttribute('file', 'unknown') line.setAttribute('number', '0') line.setAttribute('method', 'unknown') backtrace.appendChild(line) error.appendChild(backtrace) notice.appendChild(error) # /notice/request xrequest = xdoc.createElement('request') # /notice/request/url -- request.build_absolute_uri() xurl = xdoc.createElement('url') xurl_data = xdoc.createTextNode(request.build_absolute_uri()) xurl.appendChild(xurl_data) xrequest.appendChild(xurl) # /notice/request/component -- not sure.. comp = xdoc.createElement('component') #comp_data = xdoc.createTextNode('') xrequest.appendChild(comp) # /notice/request/action -- action which error occured # ... no f*****g clue.. # sjl: "actions" are the Rails equivalent of Django's views # Is there a way to figure out which view a request object went to # (if any)? Anyway, it's not GET/POST so I'm commenting it for now. #action = xdoc.createElement('action') # maybe GET/POST?? #action_data = u"%s %s" % (request.method, request.META['PATH_INFO']) #action_data = xdoc.createTextNode(action_data) #action.appendChild(action_data) #xrequest.appendChild(action) # /notice/request/params/var -- check request.GET/request.POST req_params = _parse_request(request).items() if req_params: params = xdoc.createElement('params') for key, value in req_params: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value)) var.appendChild(value) params.appendChild(var) xrequest.appendChild(params) # /notice/request/session/var -- check if sessions is enabled.. sessions = xdoc.createElement('session') for key, value in _parse_session(request.session).iteritems(): var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value)) var.appendChild(value) sessions.appendChild(var) xrequest.appendChild(sessions) # /notice/request/cgi-data/var -- all meta data cgidata = xdoc.createElement('cgi-data') for key, value in _parse_environment(request).iteritems(): var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value)) var.appendChild(value) cgidata.appendChild(var) xrequest.appendChild(cgidata) notice.appendChild(xrequest) # /notice/server-environment serverenv = xdoc.createElement('server-environment') # /notice/server-environment/project-root -- default to sys.path[0] projectroot = xdoc.createElement('project-root') projectroot.appendChild(xdoc.createTextNode(sys.path[0])) serverenv.appendChild(projectroot) # /notice/server-environment/environment-name -- environment name? wtf.. envname = xdoc.createElement('environment-name') # no idea... # sjl: This is supposed to be set to something like "test", "staging", # or "production" to help you group the errors in the web interface. # I'm still thinking about the best way to support this. # bmjames: Taking this from a settings variable. I personally have a # different settings.py for every environment and my deploy # script puts the correct one in place, so this makes sense. # But even if one had a single settings.py shared among # environments, it should be possible to set this variable # dynamically. It would simply be the responsibility of # settings.py to do it, rather than the hoptoad middleware. envname_text = hoptoad_settings.get('HOPTOAD_ENV_NAME', 'Unknown') envname_data = xdoc.createTextNode(envname_text) envname.appendChild(envname_data) serverenv.appendChild(envname) notice.appendChild(serverenv) return xdoc.toxml('utf-8')
def generate_payload(request, response=None, exception=None): """Generate an XML payload for a Hoptoad notification. Arguments: - `request`: The Django request object - `response`: Optional. Response code that was received from the webserver - `exception`: Optional. Can be a custom exception that implements __str__ and has the class name of the error that is required to be reported. """ hoptoad_settings = get_hoptoad_settings() p_error_class, p_message = _handle_errors(request, response, exception) # api v2 from: http://help.hoptoadapp.com/faqs/api-2/notifier-api-v2 xdoc = getDOMImplementation().createDocument(None, "notice", None) notice = xdoc.firstChild # /notice/@version -- should be 2.0 notice.setAttribute('version', '2.0') # /notice/api-key api_key = xdoc.createElement('api-key') api_key_data = xdoc.createTextNode(hoptoad_settings['HOPTOAD_API_KEY']) api_key.appendChild(api_key_data) notice.appendChild(api_key) # /notice/notifier/name # /notice/notifier/version # /notice/notifier/url notifier = xdoc.createElement('notifier') for key, value in zip(["name", "version", "url"], [NAME, VERSION, URL]): key = xdoc.createElement(key) value = xdoc.createTextNode(str(value)) key.appendChild(value) notifier.appendChild(key) notice.appendChild(notifier) # /notice/error/class # /notice/error/message error = xdoc.createElement('error') for key, value in zip(["class", "message"], [p_error_class, p_message]): key = xdoc.createElement(key) value = xdoc.createTextNode(value) key.appendChild(value) error.appendChild(key) # /notice/error/backtrace/error/line backtrace = xdoc.createElement('backtrace') # i do this here because I'm afraid of circular reference.. reversed_backtrace = None try: reversed_backtrace = traceback.extract_tb(sys.exc_info()[2]) reversed_backtrace.reverse() except AttributeError: # if exception doesn't have a stack trace, then it might be a # custom made exception. # TODO: figure out how to do this cleanly pass if reversed_backtrace: for filename, lineno, funcname, _text in reversed_backtrace: line = xdoc.createElement('line') line.setAttribute('file', str(filename)) line.setAttribute('number', str(lineno)) line.setAttribute('method', str(funcname)) backtrace.appendChild(line) else: line = xdoc.createElement('line') line.setAttribute('file', 'unknown') line.setAttribute('number', '0') line.setAttribute('method', 'unknown') backtrace.appendChild(line) error.appendChild(backtrace) notice.appendChild(error) # /notice/request xrequest = xdoc.createElement('request') # /notice/request/url -- request.build_absolute_uri() xurl = xdoc.createElement('url') xurl_data = xdoc.createTextNode(request.build_absolute_uri()) xurl.appendChild(xurl_data) xrequest.appendChild(xurl) view_func = resolve(request.path)[0] # /notice/request/component -- component where error occured comp = xdoc.createElement('component') comp_data = xdoc.createTextNode(view_func.__module__) comp.appendChild(comp_data) xrequest.appendChild(comp) # /notice/request/action -- action which error occured action = xdoc.createElement('action') action_data = xdoc.createTextNode(view_func.__name__) action.appendChild(action_data) xrequest.appendChild(action) # /notice/request/params/var -- check request.GET/request.POST req_params = _parse_request(request).items() if req_params: params = xdoc.createElement('params') for key, value in req_params: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value.encode('ascii', 'replace'))) var.appendChild(value) params.appendChild(var) xrequest.appendChild(params) # /notice/request/session/var -- check if sessions is enabled.. if hasattr(request, "session"): sessions = xdoc.createElement('session') for key, value in _parse_session(request.session).iteritems(): var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value.encode('ascii', 'replace'))) var.appendChild(value) sessions.appendChild(var) xrequest.appendChild(sessions) # /notice/request/cgi-data/var -- all meta data cgidata = xdoc.createElement('cgi-data') for key, value in _parse_environment(request).iteritems(): var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value.encode('ascii', 'replace'))) var.appendChild(value) cgidata.appendChild(var) xrequest.appendChild(cgidata) notice.appendChild(xrequest) # /notice/server-environment serverenv = xdoc.createElement('server-environment') # /notice/server-environment/project-root -- default to sys.path[0] projectroot = xdoc.createElement('project-root') projectroot.appendChild(xdoc.createTextNode(sys.path[0])) serverenv.appendChild(projectroot) # /notice/server-environment/environment-name -- environment name? wtf.. envname = xdoc.createElement('environment-name') envname_text = getattr(settings, 'HOPTOAD_ENV_NAME', socket.gethostname()) envname_data = xdoc.createTextNode(envname_text) envname.appendChild(envname_data) serverenv.appendChild(envname) appver = xdoc.createElement('app-version') appver_text = getattr(settings, 'HOPTOAD_APP_VERSION', '0.0.0') appver_data = xdoc.createTextNode(appver_text) appver.appendChild(appver_data) serverenv.appendChild(appver) notice.appendChild(serverenv) return xdoc.toxml('utf-8')
# timeout is 2.6 addition! response = urllib2.urlopen(r, timeout=timeout) else: response = urllib2.urlopen(r) except urllib2.URLError, err: pass else: try: # getcode is 2.6 addition!! status = response.getcode() except AttributeError: # default to just code status = response.code if status == 403 and use_ssl: if get_hoptoad_settings().get('HOPTOAD_NO_SSL_FALLBACK', False): # if we can not use SSL, re-invoke w/o using SSL _ride_the_toad(payload, timeout, use_ssl=False) if status == 403 and not use_ssl: # we were not trying to use SSL but got a 403 anyway # something else must be wrong (bad API key?) pass if status == 422: # couldn't send to hoptoad.. pass if status == 500: # hoptoad is down pass def report(payload, timeout): use_ssl = get_hoptoad_settings().get('HOPTOAD_USE_SSL', False)
def generate_payload(request, response=None, exception=None): """Generate an XML payload for a Hoptoad notification. Arguments: - `request`: The Django request object - `response`: Optional. Response code that was received from the webserver - `exception`: Optional. Can be a custom exception that implements __str__ and has the class name of the error that is required to be reported. """ hoptoad_settings = get_hoptoad_settings() p_error_class, p_message = _handle_errors(request, response, exception) # api v2 from: http://help.hoptoadapp.com/faqs/api-2/notifier-api-v2 xdoc = getDOMImplementation().createDocument(None, "notice", None) notice = xdoc.firstChild # /notice/@version -- should be 2.0 notice.setAttribute('version', '2.0') # /notice/api-key api_key = xdoc.createElement('api-key') api_key_data = xdoc.createTextNode(hoptoad_settings['HOPTOAD_API_KEY']) api_key.appendChild(api_key_data) notice.appendChild(api_key) # /notice/notifier/name # /notice/notifier/version # /notice/notifier/url notifier = xdoc.createElement('notifier') for key, value in zip(["name", "version", "url"], [NAME, VERSION, URL]): key = xdoc.createElement(key) value = xdoc.createTextNode(str(value)) key.appendChild(value) notifier.appendChild(key) notice.appendChild(notifier) # /notice/error/class # /notice/error/message error = xdoc.createElement('error') for key, value in zip(["class", "message"], [p_error_class, p_message]): key = xdoc.createElement(key) value = xdoc.createTextNode(value) key.appendChild(value) error.appendChild(key) # /notice/error/backtrace/error/line backtrace = xdoc.createElement('backtrace') # i do this here because I'm afraid of circular reference.. reversed_backtrace = None try: reversed_backtrace = traceback.extract_tb(sys.exc_info()[2]) reversed_backtrace.reverse() except AttributeError: # if exception doesn't have a stack trace, then it might be a # custom made exception. # TODO: figure out how to do this cleanly pass if reversed_backtrace: for filename, lineno, funcname, _text in reversed_backtrace: line = xdoc.createElement('line') line.setAttribute('file', str(filename)) line.setAttribute('number', str(lineno)) line.setAttribute('method', str(funcname)) backtrace.appendChild(line) else: line = xdoc.createElement('line') line.setAttribute('file', 'unknown') line.setAttribute('number', '0') line.setAttribute('method', 'unknown') backtrace.appendChild(line) error.appendChild(backtrace) notice.appendChild(error) # /notice/request xrequest = xdoc.createElement('request') # /notice/request/url -- request.build_absolute_uri() xurl = xdoc.createElement('url') xurl_data = xdoc.createTextNode(request.build_absolute_uri()) xurl.appendChild(xurl_data) xrequest.appendChild(xurl) # /notice/request/component -- not sure.. comp = xdoc.createElement('component') #comp_data = xdoc.createTextNode('') xrequest.appendChild(comp) # /notice/request/action -- action which error occured # ... no f*****g clue.. # sjl: "actions" are the Rails equivalent of Django's views # Is there a way to figure out which view a request object went to # (if any)? Anyway, it's not GET/POST so I'm commenting it for now. #action = xdoc.createElement('action') # maybe GET/POST?? #action_data = u"%s %s" % (request.method, request.META['PATH_INFO']) #action_data = xdoc.createTextNode(action_data) #action.appendChild(action_data) #xrequest.appendChild(action) # /notice/request/params/var -- check request.GET/request.POST req_params = _parse_request(request).items() if req_params: params = xdoc.createElement('params') for key, value in req_params: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value)) var.appendChild(value) params.appendChild(var) xrequest.appendChild(params) # /notice/request/session/var -- check if sessions is enabled.. if hasattr(request, "session"): sessions = xdoc.createElement('session') for key, value in _parse_session(request.session).iteritems(): var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value)) var.appendChild(value) sessions.appendChild(var) xrequest.appendChild(sessions) # /notice/request/cgi-data/var -- all meta data cgidata = xdoc.createElement('cgi-data') for key, value in _parse_environment(request).iteritems(): var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value)) var.appendChild(value) cgidata.appendChild(var) xrequest.appendChild(cgidata) notice.appendChild(xrequest) # /notice/server-environment serverenv = xdoc.createElement('server-environment') # /notice/server-environment/project-root -- default to sys.path[0] projectroot = xdoc.createElement('project-root') projectroot.appendChild(xdoc.createTextNode(sys.path[0])) serverenv.appendChild(projectroot) # /notice/server-environment/environment-name -- environment name? wtf.. envname = xdoc.createElement('environment-name') # no idea... # sjl: This is supposed to be set to something like "test", "staging", # or "production" to help you group the errors in the web interface. # I'm still thinking about the best way to support this. # bmjames: Taking this from a settings variable. I personally have a # different settings.py for every environment and my deploy # script puts the correct one in place, so this makes sense. # But even if one had a single settings.py shared among # environments, it should be possible to set this variable # dynamically. It would simply be the responsibility of # settings.py to do it, rather than the hoptoad middleware. envname_text = hoptoad_settings.get('HOPTOAD_ENV_NAME', 'Unknown') envname_data = xdoc.createTextNode(envname_text) envname.appendChild(envname_data) serverenv.appendChild(envname) notice.appendChild(serverenv) return xdoc.toxml('utf-8')
def __init__(self): """Initialize the middleware.""" hoptoad_settings = get_hoptoad_settings() self._init_middleware(hoptoad_settings)
def hoptoad_xml(exc_class, exc_msg, exc_tb=None, request_data=None): """ Generates the XML document from the given required and optional Request data is a dict of the appropriate items from a request object """ hoptoad_settings = get_hoptoad_settings() # api v2 from: http://help.hoptoadapp.com/faqs/api-2/notifier-api-v2 xdoc = getDOMImplementation().createDocument(None, "notice", None) notice = xdoc.firstChild # /notice/@version -- should be 2.0 notice.setAttribute('version', '2.0') # /notice/api-key api_key = xdoc.createElement('api-key') api_key_data = xdoc.createTextNode(hoptoad_settings['HOPTOAD_API_KEY']) api_key.appendChild(api_key_data) notice.appendChild(api_key) # /notice/notifier/name # /notice/notifier/version # /notice/notifier/url notifier = xdoc.createElement('notifier') for key, value in zip(["name", "version", "url"], [NAME, VERSION, URL]): key = xdoc.createElement(key) value = xdoc.createTextNode(str(value)) key.appendChild(value) notifier.appendChild(key) notice.appendChild(notifier) # /notice/error/class # /notice/error/message error = xdoc.createElement('error') for key, value in zip(["class", "message"], [exc_class, exc_msg]): key = xdoc.createElement(key) value = xdoc.createTextNode(value) key.appendChild(value) error.appendChild(key) # /notice/error/backtrace/error/line backtrace = xdoc.createElement('backtrace') # It's possible to not have a traceback on user-defined exceptions if exc_tb: reversed_backtrace = traceback.extract_tb(exc_tb) reversed_backtrace.reverse() for filename, lineno, funcname, _text in reversed_backtrace: line = xdoc.createElement('line') line.setAttribute('file', str(filename)) line.setAttribute('number', str(lineno)) line.setAttribute('method', str(funcname)) backtrace.appendChild(line) else: line = xdoc.createElement('line') line.setAttribute('file', 'unknown') line.setAttribute('number', '0') line.setAttribute('method', 'unknown') backtrace.appendChild(line) error.appendChild(backtrace) notice.appendChild(error) # /notice/request if request_data: xrequest = xdoc.createElement('request') # /notice/request/url -- request.build_absolute_uri() xurl = xdoc.createElement('url') xurl_data = xdoc.createTextNode(request_data['url']) xurl.appendChild(xurl_data) xrequest.appendChild(xurl) # /notice/request/component -- component where error occured comp = xdoc.createElement('component') comp_data = xdoc.createTextNode(request_data['component']) comp.appendChild(comp_data) xrequest.appendChild(comp) # /notice/request/action -- action which error occured action = xdoc.createElement('action') action_data = xdoc.createTextNode(request_data['action']) action.appendChild(action_data) xrequest.appendChild(action) # /notice/request/params/var -- check request.GET/request.POST req_params = request_data.get('params', None) if req_params: params = xdoc.createElement('params') for key, value in req_params: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode( str(value.encode('ascii', 'replace'))) var.appendChild(value) params.appendChild(var) xrequest.appendChild(params) # /notice/request/session/var -- check if sessions is enabled.. if request_data.get("session", None): sessions = xdoc.createElement('session') for key, value in request_data['session']: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode( str(value.encode('ascii', 'replace'))) var.appendChild(value) sessions.appendChild(var) xrequest.appendChild(sessions) # /notice/request/cgi-data/var -- all meta data if request_data.get('cgi-data', None): cgidata = xdoc.createElement('cgi-data') for key, value in request_data['cgi-data']: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode( str(value.encode('ascii', 'replace'))) var.appendChild(value) cgidata.appendChild(var) xrequest.appendChild(cgidata) notice.appendChild(xrequest) # /notice/server-environment serverenv = xdoc.createElement('server-environment') # /notice/server-environment/project-root -- default to sys.path[0] projectroot = xdoc.createElement('project-root') projectroot.appendChild(xdoc.createTextNode(sys.path[0])) serverenv.appendChild(projectroot) # /notice/server-environment/environment-name -- environment name? wtf.. envname = xdoc.createElement('environment-name') envname_text = getattr(settings, 'HOPTOAD_ENV_NAME', socket.gethostname()) envname_data = xdoc.createTextNode(envname_text) envname.appendChild(envname_data) serverenv.appendChild(envname) appver = xdoc.createElement('app-version') appver_text = getattr(settings, 'HOPTOAD_APP_VERSION', '0.0.0') appver_data = xdoc.createTextNode(appver_text) appver.appendChild(appver_data) serverenv.appendChild(appver) notice.appendChild(serverenv) return xdoc.toxml('utf-8')
def hoptoad_xml(exc_class, exc_msg, exc_tb = None, request_data = None): """ Generates the XML document from the given required and optional Request data is a dict of the appropriate items from a request object """ hoptoad_settings = get_hoptoad_settings() # api v2 from: http://help.hoptoadapp.com/faqs/api-2/notifier-api-v2 xdoc = getDOMImplementation().createDocument(None, "notice", None) notice = xdoc.firstChild # /notice/@version -- should be 2.0 notice.setAttribute('version', '2.0') # /notice/api-key api_key = xdoc.createElement('api-key') api_key_data = xdoc.createTextNode(hoptoad_settings['HOPTOAD_API_KEY']) api_key.appendChild(api_key_data) notice.appendChild(api_key) # /notice/notifier/name # /notice/notifier/version # /notice/notifier/url notifier = xdoc.createElement('notifier') for key, value in zip(["name", "version", "url"], [NAME, VERSION, URL]): key = xdoc.createElement(key) value = xdoc.createTextNode(str(value)) key.appendChild(value) notifier.appendChild(key) notice.appendChild(notifier) # /notice/error/class # /notice/error/message error = xdoc.createElement('error') for key, value in zip(["class", "message"], [exc_class, exc_msg]): key = xdoc.createElement(key) value = xdoc.createTextNode(value) key.appendChild(value) error.appendChild(key) # /notice/error/backtrace/error/line backtrace = xdoc.createElement('backtrace') # It's possible to not have a traceback on user-defined exceptions if exc_tb: reversed_backtrace = traceback.extract_tb(exc_tb) reversed_backtrace.reverse() for filename, lineno, funcname, _text in reversed_backtrace: line = xdoc.createElement('line') line.setAttribute('file', str(filename)) line.setAttribute('number', str(lineno)) line.setAttribute('method', str(funcname)) backtrace.appendChild(line) else: line = xdoc.createElement('line') line.setAttribute('file', 'unknown') line.setAttribute('number', '0') line.setAttribute('method', 'unknown') backtrace.appendChild(line) error.appendChild(backtrace) notice.appendChild(error) # /notice/request if request_data: xrequest = xdoc.createElement('request') # /notice/request/url -- request.build_absolute_uri() xurl = xdoc.createElement('url') xurl_data = xdoc.createTextNode(request_data['url']) xurl.appendChild(xurl_data) xrequest.appendChild(xurl) # /notice/request/component -- component where error occured comp = xdoc.createElement('component') comp_data = xdoc.createTextNode(request_data['component']) comp.appendChild(comp_data) xrequest.appendChild(comp) # /notice/request/action -- action which error occured action = xdoc.createElement('action') action_data = xdoc.createTextNode(request_data['action']) action.appendChild(action_data) xrequest.appendChild(action) # /notice/request/params/var -- check request.GET/request.POST req_params = request_data.get('params', None) if req_params: params = xdoc.createElement('params') for key, value in req_params: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value.encode('ascii', 'replace'))) var.appendChild(value) params.appendChild(var) xrequest.appendChild(params) # /notice/request/session/var -- check if sessions is enabled.. if request_data.get("session", None): sessions = xdoc.createElement('session') for key, value in request_data['session']: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value.encode('ascii', 'replace'))) var.appendChild(value) sessions.appendChild(var) xrequest.appendChild(sessions) # /notice/request/cgi-data/var -- all meta data if request_data.get('cgi-data', None): cgidata = xdoc.createElement('cgi-data') for key, value in request_data['cgi-data']: var = xdoc.createElement('var') var.setAttribute('key', key) value = xdoc.createTextNode(str(value.encode('ascii', 'replace'))) var.appendChild(value) cgidata.appendChild(var) xrequest.appendChild(cgidata) notice.appendChild(xrequest) # /notice/server-environment serverenv = xdoc.createElement('server-environment') # /notice/server-environment/project-root -- default to sys.path[0] projectroot = xdoc.createElement('project-root') projectroot.appendChild(xdoc.createTextNode(sys.path[0])) serverenv.appendChild(projectroot) # /notice/server-environment/environment-name -- environment name? wtf.. envname = xdoc.createElement('environment-name') envname_text = getattr(settings, 'HOPTOAD_ENV_NAME', socket.gethostname()) envname_data = xdoc.createTextNode(envname_text) envname.appendChild(envname_data) serverenv.appendChild(envname) appver = xdoc.createElement('app-version') appver_text = getattr(settings, 'HOPTOAD_APP_VERSION', '0.0.0') appver_data = xdoc.createTextNode(appver_text) appver.appendChild(appver_data) serverenv.appendChild(appver) notice.appendChild(serverenv) return xdoc.toxml('utf-8')
import traceback import urllib2 import yaml from django.views.debug import get_safe_settings from django.conf import settings from hoptoad import get_hoptoad_settings PROTECTED_PARAMS = frozenset(get_hoptoad_settings().get( 'HOPTOAD_PROTECTED_PARAMS', [])) def _parse_environment(request): """Return an environment mapping for a notification from the given request. """ env = dict((str(k), str(v)) for (k, v) in get_safe_settings().items()) env.update(dict((str(k), str(v)) for (k, v) in request.META.items())) env['REQUEST_URI'] = request.build_absolute_uri() return env def _parse_traceback(trace): """Return the given traceback string formatted for a notification.""" p_traceback = [ "%s:%d:in '%s'" % (filename, lineno, funcname)