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, '&'.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 & 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 |
|