error.py
author Tero Marttila <terom@fixme.fi>
Mon, 16 Feb 2009 03:25:00 +0200
changeset 137 a25d1bf758e6
parent 136 c69a176b3620
child 139 9c7769850195
permissions -rw-r--r--
moar pimping of the error page... at this point, error messages are becoming more of a feature than a bug
"""
    Build error messages
"""

import traceback, sys, cgi, urllib

def truncate (msg, limit) :
    """
        Truncate the given message to <limit> chars
    """

    if len(msg) > limit :
        return msg[:limit-3] + '...'

    else :
        return msg

def build_link (title, url) :
    return '<a href="%s">%s</a>' % (cgi.escape(url, True), cgi.escape(title))

def build_error (exc_info=None, env=None) :
    """
        Dumps out a raw traceback of the given/current exception to stdout.

        If request_env, it should be a environment dict, like under WSGI, and will be used to display additional info
        about the request.

        Returns a (status, content-type, body) tuple, with all components being non-unicode strs.
    """

    # default for exc_info is current exception
    if not exc_info :
        exc_info = sys.exc_info()

    # request URL?
    if env :
        try :
            from qmsk.web.http import request_url

            url = request_url(env)

        except :
            # ignore
            url = None
    else :
        url = None

    # working copy path?
    try :
        from config import HG_WC_PATH, HGWEB_URL

        wc_path = HG_WC_PATH
        hgweb_url = HGWEB_URL

    except :
        # a good guess
        wc_path = '.'
        hgweb_url = None
    
    # version?
    try :
        from version import version_string, version_link_hg

        version = version_string(wc_path)

        if hgweb_url :
            version_href = version_link_hg(wc_path, hgweb_url)

        else :
            version_href = None
    
    except :
        version = None
        version_href = None
    
    # the exception type
    exception_str = traceback.format_exception_only(*exc_info[:2])[-1]

    # the exception traceback
    traceback_lines = traceback.format_exception(*exc_info)

    # XXX: make this configureable
    trac_url = "http://projects.qmsk.net/irclogs2/trac"
    
    # ticket list
    trac_query = build_link("All tickets", "%s/query" % trac_url)

    # submit ticket
    submit_args = dict(type='defect')
    
    # handle optional components
    if url :
        submit_args['url'] = url
        trac_query_url = build_link("Same URL", "%s/query?url=%s" % (trac_url, urllib.quote(url)))
    else :
        trac_query_url = ""
    
    if version :
        submit_args['revision'] = version
        trac_query_version = build_link("Same version", "%s/query?revision=%s" % (trac_url, urllib.quote(version)))

    else :
        trac_query_version = ""
    
    if exception_str :
        submit_args['summary'] = truncate(exception_str, 140)
        trac_query_err = build_link("Same error", "%s/query?summary=%s" % (trac_url, urllib.quote(exception_str.rstrip())))

    else :
        trac_query_err = ""

    if traceback_lines :
        # this is big
        submit_args['description'] = """\
[Insert any additional information here]


= Traceback =
{{{
%s
}}}""" % ''.join(traceback_lines)
    
    # the trac newticket URL
    submit_url = "%s/newticket?%s" % (trac_url, '&amp;'.join('%s=%s' % (urllib.quote(k), urllib.quote(v)) for k, v in submit_args.iteritems()))

    # return
    return ('500 Internal Server Error', 'text/html; charset=UTF-8', ("""\
<html><head><title>500 Internal Server Error</title></head><body>
<h1>Oops!</h1>
<p>
    An error occured, which was not logged, and was not reported to anybody. It might be your fault, or it might be mine.
</p>

<p>
    You can try:
    <ol style="list-style-type: lower-alpha">
        <li><strong>Poking</strong> the administrator of this site to see if they respond</li>
        <li><strong>Looking</strong> for similar issue tickets with:
          <ul>
            <li>%(trac_query)s</li>
            <li>%(trac_query_url)s</li>
            <li>%(trac_query_version)s</li>
            <li>%(trac_query_err)s</li>
          </ul>
        </li>
        <li><strong>Submitting</strong> a new ticket using the following link (quick &amp; easy):</li>
    </ol>
</p>
<pre>
    <a href="%(submit_url)s">%(submit_url_short)s</a>
</pre>

<h2>Details:</h2>
<p>The page you tried to request was:</p>
<pre>
    %(url)s
</pre>

<p>The software version is:</p>
<pre>
    %(version_link)s
</pre>

<p>The error was:</p>
<pre>
    %(exception)s
</pre>

<p>The traceback was:</p>
<pre>%(traceback)s</pre>
</body></html>""" % dict(
        url                 = url if url else 'Unknown',
        version_link        = version_href if version_href else 'Unknown',
        exception           = truncate(exception_str, 512),
        traceback           = cgi.escape(''.join('   ' + line for line in traceback_lines)),
        trac_query          = trac_query,
        trac_query_url      = trac_query_url,
        trac_query_version  = trac_query_version,
        trac_query_err      = trac_query_err,
        submit_url          = submit_url,
        submit_url_short    = truncate(submit_url, 120)
    )).encode('utf-8'))