Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 356 lines (319 sloc) 12.136 kb
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
1 """
2 pretty debug errors
3 (part of web.py)
4
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
5 portions adapted from Django <djangoproject.com>
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
6 Copyright (c) 2005, the Lawrence Journal-World
7 Used under the modified BSD license:
8 http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
9 """
10
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
11 __all__ = ["debugerror", "djangoerror", "emailerrors"]
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
12
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
13 import sys, urlparse, pprint, traceback
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
14 from net import websafe
15 from template import Template
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
16 from utils import sendmail
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
17 import webapi as web
18
19 import os, os.path
20 whereami = os.path.join(os.getcwd(), __file__)
21 whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1])
22 djangoerror_t = """\
23 $def with (exception_type, exception_value, frames)
24 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
25 <html lang="en">
26 <head>
27 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
28 <meta name="robots" content="NONE,NOARCHIVE" />
29 <title>$exception_type at $ctx.path</title>
30 <style type="text/css">
31 html * { padding:0; margin:0; }
32 body * { padding:10px 20px; }
33 body * * { padding:0; }
34 body { font:small sans-serif; }
35 body>div { border-bottom:1px solid #ddd; }
36 h1 { font-weight:normal; }
37 h2 { margin-bottom:.8em; }
38 h2 span { font-size:80%; color:#666; font-weight:normal; }
39 h3 { margin:1em 0 .5em 0; }
40 h4 { margin:0 0 .5em 0; font-weight: normal; }
41 table {
42 border:1px solid #ccc; border-collapse: collapse; background:white; }
43 tbody td, tbody th { vertical-align:top; padding:2px 3px; }
44 thead th {
45 padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
46 font-weight:normal; font-size:11px; border:1px solid #ddd; }
47 tbody th { text-align:right; color:#666; padding-right:.5em; }
48 table.vars { margin:5px 0 2px 40px; }
49 table.vars td, table.req td { font-family:monospace; }
50 table td.code { width:100%;}
51 table td.code div { overflow:hidden; }
52 table.source th { color:#666; }
53 table.source td {
54 font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
55 ul.traceback { list-style-type:none; }
56 ul.traceback li.frame { margin-bottom:1em; }
57 div.context { margin: 10px 0; }
58 div.context ol {
59 padding-left:30px; margin:0 10px; list-style-position: inside; }
60 div.context ol li {
61 font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
62 div.context ol.context-line li { color:black; background-color:#ccc; }
63 div.context ol.context-line li span { float: right; }
64 div.commands { margin-left: 40px; }
65 div.commands a { color:black; text-decoration:none; }
66 #summary { background: #ffc; }
67 #summary h2 { font-weight: normal; color: #666; }
68 #explanation { background:#eee; }
69 #template, #template-not-exist { background:#f6f6f6; }
70 #template-not-exist ul { margin: 0 0 0 20px; }
71 #traceback { background:#eee; }
72 #requestinfo { background:#f6f6f6; padding-left:120px; }
73 #summary table { border:none; background:transparent; }
74 #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
75 #requestinfo h3 { margin-bottom:-1em; }
76 .error { background: #ffc; }
77 .specific { color:#cc3300; font-weight:bold; }
78 </style>
79 <script type="text/javascript">
80 //<!--
81 function getElementsByClassName(oElm, strTagName, strClassName){
82 // Written by Jonathan Snook, http://www.snook.ca/jon;
83 // Add-ons by Robert Nyman, http://www.robertnyman.com
84 var arrElements = (strTagName == "*" && document.all)? document.all :
85 oElm.getElementsByTagName(strTagName);
86 var arrReturnElements = new Array();
87 strClassName = strClassName.replace(/\-/g, "\\-");
70455f2 @anandology fix template in djangoerror
anandology authored
88 var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)");
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
89 var oElement;
90 for(var i=0; i<arrElements.length; i++){
91 oElement = arrElements[i];
92 if(oRegExp.test(oElement.className)){
93 arrReturnElements.push(oElement);
94 }
95 }
96 return (arrReturnElements)
97 }
98 function hideAll(elems) {
99 for (var e = 0; e < elems.length; e++) {
100 elems[e].style.display = 'none';
101 }
102 }
103 window.onload = function() {
104 hideAll(getElementsByClassName(document, 'table', 'vars'));
105 hideAll(getElementsByClassName(document, 'ol', 'pre-context'));
106 hideAll(getElementsByClassName(document, 'ol', 'post-context'));
107 }
108 function toggle() {
109 for (var i = 0; i < arguments.length; i++) {
110 var e = document.getElementById(arguments[i]);
111 if (e) {
112 e.style.display = e.style.display == 'none' ? 'block' : 'none';
113 }
114 }
115 return false;
116 }
117 function varToggle(link, id) {
118 toggle('v' + id);
119 var s = link.getElementsByTagName('span')[0];
120 var uarr = String.fromCharCode(0x25b6);
121 var darr = String.fromCharCode(0x25bc);
122 s.innerHTML = s.innerHTML == uarr ? darr : uarr;
123 return false;
124 }
125 //-->
126 </script>
127 </head>
128 <body>
129
7a1ff8f fix debug error
Anand authored
130 $def dicttable (d, kls='req', id=None):
131 $ items = d and d.items() or []
132 $items.sort()
133 $:dicttable_items(items, kls, id)
134
135 $def dicttable_items(items, kls='req', id=None):
136 $if items:
137 <table class="$kls"
138 $if id: id="$id"
139 ><thead><tr><th>Variable</th><th>Value</th></tr></thead>
140 <tbody>
141 $for k, v in items:
142 <tr><td>$k</td><td class="code"><div>$prettify(v)</div></td></tr>
143 </tbody>
144 </table>
145 $else:
146 <p>No data.</p>
147
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
148 <div id="summary">
149 <h1>$exception_type at $ctx.path</h1>
150 <h2>$exception_value</h2>
151 <table><tr>
152 <th>Python</th>
153 <td>$frames[0].filename in $frames[0].function, line $frames[0].lineno</td>
154 </tr><tr>
155 <th>Web</th>
156 <td>$ctx.method $ctx.home$ctx.path</td>
157 </tr></table>
158 </div>
159 <div id="traceback">
160 <h2>Traceback <span>(innermost first)</span></h2>
161 <ul class="traceback">
162 $for frame in frames:
163 <li class="frame">
164 <code>$frame.filename</code> in <code>$frame.function</code>
165 $if frame.context_line:
166 <div class="context" id="c$frame.id">
167 $if frame.pre_context:
168 <ol start="$frame.pre_context_lineno" class="pre-context" id="pre$frame.id">
169 $for line in frame.pre_context:
170 <li onclick="toggle('pre$frame.id', 'post$frame.id')">$line</li>
171 </ol>
172 <ol start="$frame.lineno" class="context-line"><li onclick="toggle('pre$frame.id', 'post$frame.id')">$frame.context_line <span>...</span></li></ol>
173 $if frame.post_context:
70455f2 @anandology fix template in djangoerror
anandology authored
174 <ol start='${frame.lineno + 1}' class="post-context" id="post$frame.id">
175 $for line in frame.post_context:
176 <li onclick="toggle('pre$frame.id', 'post$frame.id')">$line</li>
177 </ol>
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
178 </div>
179
180 $if frame.vars:
181 <div class="commands">
182 <a href='#' onclick="return varToggle(this, '$frame.id')"><span>&#x25b6;</span> Local vars</a>
183 $# $inspect.formatargvalues(*inspect.getargvalues(frame['tb'].tb_frame))
184 </div>
185 $:dicttable(frame.vars, kls='vars', id=('v' + str(frame.id)))
186 </li>
187 </ul>
188 </div>
189
190 <div id="requestinfo">
191 $if ctx.output or ctx.headers:
192 <h2>Response so far</h2>
193 <h3>HEADERS</h3>
7a1ff8f fix debug error
Anand authored
194 $:dicttable_items(ctx.headers)
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
195
196 <h3>BODY</h3>
197 <p class="req" style="padding-bottom: 2em"><code>
198 $ctx.output
199 </code></p>
200
201 <h2>Request information</h2>
202
203 <h3>INPUT</h3>
204 $:dicttable(web.input())
205
206 <h3 id="cookie-info">COOKIES</h3>
207 $:dicttable(web.cookies())
208
209 <h3 id="meta-info">META</h3>
7a1ff8f fix debug error
Anand authored
210 $ newctx = [(k, v) for (k, v) in ctx.iteritems() if not k.startswith('_') and not isinstance(v, dict)]
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
211 $:dicttable(dict(newctx))
212
213 <h3 id="meta-info">ENVIRONMENT</h3>
214 $:dicttable(ctx.env)
215 </div>
216
217 <div id="explanation">
218 <p>
7a1ff8f fix debug error
Anand authored
219 You're seeing this error because you have <code>web.config.debug</code>
220 set to <code>True</code>. Set that to <code>False</code> if you don't to see this.
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
221 </p>
222 </div>
223
224 </body>
225 </html>
226 """
227
c015a59 @anandology fix templetor for GAE
anandology authored
228 djangoerror_r = None
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
229
230 def djangoerror():
231 def _get_lines_from_file(filename, lineno, context_lines):
232 """
233 Returns context_lines before and after lineno from file.
234 Returns (pre_context_lineno, pre_context, context_line, post_context).
235 """
236 try:
237 source = open(filename).readlines()
238 lower_bound = max(0, lineno - context_lines)
239 upper_bound = lineno + context_lines
240
241 pre_context = \
242 [line.strip('\n') for line in source[lower_bound:lineno]]
243 context_line = source[lineno].strip('\n')
244 post_context = \
245 [line.strip('\n') for line in source[lineno + 1:upper_bound]]
246
247 return lower_bound, pre_context, context_line, post_context
248 except (OSError, IOError):
249 return None, [], None, []
250
251 exception_type, exception_value, tback = sys.exc_info()
252 frames = []
253 while tback is not None:
254 filename = tback.tb_frame.f_code.co_filename
255 function = tback.tb_frame.f_code.co_name
256 lineno = tback.tb_lineno - 1
257 pre_context_lineno, pre_context, context_line, post_context = \
258 _get_lines_from_file(filename, lineno, 7)
259 frames.append(web.storage({
260 'tback': tback,
261 'filename': filename,
262 'function': function,
263 'lineno': lineno,
264 'vars': tback.tb_frame.f_locals,
265 'id': id(tback),
266 'pre_context': pre_context,
267 'context_line': context_line,
268 'post_context': post_context,
269 'pre_context_lineno': pre_context_lineno,
270 }))
271 tback = tback.tb_next
272 frames.reverse()
273 urljoin = urlparse.urljoin
274 def prettify(x):
275 try:
276 out = pprint.pformat(x)
277 except Exception, e:
278 out = '[could not display: <' + e.__class__.__name__ + \
279 ': '+str(e)+'>]'
280 return out
c015a59 @anandology fix templetor for GAE
anandology authored
281
282 global djangoerror_r
283 if djangoerror_r is None:
284 djangoerror_r = Template(djangoerror_t, filename=__file__, filter=websafe)
285
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
286 t = djangoerror_r
7a1ff8f fix debug error
Anand authored
287 globals = {'ctx': web.ctx, 'web':web, 'dict':dict, 'str':str, 'prettify': prettify}
288 t.t.func_globals.update(globals)
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
289 return t(exception_type, exception_value, frames)
290
291 def debugerror():
292 """
293 A replacement for `internalerror` that presents a nice page with lots
294 of debug information for the programmer.
295
296 (Based on the beautiful 500 page from [Django](http://djangoproject.com/),
297 designed by [Wilson Miner](http://wilsonminer.com/).)
298 """
f4cf5b2 @anandology use web._InternalError instead of web.internalerror to stop failing w…
anandology authored
299 return web._InternalError(djangoerror())
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
300
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
301 def emailerrors(email_address, olderror):
302 """
303 Wraps the old `internalerror` handler (pass as `olderror`) to
304 additionally email all errors to `email_address`, to aid in
305 debugging production websites.
306
307 Emails contain a normal text traceback as well as an
308 attachment containing the nice `debugerror` page.
309 """
310 def emailerrors_internal():
51b438f @anandology fixed debugerror and emailerrors (Bug#179713)
anandology authored
311 error = olderror()
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
312 tb = sys.exc_info()
313 error_name = tb[0]
314 error_value = tb[1]
315 tb_txt = ''.join(traceback.format_exception(*tb))
316 path = web.ctx.path
317 request = web.ctx.method+' '+web.ctx.home+web.ctx.fullpath
318 eaddr = email_address
319 text = ("""\
320 ------here----
321 Content-Type: text/plain
322 Content-Disposition: inline
323
324 %(request)s
325
326 %(tb_txt)s
327
328 ------here----
329 Content-Type: text/html; name="bug.html"
330 Content-Disposition: attachment; filename="bug.html"
331
332 """ % locals()) + str(djangoerror())
0a34e17 update debugerror to use new API
aaronsw authored
333 sendmail(
334 "your buggy site <%s>" % eaddr,
335 "the bugfixer <%s>" % eaddr,
336 "bug: %(error_name)s: %(error_value)s (%(path)s)" % locals(),
337 text,
338 headers={'Content-Type': 'multipart/mixed; boundary="----here----"'})
51b438f @anandology fixed debugerror and emailerrors (Bug#179713)
anandology authored
339 return error
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
340
341 return emailerrors_internal
342
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
343 if __name__ == "__main__":
344 urls = (
345 '/', 'index'
346 )
35c0702 @anandology let web.debugerror return an error instead error message.
anandology authored
347 from application import application
348 app = application(urls, globals())
349 app.internalerror = debugerror
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
350
351 class index:
352 def GET(self):
353 thisdoesnotexist
35c0702 @anandology let web.debugerror return an error instead error message.
anandology authored
354
355 app.run()
Something went wrong with that request. Please try again.