Skip to content

Commit 9ac526a

Browse files
committed
Unsilence BacktraceCleaner with BACKTRACE without removing silencers
rails/rails@957a3e5 allowed the BACKTRACE env to unsilence backtraces in normals runs not just tests. However, the implementation achieves this by removing the silences in an initializer. This means that the state of backtrace silencer becomes cached by spring and the developer needs to reset spring every time they want to silence or unsilence the backtrace. It also means custom silencers added in an initializer need to be added after the :configure_backtrace_cleaner initializer or else they won't be un-silenced properly. Instead, let's teach Rails::BacktraceCleaner to unsilence the backtrace if the BACKTRACE variable is set. ActiveSupport::BacktraceCleaner#clean already allows this by passing nil as the second argument, which just filters but does not silence the backtrace. So, in Rails::BacktraceCleaner#clean we can call super with nil in the second argument if the BACKTRACE variable is present. That way we do not need to remove the silencers in an initializer, and we don't have to reset spring to silence the backtrace.
1 parent f04c59b commit 9ac526a

File tree

3 files changed

+45
-49
lines changed

3 files changed

+45
-49
lines changed

railties/lib/rails/application/bootstrap.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@ module Bootstrap
7575
end
7676
end
7777

78-
initializer :configure_backtrace_cleaner, group: :all do
79-
Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
80-
end
81-
8278
# Initialize cache early in the stack so railties can make use of it.
8379
initializer :initialize_cache, group: :all do
8480
cache_format_version = config.active_support.delete(:cache_format_version)

railties/lib/rails/backtrace_cleaner.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,18 @@ def initialize
2525
end
2626
add_silencer { |line| !APP_DIRS_PATTERN.match?(line) }
2727
end
28+
29+
def clean(backtrace, kind = :silent)
30+
kind = nil if ENV["BACKTRACE"]
31+
32+
super(backtrace, kind)
33+
end
34+
alias_method :filter, :clean
35+
36+
def clean_frame(frame, kind = :silent)
37+
kind = nil if ENV["BACKTRACE"]
38+
39+
super(frame, kind)
40+
end
2841
end
2942
end
Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,55 @@
11
# frozen_string_literal: true
22

3-
require "isolation/abstract_unit"
4-
require "rack/test"
53
require "env_helpers"
64

75
module ApplicationTests
86
class BacktraceCleanerTest < ActiveSupport::TestCase
9-
include ActiveSupport::Testing::Isolation
10-
include Rack::Test::Methods
117
include EnvHelpers
128

13-
def teardown
14-
teardown_app
9+
setup do
10+
@cleaner = Rails::BacktraceCleaner.new
1511
end
1612

17-
test "backtrace is cleaned" do
18-
setup_app
13+
test "#clean silences Rails code from backtrace" do
14+
backtrace = [
15+
"app/controllers/foo_controller.rb:4:in 'index'",
16+
"rails/railties/lib/rails/engine.rb:536:in `call"
17+
]
1918

20-
app("development")
21-
get "/"
22-
if RUBY_VERSION >= "3.4"
23-
assert_includes last_response.body, "app/app/controllers/foo_controller.rb:4:in 'FooController#index'"
24-
else
25-
assert_includes last_response.body, "app/app/controllers/foo_controller.rb:4:in `index'"
26-
end
27-
assert_not_includes last_response.body, "rails/railties/test/env_helpers.rb"
19+
cleaned = @cleaner.clean(backtrace)
20+
21+
assert_equal ["app/controllers/foo_controller.rb:4:in 'index'"], cleaned
2822
end
2923

30-
test "backtrace is not cleaned" do
24+
test "#clean does not silence when BACKTRACE is set" do
3125
switch_env("BACKTRACE", "1") do
32-
setup_app
26+
backtrace = [
27+
"app/app/controllers/foo_controller.rb:4:in 'index'",
28+
"/rails/railties/lib/rails/engine.rb:536:in `call"
29+
]
30+
31+
cleaned = @cleaner.clean(backtrace)
3332

34-
app("development")
35-
get "/"
36-
if RUBY_VERSION >= "3.4"
37-
assert_includes last_response.body, "app/app/controllers/foo_controller.rb:4:in 'FooController#index'"
38-
else
39-
assert_includes last_response.body, "app/app/controllers/foo_controller.rb:4:in `index'"
40-
end
41-
assert_includes last_response.body, "rails/railties/test/env_helpers.rb"
33+
assert_equal backtrace, cleaned
4234
end
4335
end
4436

45-
private
46-
def setup_app
47-
build_app
37+
test "#clean_frame silences Rails code" do
38+
frame = "rails/railties/lib/rails/engine.rb:536:in `call"
4839

49-
controller :foo, <<-RUBY
50-
class FooController < ApplicationController
51-
def index
52-
begin
53-
raise "ERROR"
54-
rescue StandardError => e
55-
render plain: e.backtrace.join("\n")
56-
end
57-
end
58-
end
59-
RUBY
40+
cleaned = @cleaner.clean_frame(frame)
41+
42+
assert_equal nil, cleaned
43+
end
6044

61-
app_file "config/routes.rb", <<-RUBY
62-
Rails.application.routes.draw do
63-
root to: "foo#index"
64-
end
65-
RUBY
45+
test "#clean_frame does not silence when BACKTRACE is set" do
46+
switch_env("BACKTRACE", "1") do
47+
frame = "rails/railties/lib/rails/engine.rb:536:in `call"
48+
49+
cleaned = @cleaner.clean_frame(frame)
50+
51+
assert_equal frame, cleaned
6652
end
53+
end
6754
end
6855
end

0 commit comments

Comments
 (0)