Esempio n. 1
0
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.")
Esempio n. 2
0
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.")
Esempio n. 3
0
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
Esempio n. 4
0
 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.')
Esempio n. 5
0
 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.')
Esempio n. 6
0
    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)
Esempio n. 7
0
    def __init__(self):
        """Initialize the middleware."""
        hoptoad_settings = get_hoptoad_settings()

        if len(hoptoad_settings) == 0:
            raise MiddlewareNotUsed

        self._init_middleware(hoptoad_settings)
Esempio n. 8
0
    def __init__(self):
        """Initialize the middleware."""
        hoptoad_settings = get_hoptoad_settings()

        if len(hoptoad_settings) == 0:
            raise MiddlewareNotUsed

        self._init_middleware(hoptoad_settings)
Esempio n. 9
0
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")
Esempio n. 10
0
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)
Esempio n. 11
0
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)
Esempio n. 12
0
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)
Esempio n. 13
0
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)
Esempio n. 14
0
def report(payload, timeout):
    use_ssl = get_hoptoad_settings().get('HOPTOAD_USE_SSL', False)
    return _ride_the_toad(payload, timeout, use_ssl)
Esempio n. 15
0
 def __init__(self):
     self._debug = get_hoptoad_settings().get('HOPTOAD_DEBUG', False)
Esempio n. 16
0
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)
Esempio n. 17
0
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, _
Esempio n. 18
0
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')
Esempio n. 19
0
def report(payload, timeout):
    use_ssl = get_hoptoad_settings().get('HOPTOAD_USE_SSL', False)
    return _ride_the_toad(payload, timeout, use_ssl)
Esempio n. 20
0
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')
Esempio n. 21
0
            # 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)
Esempio n. 22
0
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')
Esempio n. 23
0
 def __init__(self):
     """Initialize the middleware."""
     hoptoad_settings = get_hoptoad_settings()
     self._init_middleware(hoptoad_settings)
Esempio n. 24
0
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')
Esempio n. 25
0
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')
Esempio n. 26
0
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)
Esempio n. 27
0
 def __init__(self):
     """Initialize the middleware."""
     hoptoad_settings = get_hoptoad_settings()
     self._init_middleware(hoptoad_settings)