Skip to content

Instantly share code, notes, and snippets.

@pplante
Created April 10, 2011 00:28
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pplante/911930 to your computer and use it in GitHub Desktop.
Save pplante/911930 to your computer and use it in GitHub Desktop.
template for nicer debugging of tornado exceptions
# Copyright (c) 2011 Phil Plante <unhappyrobot AT gmail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import httplib
import logging
import os
class UncaughtExceptionMixin(object):
def get_error_html(self, status_code, **kwargs):
def get_snippet(fp, target_line, num_lines):
if fp.endswith('.html'):
fp = os.path.join(self.get_template_path(), fp)
half_lines = (num_lines/2)
try:
with open(fp) as f:
all_lines = [line for line in f]
return ''.join(all_lines[target_line-half_lines:target_line+half_lines])
except Exception, ex:
logging.error(ex)
return ''
if self.application.settings.get('debug', False) is False:
full_message = kwargs.get('exception', None)
if not full_message or unicode(full_message) == '':
full_message = 'Sky is falling!'
return "<html><title>%(code)d: %(message)s</title><body><h1>%(code)d: %(message)s</h1>%(full_message)s</body></html>" % {
"code": status_code,
"message": httplib.responses[status_code],
"full_message": full_message,
}
else:
exception = kwargs.get('exception', None)
return self.render_string('exception.html', get_snippet=get_snippet, exception=exception, status_code=status_code, kwargs=kwargs)
<!--
# Copyright (c) 2011 Phil Plante <unhappyrobot AT gmail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-->
{% import traceback %}
{% import sys %}
{% import os %}
{% import tornado %}
{% set type, value, tback = sys.exc_info() %}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>HTTP Status {{ status_code }} &raquo; Tornado v{{ tornado.version }}</title>
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
SyntaxHighlighter.all();
</script>
<style type="text/css" media="screen">
body {
font-family: Helvetica;
font-size: 10pt;
}
h1 {
background: #ffc06f;
border-bottom: 1px solid #ff9309;
margin: 0;
padding: 5px;
}
h2 {
background: #ffdd6f;
border-bottom: 1px solid #ff9309;
margin: 0;
margin-bottom: 1em;
padding: 5px;
}
h3 {
border-bottom: 1px solid #CCC;
margin: 0.5em 0;
padding-bottom: 0.5em;
}
hr {
background: #CCC;
border: none;
height: 1px;
margin: 0.25em 0;
}
.traceback-frame-header td {
background: #EEFFFF;
padding: 5px;
}
.traceback-frame-header h4 {
cursor: pointer;
margin: 0;
}
.traceback-frame.first .traceback-frame-header td {
background: #e8fce4;
}
table td.key {
background: #E9FFFF;
padding: 4px 8px;
}
table td.value {
padding: 4px;
}
table td.value.alt {
background: #EFEFEF;
}
</style>
</head>
<body>
<h1>HTTP Status {{ status_code }}</h1>
{% if exception %}
{% set traceback_list = traceback.extract_tb(tback) %}
<h2>Application raised {{ exception.__class__.__name__ }}: {{ exception }}</h2>
{% set filepath, line, method, code = traceback_list[-1] %}
<table class="traceback-frame first">
<tr class="traceback-frame-header">
<td width="100%" nowrap>
<h4>on line <span class="line-no">{{ line }}</span> of <span class="method">{{ method }}</span> in {{ os.path.basename(filepath) }}</h4>
</td>
<td nowrap>File: <strong>{{ filepath }}</strong></td>
</tr>
<tr class="traceback-frame-extended">
<td colspan="2">
{% set extension = os.path.splitext(filepath)[1][1:] %}
{% if extension in ['py', 'html', 'htm'] %}
<pre class="brush: {{ os.path.splitext(filepath)[1][1:] }}; ruler: true; toolbar: false; smart-tabs: true; first-line: {{ line-4 }}; highlight: {{ line }};">
{{ escape(get_snippet(filepath, line, 10)) }}
</pre>
{% else %}
<p>Cannot load file, type not supported.</p>
{% end %}
</td>
</tr>
</table>
<br />
<h3>Full Traceback</h3>
<sup>click each row to view full detail and source code snippet.</sup>
<div id="full-traceback">
{% for filepath, line, method, code in traceback_list %}
<table class="traceback-frame">
<tr class="traceback-frame-header">
<td width="100%" nowrap>
<h4>on line <span class="line-no">{{ line }}</span> of <span class="method">{{ method }}</span> in {{ os.path.basename(filepath) }}</h4>
</td>
<td nowrap>File: <strong>{{ filepath }}</strong></td>
</tr>
<tr class="traceback-frame-extended">
<td colspan="2">
{% set extension = os.path.splitext(filepath)[1][1:] %}
{% if extension in ['py', 'html', 'htm'] %}
<pre class="brush: {{ os.path.splitext(filepath)[1][1:] }}; ruler: true; toolbar: false; smart-tabs: true; first-line: {{ line-4 }}; highlight: {{ line }};">
{{ escape(get_snippet(filepath, line, 10)) }}
</pre>
{% else %}
<p>Cannot load file, type not supported.</p>
{% end %}
</td>
</tr>
</table>
<br />
{% end %}
</div>
<h3>Request Headers</h3>
<p>
<table width="100%">
{% for hk, hv in handler.request.headers.iteritems() %}
<tr>
<td class="key" nowrap>{{ hk }}</td>
<td class="value {{ cycle(('', 'alt')) }}" width="100%">{{ hv }}</td>
</tr>
{% end %}
</table>
</p>
<br />
<h3>Response Headers</h3>
<p>
<table width="100%">
{% for hk, hv in handler._headers.iteritems() %}
<tr>
<td class="key" nowrap>{{ hk }}</td>
<td class="value {{ cycle(('', 'alt')) }}" width="100%">{{ hv }}</td>
</tr>
{% end %}
</table>
</p>
{% end %}
<br />
<br />
<hr />
<p>
Tornado v{{ tornado.version }}
</p>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(e) {
$('#full-traceback .traceback-frame-extended').hide();
$('#full-traceback .traceback-frame-header').click(function(e) {
$(e.currentTarget).siblings('.traceback-frame-extended').toggle();
});
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment