Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 144 lines (115 sloc) 4.354 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
import sys
from pprint import pformat

from pyramid.tweens import EXCVIEW
from pyramid.settings import aslist
from pyramid.settings import asbool
from pyramid.util import DottedNameResolver
from pyramid.httpexceptions import WSGIHTTPException
from pyramid.security import unauthenticated_userid

resolver = DottedNameResolver(None)

PY3 = sys.version_info[0] == 3

if PY3: # pragma: no cover
    import builtins
else:
    import __builtin__ as builtins

def as_globals_list(value):
    L = []
    value = aslist(value)
    for dottedname in value:
        if dottedname in builtins.__dict__:
            if PY3: # pragma: no cover
                dottedname = 'builtins.%s' % dottedname
            else:
                dottedname = '__builtin__.%s' % dottedname
        obj = resolver.resolve(dottedname)
        L.append(obj)
    return L

def _get_url(request):
    try:
        url = request.url
    except UnicodeDecodeError:
        # do the best we can
        url = (request.host_url +
               request.environ.get('SCRIPT_NAME') +
               request.environ.get('PATH_INFO'))
        qs = request.environ.get('QUERY_STRING')
        if qs:
            url += '?' + qs
        url = 'could not decode url: %r' % url
    return url

_MESSAGE_TEMPLATE = """

%(url)s

ENVIRONMENT

%(env)s


PARAMETERS

%(params)s


UNAUTHENTICATED USER

%(usr)s

"""

def _get_message(request):
    url = _get_url(request)
    unauth = unauthenticated_userid(request)

    try:
        params = request.params
    except UnicodeDecodeError:
        params = 'could not decode params'

    return _MESSAGE_TEMPLATE % dict(
            url=url,
            env=pformat(request.environ),
            params=pformat(params),
            usr=unauth if unauth else '')

def _handle_error(request, getLogger, get_message):
    # save the traceback as it may get lost when we get the message.
    # _handle_error is not in the traceback, so calling sys.exc_info
    # does NOT create a circular reference
    exc_info = sys.exc_info()
    try:
        logger = getLogger('exc_logger')
        message = get_message(request)
        logger.error(message, exc_info=exc_info)
    except:
        logger.exception("Exception while logging")
    raise

def exclog_tween_factory(handler, registry):

    get = registry.settings.get

    ignored = get('exclog.ignore', (WSGIHTTPException,))
    get_message = _get_url
    if get('exclog.extra_info', False):
         get_message = _get_message
    get_message = get('exclog.get_message', get_message)

    getLogger = get('exclog.getLogger', 'logging.getLogger')
    getLogger = resolver.resolve(getLogger)

    def exclog_tween(request, getLogger=getLogger):
        # getLogger injected for testing purposes
        try:
            return handler(request)
        except ignored:
            raise
        except:
            _handle_error(request, getLogger, get_message)
            # _handle_error always raises
            raise AssertionError('Should never get here') #pragma NO COVER
    return exclog_tween

def includeme(config):
    """
Set up am implicit :term:`tween` to log exception information that is
generated by your Pyramid application. The logging data will be sent to
the Python logger named ``exc_logger``.

This tween configured to be placed 'below' the exception view tween. It
will log all exceptions (even those eventually caught by a Pyramid
exception view) except 'http exceptions' (any exception that derives from
``pyramid.httpexceptions.WSGIHTTPException`` such as ``HTTPFound``). You
can instruct ``pyramid_exclog`` to ignore custom exception types by using
the ``excview.ignore`` configuration setting.
"""
    get = config.registry.settings.get
    ignored = as_globals_list(get('exclog.ignore',
                                  'pyramid.httpexceptions.WSGIHTTPException'))
    extra_info = asbool(get('exclog.extra_info', False))
    get_message = get('exclog.get_message', None)
    if get_message is not None:
        get_message = config.maybe_dotted(get_message)
        config.registry.settings['exclog.get_message'] = get_message
    config.registry.settings['exclog.ignore'] = tuple(ignored)
    config.registry.settings['exclog.extra_info'] = extra_info
    config.add_tween('pyramid_exclog.exclog_tween_factory', under=EXCVIEW)
Something went wrong with that request. Please try again.