error.py
changeset 140 6db2527b67cf
parent 139 9c7769850195
child 141 65c98c9e1716
equal deleted inserted replaced
139:9c7769850195 140:6db2527b67cf
     1 """
       
     2     Build error messages
       
     3 """
       
     4 
       
     5 import traceback, sys, cgi, urllib
       
     6 
       
     7 def truncate (msg, limit) :
       
     8     """
       
     9         Truncate the given message to <limit> chars
       
    10     """
       
    11 
       
    12     if len(msg) > limit :
       
    13         return msg[:limit-3] + '...'
       
    14 
       
    15     else :
       
    16         return msg
       
    17 
       
    18 def build_link (title, url) :
       
    19     return '<a href="%s">%s</a>' % (cgi.escape(url, True), cgi.escape(title))
       
    20 
       
    21 def build_error (exc_info=None, env=None) :
       
    22     """
       
    23         Dumps out a raw traceback of the given/current exception to stdout.
       
    24 
       
    25         If request_env, it should be a environment dict, like under WSGI, and will be used to display additional info
       
    26         about the request.
       
    27 
       
    28         Returns a (status, content-type, body) tuple, with all components being non-unicode strs.
       
    29     """
       
    30 
       
    31     # default for exc_info is current exception
       
    32     if not exc_info :
       
    33         exc_info = sys.exc_info()
       
    34 
       
    35     # request URL?
       
    36     if env :
       
    37         try :
       
    38             from qmsk.web.http import request_url
       
    39 
       
    40             url = request_url(env)
       
    41 
       
    42         except :
       
    43             # ignore
       
    44             url = None
       
    45     else :
       
    46         url = None
       
    47 
       
    48     # working copy path?
       
    49     try :
       
    50         from config import HG_WC_PATH, HGWEB_URL
       
    51 
       
    52         wc_path = HG_WC_PATH
       
    53         hgweb_url = HGWEB_URL
       
    54 
       
    55     except :
       
    56         # a good guess
       
    57         wc_path = '.'
       
    58         hgweb_url = None
       
    59     
       
    60     # version?
       
    61     try :
       
    62         from version import version_string, version_link_hg
       
    63 
       
    64         version = version_string(wc_path)
       
    65 
       
    66         if hgweb_url :
       
    67             version_href = version_link_hg(hgweb_url, wc_path)
       
    68 
       
    69         else :
       
    70             version_href = None
       
    71     
       
    72     except :
       
    73         version = None
       
    74         version_href = None
       
    75     
       
    76     # the exception type
       
    77     exception_str = traceback.format_exception_only(*exc_info[:2])[-1]
       
    78 
       
    79     # the exception traceback
       
    80     traceback_lines = traceback.format_exception(*exc_info)
       
    81 
       
    82     # XXX: make this configureable
       
    83     trac_url = "http://projects.qmsk.net/irclogs2/trac"
       
    84     
       
    85     # ticket list
       
    86     trac_query = build_link("All tickets", "%s/query" % trac_url)
       
    87 
       
    88     # submit ticket
       
    89     submit_args = dict(type='defect')
       
    90     
       
    91     # handle optional components
       
    92     if url :
       
    93         submit_args['url'] = url
       
    94         trac_query_url = build_link("Same URL", "%s/query?url=%s" % (trac_url, urllib.quote(url)))
       
    95     else :
       
    96         trac_query_url = ""
       
    97     
       
    98     if version :
       
    99         submit_args['revision'] = version
       
   100         trac_query_version = build_link("Same version", "%s/query?revision=%s" % (trac_url, urllib.quote(version)))
       
   101 
       
   102     else :
       
   103         trac_query_version = ""
       
   104     
       
   105     if exception_str :
       
   106         submit_args['summary'] = truncate(exception_str, 140)
       
   107         trac_query_err = build_link("Same error", "%s/query?summary=%s" % (trac_url, urllib.quote(exception_str.rstrip())))
       
   108 
       
   109     else :
       
   110         trac_query_err = ""
       
   111 
       
   112     if traceback_lines :
       
   113         # this is big
       
   114         submit_args['description'] = """\
       
   115 [Insert any additional information here]
       
   116 
       
   117 
       
   118 = Traceback =
       
   119 {{{
       
   120 %s
       
   121 }}}""" % ''.join(traceback_lines)
       
   122     
       
   123     # the trac newticket URL
       
   124     submit_url = "%s/newticket?%s" % (trac_url, '&amp;'.join('%s=%s' % (urllib.quote(k), urllib.quote(v)) for k, v in submit_args.iteritems()))
       
   125 
       
   126     # return
       
   127     return ('500 Internal Server Error', 'text/html; charset=UTF-8', ("""\
       
   128 <html><head><title>500 Internal Server Error</title></head><body>
       
   129 <h1>Oops!</h1>
       
   130 <p>
       
   131     An error occured, which was not logged, and was not reported to anybody. It might be your fault, or it might be mine.
       
   132 </p>
       
   133 
       
   134 <p>
       
   135     You can try:
       
   136     <ol style="list-style-type: lower-alpha">
       
   137         <li><strong>Poking</strong> the administrator of this site to see if they respond</li>
       
   138         <li><strong>Looking</strong> for similar issue tickets with:
       
   139           <ul>
       
   140             <li>%(trac_query)s</li>
       
   141             <li>%(trac_query_url)s</li>
       
   142             <li>%(trac_query_version)s</li>
       
   143             <li>%(trac_query_err)s</li>
       
   144           </ul>
       
   145         </li>
       
   146         <li><strong>Submitting</strong> a new ticket using the following link (quick &amp; easy):</li>
       
   147     </ol>
       
   148 </p>
       
   149 <pre>
       
   150     <a href="%(submit_url)s">%(submit_url_short)s</a>
       
   151 </pre>
       
   152 
       
   153 <h2>Details:</h2>
       
   154 <p>The page you tried to request was:</p>
       
   155 <pre>
       
   156     %(url)s
       
   157 </pre>
       
   158 
       
   159 <p>The software version is:</p>
       
   160 <pre>
       
   161     %(version_link)s
       
   162 </pre>
       
   163 
       
   164 <p>The error was:</p>
       
   165 <pre>
       
   166     %(exception)s
       
   167 </pre>
       
   168 
       
   169 <p>The traceback was:</p>
       
   170 <pre>%(traceback)s</pre>
       
   171 </body></html>""" % dict(
       
   172         url                 = url if url else 'Unknown',
       
   173         version_link        = version_href if version_href else 'Unknown',
       
   174         exception           = truncate(exception_str, 512),
       
   175         traceback           = cgi.escape(''.join('   ' + line for line in traceback_lines)),
       
   176         trac_query          = trac_query,
       
   177         trac_query_url      = trac_query_url,
       
   178         trac_query_version  = trac_query_version,
       
   179         trac_query_err      = trac_query_err,
       
   180         submit_url          = submit_url,
       
   181         submit_url_short    = truncate(submit_url, 120)
       
   182     )).encode('utf-8'))
       
   183