提交 731dcd84 编写于 作者: J Joshua Peek

Silence server backtrace in rescue templates and log files. Also remove some...

Silence server backtrace in rescue templates and log files. Also remove some noise from missing template errors.
上级 9c9da6c8
module ActionController #:nodoc:
# Actions that fail to perform as expected throw exceptions. These exceptions can either be rescued for the public view
# (with a nice user-friendly explanation) or for the developers view (with tons of debugging information). The developers view
# is already implemented by the Action Controller, but the public view should be tailored to your specific application.
#
# The default behavior for public exceptions is to render a static html file with the name of the error code thrown. If no such
# file exists, an empty response is sent with the correct status code.
# Actions that fail to perform as expected throw exceptions. These
# exceptions can either be rescued for the public view (with a nice
# user-friendly explanation) or for the developers view (with tons of
# debugging information). The developers view is already implemented by
# the Action Controller, but the public view should be tailored to your
# specific application.
#
# You can override what constitutes a local request by overriding the <tt>local_request?</tt> method in your own controller.
# Custom rescue behavior is achieved by overriding the <tt>rescue_action_in_public</tt> and <tt>rescue_action_locally</tt> methods.
# The default behavior for public exceptions is to render a static html
# file with the name of the error code thrown. If no such file exists, an
# empty response is sent with the correct status code.
#
# You can override what constitutes a local request by overriding the
# <tt>local_request?</tt> method in your own controller. Custom rescue
# behavior is achieved by overriding the <tt>rescue_action_in_public</tt>
# and <tt>rescue_action_locally</tt> methods.
module Rescue
LOCALHOST = '127.0.0.1'.freeze
......@@ -32,6 +38,9 @@ module Rescue
'ActionView::TemplateError' => 'template_error'
}
RESCUES_TEMPLATE_PATH = ActionView::PathSet::Path.new(
"#{File.dirname(__FILE__)}/templates", true)
def self.included(base) #:nodoc:
base.cattr_accessor :rescue_responses
base.rescue_responses = Hash.new(DEFAULT_RESCUE_RESPONSE)
......@@ -56,12 +65,15 @@ def process_with_exception(request, response, exception) #:nodoc:
end
protected
# Exception handler called when the performance of an action raises an exception.
# Exception handler called when the performance of an action raises
# an exception.
def rescue_action(exception)
rescue_with_handler(exception) || rescue_action_without_handler(exception)
rescue_with_handler(exception) ||
rescue_action_without_handler(exception)
end
# Overwrite to implement custom logging of errors. By default logs as fatal.
# Overwrite to implement custom logging of errors. By default
# logs as fatal.
def log_error(exception) #:doc:
ActiveSupport::Deprecation.silence do
if ActionView::TemplateError === exception
......@@ -75,16 +87,19 @@ def log_error(exception) #:doc:
end
end
# Overwrite to implement public exception handling (for requests answering false to <tt>local_request?</tt>). By
# default will call render_optional_error_file. Override this method to provide more user friendly error messages.
# Overwrite to implement public exception handling (for requests
# answering false to <tt>local_request?</tt>). By default will call
# render_optional_error_file. Override this method to provide more
# user friendly error messages.
def rescue_action_in_public(exception) #:doc:
render_optional_error_file response_code_for_rescue(exception)
end
# Attempts to render a static error page based on the <tt>status_code</tt> thrown,
# or just return headers if no such file exists. For example, if a 500 error is
# being handled Rails will first attempt to render the file at <tt>public/500.html</tt>.
# If the file doesn't exist, the body of the response will be left empty.
# Attempts to render a static error page based on the
# <tt>status_code</tt> thrown, or just return headers if no such file
# exists. For example, if a 500 error is being handled Rails will first
# attempt to render the file at <tt>public/500.html</tt>. If the file
# doesn't exist, the body of the response will be left empty.
def render_optional_error_file(status_code)
status = interpret_status(status_code)
path = "#{Rails.public_path}/#{status[0,3]}.html"
......@@ -106,11 +121,13 @@ def local_request? #:doc:
# a controller action.
def rescue_action_locally(exception)
@template.instance_variable_set("@exception", exception)
@template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
@template.instance_variable_set("@contents", @template.render(:file => template_path_for_local_rescue(exception)))
@template.instance_variable_set("@rescues_path", RESCUES_TEMPLATE_PATH)
@template.instance_variable_set("@contents",
@template.render(:file => template_path_for_local_rescue(exception)))
response.content_type = Mime::HTML
render_for_file(rescues_path("layout"), response_code_for_rescue(exception))
render_for_file(rescues_path("layout"),
response_code_for_rescue(exception))
end
def rescue_action_without_handler(exception)
......@@ -138,7 +155,7 @@ def perform_action_with_rescue #:nodoc:
end
def rescues_path(template_name)
"#{File.dirname(__FILE__)}/templates/rescues/#{template_name}.erb"
RESCUES_TEMPLATE_PATH["rescues/#{template_name}.erb"]
end
def template_path_for_local_rescue(exception)
......@@ -150,8 +167,9 @@ def response_code_for_rescue(exception)
end
def clean_backtrace(exception)
defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ?
Rails.backtrace_cleaner.clean(exception.backtrace) : exception.backtrace
defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ?
Rails.backtrace_cleaner.clean(exception.backtrace) :
exception.backtrace
end
end
end
......@@ -6,6 +6,6 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
<%= render(:file => @rescues_path + "/_trace.erb") %>
<%= render :file => @rescues_path["rescues/_trace.erb"] %>
<%= render(:file => @rescues_path + "/_request_and_response.erb") %>
<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
......@@ -15,7 +15,7 @@
<% @real_exception = @exception
@exception = @exception.original_exception || @exception %>
<%= render(:file => @rescues_path + "/_trace.erb") %>
<%= render :file => @rescues_path["rescues/_trace.erb"] %>
<% @exception = @real_exception %>
<%= render(:file => @rescues_path + "/_request_and_response.erb") %>
<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
......@@ -5,7 +5,7 @@ class ActionViewError < StandardError #:nodoc:
class MissingTemplate < ActionViewError #:nodoc:
def initialize(paths, path, template_format = nil)
full_template_path = path.include?('.') ? path : "#{path}.erb"
display_paths = paths.join(':')
display_paths = paths.compact.join(":")
template_type = (path =~ /layouts/i) ? 'layout' : 'template'
super("Missing #{template_type} #{full_template_path} in view path #{display_paths}")
end
......
......@@ -41,7 +41,7 @@ def unshift(*objs)
class Path #:nodoc:
attr_reader :path, :paths
delegate :to_s, :to_str, :hash, :inspect, :to => :path
delegate :hash, :inspect, :to => :path
def initialize(path, load = false)
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
......@@ -49,6 +49,14 @@ def initialize(path, load = false)
reload! if load
end
def to_s
if defined?(RAILS_ROOT)
path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '')
else
path.to_s
end
end
def ==(path)
to_str == path.to_str
end
......
......@@ -43,29 +43,29 @@ def teardown
end
def test_template_load_path_was_set_correctly
assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
end
def test_controller_appends_view_path_correctly
@controller.append_view_path 'foo'
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s)
@controller.append_view_path(%w(bar baz))
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
@controller.append_view_path(FIXTURE_LOAD_PATH)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
end
def test_controller_prepends_view_path_correctly
@controller.prepend_view_path 'baz'
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
@controller.prepend_view_path(%w(foo bar))
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
@controller.prepend_view_path(FIXTURE_LOAD_PATH)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
end
def test_template_appends_view_path_correctly
......@@ -73,10 +73,10 @@ def test_template_appends_view_path_correctly
class_view_paths = TestController.view_paths
@controller.append_view_path 'foo'
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s)
@controller.append_view_path(%w(bar baz))
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
assert_equal class_view_paths, TestController.view_paths
end
......@@ -85,10 +85,10 @@ def test_template_prepends_view_path_correctly
class_view_paths = TestController.view_paths
@controller.prepend_view_path 'baz'
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
@controller.prepend_view_path(%w(foo bar))
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_equal class_view_paths, TestController.view_paths
end
......@@ -130,12 +130,12 @@ class C < ActionController::Base; end
A.view_paths = ['a/path']
assert_equal ['a/path'], A.view_paths
assert_equal ['a/path'], A.view_paths.map(&:to_s)
assert_equal A.view_paths, B.view_paths
assert_equal original_load_paths, C.view_paths
C.view_paths = []
assert_nothing_raised { C.view_paths << 'c/path' }
assert_equal ['c/path'], C.view_paths
assert_equal ['c/path'], C.view_paths.map(&:to_s)
end
end
......@@ -11,10 +11,11 @@ class Exception # :nodoc:
def clean_message
Pathname.clean_within message
end
TraceSubstitutions = []
FrameworkRegexp = /generated|vendor|dispatch|ruby|script\/\w+/
FrameworkStart = /action_controller\/dispatcher\.rb/.freeze
FrameworkRegexp = /generated|vendor|dispatch|ruby|script\/\w+/.freeze
def clean_backtrace
backtrace.collect do |line|
Pathname.clean_within(TraceSubstitutions.inject(line) do |result, (regexp, sub)|
......@@ -22,20 +23,22 @@ def clean_backtrace
end)
end
end
def application_backtrace
before_framework_frame = nil
before_application_frame = true
trace = clean_backtrace.reject do |line|
before_framework_frame ||= (line =~ FrameworkStart)
non_app_frame = (line =~ FrameworkRegexp)
before_application_frame = false unless non_app_frame
non_app_frame && ! before_application_frame
before_framework_frame || (non_app_frame && !before_application_frame)
end
# If we didn't find any application frames, return an empty app trace.
before_application_frame ? [] : trace
end
def framework_backtrace
clean_backtrace.grep FrameworkRegexp
end
......
......@@ -3,7 +3,9 @@ class BacktraceCleaner < ActiveSupport::BacktraceCleaner
ERB_METHOD_SIG = /:in `_run_erb_.*/
VENDOR_DIRS = %w( vendor/plugins vendor/gems vendor/rails )
SERVER_DIRS = %w( lib/mongrel bin/mongrel lib/rack )
SERVER_DIRS = %w( lib/mongrel bin/mongrel
lib/passenger bin/passenger-spawn-server
lib/rack )
RAILS_NOISE = %w( script/server )
RUBY_NOISE = %w( rubygems/custom_require benchmark.rb )
......@@ -30,4 +32,4 @@ def filter_backtrace_with_cleaning(backtrace, prefix=nil)
Rails.backtrace_cleaner.clean(backtrace)
end
end
end
\ No newline at end of file
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册