pimp mah error messages, it has a full link to the Trac with pre-filled title, traceback, url, hg revision fields
authorTero Marttila <terom@fixme.fi>
Mon, 16 Feb 2009 02:49:06 +0200
changeset 135 19ff083c2870
parent 134 fbccc1648d79
child 136 c69a176b3620
pimp mah error messages, it has a full link to the Trac with pre-filled title, traceback, url, hg revision fields
error.py
wsgi.py
--- a/error.py	Mon Feb 16 02:09:14 2009 +0200
+++ b/error.py	Mon Feb 16 02:49:06 2009 +0200
@@ -2,35 +2,112 @@
     Build error messages
 """
 
-import traceback, sys
+import traceback, sys, cgi, urllib
 
-def build_error (exc_info=None) :
+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
+    # 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
+
+        wc_path = HG_WC_PATH
+
+    except :
+        # a good guess
+        wc_path = '.'
+    
+    # version?
+    try :
+        from version import version_string
+
+        version = version_string(wc_path)
+    
+    except :
+        version = None
+    
+    # the exception type
+    exception_str = traceback.format_exception_only(*exc_info[:2])[-1][:255]
+
+    # the exception traceback
+    traceback_lines = traceback.format_exception(*exc_info)
+
+    # XXX: make this configureable
+    trac_url = "http://projects.qmsk.net/irclogs2/trac"
+    
+    # ticket list
+    query_url = "%s/query" % trac_url
+
+    # submit ticket
+    submit_args = dict(type='defect')
+
+    if url :
+        submit_args['url'] = url
+
+    if version :
+        submit_args['revision'] = version
+    
+    if exception_str :
+        submit_args['summary'] = exception_str
+
+    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 will not be reported to anybody. It might be your fault, or it might be
-    the programmer's, but it's probably not mine. If you think you really care, you can try poking the administrator of
-    this site to see if they respond. 
+    mine. 
 </p>
 <p>
-    If you do so, please include the following information:
+    You can try poking the administrator of this site to see if they respond, or submit a defect ticket at the <a href="%(query_url)s">Project Trac</a>, using the following link:
 </p>
+<pre>
+    <a href="%(submit_url)s">%(submit_url_short)s</a>
+</pre>
 <h2>Details:</h2>
 <pre>%(traceback)s</pre>
 </body></html>""" % dict(
-        traceback   = ''.join(traceback.format_exception(*exc_info))
+        traceback           = cgi.escape(''.join(traceback_lines)),
+        query_url           = query_url,
+        submit_url          = submit_url,
+        submit_url_short    = submit_url[:120] + '...'
     )).encode('utf-8'))
 
--- a/wsgi.py	Mon Feb 16 02:09:14 2009 +0200
+++ b/wsgi.py	Mon Feb 16 02:49:06 2009 +0200
@@ -21,7 +21,7 @@
         """
         
         # get info
-        status, content_type, body = error.build_error()
+        status, content_type, body = error.build_error(env=env)
 
         # headers
         start_response(status, [('Content-type', content_type)], exc_info)