I use the Rails console in debug mode quite a lot, and its just a bit tedious having to change the size of the console window so I can find the top of the listing without having to scroll.
I thought the BacktraceCleaner could help with that, but I can't get it silence anything in the console.
I put this code in an initializer in my application.
bc = Rails.backtrace_cleaner
bc.add_filter { |line| line.gsub(Rails.root.to_s, '<root>') }
bc.add_silencer { |line| line.index('<root>').nil? and line.index('/') == 0 }
bc.add_silencer { |line| line.index('<root>/vendor/') == 0 }
bc.add_silencer { |line| line =~ /console.rb/ }
bc.add_silencer { |line| line =~ /ruby-debug.ide.rb/ }
bc.add_silencer { |line| line =~ /rdebug-ide/ }
but no effect on the console errors. So I tried it directly in the console:
>>bc = Rails.backtrace_cleaner
>>bc.add_silencer { |line| line =~ /console.rb/ }
>> 1/0
ZeroDivisionError: divided by 0
from (irb):23:in `/'
from (irb):23
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-4.0.3/lib/rails/commands /console.rb:90:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-4.0.3/lib/rails/commands/console.rb:9:in `start'
--and still seeing backtrace lines containing 'console.rb'. Is Rails.backtrace_cleaner returning some other cleaner that isn't the one used in the Rails console environment?
How can I get a handle to (or install) a backtrace cleaner on the console backtraces?
The problem is that the IRB console implements its own hard-wired backtrace silencer that is different from the Rails' one. But it can be overridden by monkey-patching IRB.
From IRB's source code we can see that the silencer is called here using the filter_backtrace
method from the WorkSpace class. Thus, we can patch this method to use the Rails silencer on top of the default IRB's one.
The patch could be put in a Rails initializer but a cleaner approach in my opinion is to use the IRB_RC
configuration variable that can be set to any ruby code and that will be called during IRB's initialization. Thus we'll keep the patch in IRB's context only and won't affect the Rails app code itself.
The following code goes to ~/.irbrc
:
if ENV['RAILS_ENV']
# silence console backtraces using BacktraceSilencer from Rails
IRB.conf[:IRB_RC] = Proc.new do
class IRB::WorkSpace
alias_method :orig_filter_backtrace, :filter_backtrace
def filter_backtrace(bt)
filtered_bt = orig_filter_backtrace(bt)
# The Rails silencer operates on the whole backtrace therefore
# we need to temporarily convert the particular trace line to an array
rails_backtrace_cleaner.clean(Array(filtered_bt)).first
end
private
def rails_backtrace_cleaner
Rails.backtrace_cleaner
end
end
end
end
As commented in the code, we need to deal with one small issue - the Rails silencer operates on the whole backtrace (passed as an array of lines), whereas the IRB's silencing method is called for each line separately. That's why the line is temporarily converted to an array before passing to the Rails silencer.
If you really want a custom silencer, not the Rails one, use something like this instead:
def rails_backtrace_cleaner
@rails_backtrace_cleaner ||= begin
bc = ActiveSupport::BacktraceCleaner.new
bc.add_filter { |line| line.gsub(Rails.root.to_s, '<root>') }
bc.add_silencer { |line| line.index('<root>').nil? and line.index('/') == 0 }
bc.add_silencer { |line| line.index('<root>/vendor/') == 0 }
bc.add_silencer { |line| line =~ /console.rb/ }
bc.add_silencer { |line| line =~ /ruby-debug.ide.rb/ }
bc.add_silencer { |line| line =~ /rdebug-ide/ }
bc
end
end
$ rails c
Loading development environment (Rails 4.2.5.1)
>> 1/0
ZeroDivisionError: divided by 0
>>
Example with an exception raised inside a model method:
$ rails c
Loading development environment (Rails 4.2.5.1)
>> BaseUser.find(1234).update_rating
RuntimeError: Exception occured!
from app/models/base_user.rb:51:in `update_rating'
>>
As can be seen, Rails internal stacktrace lines are silenced and Rails root paths are filtered out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With