提交 1ed264bc 编写于 作者: R Ryan Dao

Retrieve source code for the entire stack trace

Provide the ability to extract the source code of the entire exception stack
trace, not just the frame raising the error. This improves debugging
capability of the error page, especially for framework-related errors.
上级 30529dc0
......@@ -38,9 +38,7 @@ def render_exception(env, exception)
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
request: request,
exception: wrapper.exception,
application_trace: wrapper.application_trace,
framework_trace: wrapper.framework_trace,
full_trace: wrapper.full_trace,
traces: traces_from_wrapper(wrapper),
routes_inspector: routes_inspector(exception),
source_extract: wrapper.source_extract,
line_number: wrapper.line_number,
......@@ -95,5 +93,36 @@ def routes_inspector(exception)
ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
end
end
# Augment the exception traces by providing ids for all unique stack frame
def traces_from_wrapper(wrapper)
application_trace = wrapper.application_trace
framework_trace = wrapper.framework_trace
full_trace = wrapper.full_trace
if application_trace && framework_trace
id_counter = 0
application_trace = application_trace.map do |trace|
prev = id_counter
id_counter += 1
{ id: prev, trace: trace }
end
framework_trace = framework_trace.map do |trace|
prev = id_counter
id_counter += 1
{ id: prev, trace: trace }
end
full_trace = application_trace + framework_trace
end
{
"Application Trace" => application_trace,
"Framework Trace" => framework_trace,
"Full Trace" => full_trace
}
end
end
end
......@@ -61,12 +61,15 @@ def self.status_code_for_exception(class_name)
end
def source_extract
if application_trace && trace = application_trace.first
file, line, _ = trace.split(":")
@file = file
@line_number = line.to_i
source_fragment(@file, @line_number)
end
exception.backtrace.map do |trace|
file, line = trace.split(":")
line_number = line.to_i
{
code: source_fragment(file, line_number),
file: file,
line_number: line_number
}
end if exception.backtrace
end
private
......@@ -110,7 +113,7 @@ def source_fragment(path, line)
def expand_backtrace
@exception.backtrace.unshift(
@exception.to_s.split("\n")
).flatten!
).flatten!
end
end
end
<% if @source_extract %>
<div class="source">
<div class="info">
Extracted source (around line <strong>#<%= @line_number %></strong>):
</div>
<div class="data">
<table cellpadding="0" cellspacing="0" class="lines">
<tr>
<td>
<pre class="line_numbers">
<% @source_extract.keys.each do |line_number| %>
<% @source_extract.each_with_index do |extract_source, index| %>
<% if extract_source[:code] %>
<div class="source <%="hidden" if index != 0%>" id="frame-source-<%=index%>">
<div class="info">
Extracted source (around line <strong>#<%= extract_source[:line_number] %></strong>):
</div>
<div class="data">
<table cellpadding="0" cellspacing="0" class="lines">
<tr>
<td>
<pre class="line_numbers">
<% extract_source[:code].keys.each do |line_number| %>
<span><%= line_number -%></span>
<% end %>
</pre>
</td>
<% end %>
</pre>
</td>
<td width="100%">
<pre>
<% @source_extract.each do |line, source| -%><div class="line<%= " active" if line == @line_number -%>"><%= source -%></div><% end -%>
<% extract_source[:code].each do |line, source| -%><div class="line<%= " active" if line == extract_source[:line_number] -%>"><%= source -%></div><% end -%>
</pre>
</td>
</tr>
</table>
</div>
</div>
</tr>
</table>
</div>
</div>
<% end %>
<% end %>
<% end %>
<%
traces = { "Application Trace" => @application_trace,
"Framework Trace" => @framework_trace,
"Full Trace" => @full_trace }
names = traces.keys
%>
<% names = @traces.keys %>
<p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
......@@ -16,9 +11,42 @@
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
<% end %>
<% traces.each do |name, trace| %>
<% @traces.each do |name, trace| %>
<div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
<pre><code><%= trace.join "\n" %></code></pre>
<pre><code><% trace.each do |frame| %><a class="trace-frames" data-frame-id="<%= frame[:id] %>" href="#"><%= frame[:trace] %></a><br><% end %></code></pre>
</div>
<% end %>
<script type="text/javascript">
var traceFrames = document.getElementsByClassName('trace-frames');
var selectedFrame, currentSource = document.getElementById('frame-source-0');
// Add click listeners for all stack frames
for (var i = 0; i < traceFrames.length; i++) {
traceFrames[i].addEventListener('click', function(e) {
e.preventDefault();
var target = e.target;
var frame_id = target.dataset.frameId;
if (selectedFrame) {
selectedFrame.className = selectedFrame.className.replace("selected", "");
}
target.className += " selected";
selectedFrame = target;
// Change the extracted source code
changeSourceExtract(frame_id);
});
function changeSourceExtract(frame_id) {
var el = document.getElementById('frame-source-' + frame_id);
if (currentSource && el) {
currentSource.className += " hidden";
el.className = el.className.replace(" hidden", "");
currentSource = el;
}
}
}
</script>
</div>
<%
traces = { "Application Trace" => @application_trace,
"Framework Trace" => @framework_trace,
"Full Trace" => @full_trace }
%>
Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>
<% traces.each do |name, trace| %>
<% @traces.each do |name, trace| %>
<% if trace.any? %>
<%= name %>
<%= trace.join("\n") %>
<%= trace.map(&:trace).join("\n") %>
<% end %>
<% end %>
......@@ -116,9 +116,15 @@
background-color: #FFCCCC;
}
.hidden {
display: none;
}
a { color: #980905; }
a:visited { color: #666; }
a.trace-frames { color: #666; }
a:hover { color: #C52F24; }
a.trace-frames.selected { color: #C52F24 }
<%= yield :style %>
</style>
......
<% @source_extract = @exception.source_extract(0, :html) %>
<header>
<h1>
<%= @exception.original_exception.class.to_s %> in
......@@ -12,29 +11,7 @@
</p>
<pre><code><%= h @exception.message %></code></pre>
<div class="source">
<div class="info">
<p>Extracted source (around line <strong>#<%= @exception.line_number %></strong>):</p>
</div>
<div class="data">
<table cellpadding="0" cellspacing="0" class="lines">
<tr>
<td>
<pre class="line_numbers">
<% @source_extract.keys.each do |line_number| %>
<span><%= line_number -%></span>
<% end %>
</pre>
</td>
<td width="100%">
<pre>
<% @source_extract.each do |line, source| -%><div class="line<%= " active" if line == @exception.line_number -%>"><%= source -%></div><% end -%>
</pre>
</td>
</tr>
</table>
</div>
</div>
<%= render template: "rescues/_source" %>
<p><%= @exception.sub_template_message %></p>
......
<% @source_extract = @exception.source_extract(0, :html) %>
<%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册