PageRenderTime 40ms CodeModel.GetById 29ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/tornado/web/debugerror.py

https://github.com/yuroyoro/benchmark_asynchronous_servers
Python | 356 lines | 344 code | 3 blank | 9 comment | 0 complexity | fb9bb783dc1119f5a523e828b70325ec MD5 | raw file
  1"""
  2pretty debug errors
  3(part of web.py)
  4
  5portions adapted from Django <djangoproject.com> 
  6Copyright (c) 2005, the Lawrence Journal-World
  7Used under the modified BSD license:
  8http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
  9"""
 10
 11__all__ = ["debugerror", "djangoerror", "emailerrors"]
 12
 13import sys, urlparse, pprint, traceback
 14from net import websafe
 15from template import Template
 16from utils import sendmail
 17import webapi as web
 18
 19import os, os.path
 20whereami = os.path.join(os.getcwd(), __file__)
 21whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1])
 22djangoerror_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, "\\-");
 88        var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)");
 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
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
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:
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>
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>
194    $:dicttable_items(ctx.headers)
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>
210$ newctx = [(k, v) for (k, v) in ctx.iteritems() if not k.startswith('_') and not isinstance(v, dict)]
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>
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.
221  </p>
222</div>
223
224</body>
225</html>
226"""
227
228djangoerror_r = None
229
230def 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
281        
282    global djangoerror_r
283    if djangoerror_r is None:
284        djangoerror_r = Template(djangoerror_t, filename=__file__, filter=websafe)
285        
286    t = djangoerror_r
287    globals = {'ctx': web.ctx, 'web':web, 'dict':dict, 'str':str, 'prettify': prettify}
288    t.t.func_globals.update(globals)
289    return t(exception_type, exception_value, frames)
290
291def 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    """
299    return web._InternalError(djangoerror())
300
301def emailerrors(to_address, olderror, from_address=None):
302    """
303    Wraps the old `internalerror` handler (pass as `olderror`) to 
304    additionally email all errors to `to_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    from_address = from_address or to_address
311
312    def emailerrors_internal():
313        error = olderror()
314        tb = sys.exc_info()
315        error_name = tb[0]
316        error_value = tb[1]
317        tb_txt = ''.join(traceback.format_exception(*tb))
318        path = web.ctx.path
319        request = web.ctx.method + ' ' + web.ctx.home + web.ctx.fullpath
320        text = ("""\
321------here----
322Content-Type: text/plain
323Content-Disposition: inline
324
325%(request)s
326
327%(tb_txt)s
328
329------here----
330Content-Type: text/html; name="bug.html"
331Content-Disposition: attachment; filename="bug.html"
332
333""" % locals()) + str(djangoerror())
334        sendmail(
335          "your buggy site <%s>" % from_address,
336          "the bugfixer <%s>" % to_address,
337          "bug: %(error_name)s: %(error_value)s (%(path)s)" % locals(),
338          text, 
339          headers={'Content-Type': 'multipart/mixed; boundary="----here----"'})
340        return error
341    
342    return emailerrors_internal
343
344if __name__ == "__main__":
345    urls = (
346        '/', 'index'
347    )
348    from application import application
349    app = application(urls, globals())
350    app.internalerror = debugerror
351    
352    class index:
353        def GET(self):
354            thisdoesnotexist
355
356    app.run()