2008-11-22 12:06:08 -05:00
|
|
|
module ActiveSupport
|
|
|
|
# Many backtraces include too much information that's not relevant for the context. This makes it hard to find the signal
|
|
|
|
# in the backtrace and adds debugging time. With a BacktraceCleaner, you can setup filters and silencers for your particular
|
|
|
|
# context, so only the relevant lines are included.
|
|
|
|
#
|
|
|
|
# If you need to reconfigure an existing BacktraceCleaner, like the one in Rails, to show as much as possible, you can always
|
2010-03-27 12:47:39 -04:00
|
|
|
# call BacktraceCleaner#remove_silencers! Also, if you need to reconfigure an existing BacktraceCleaner so that it does not
|
|
|
|
# filter or modify the paths of any lines of the backtrace, you can call BacktraceCleaner#remove_filters! These two methods
|
|
|
|
# will give you a completely untouched backtrace.
|
2008-11-22 12:06:08 -05:00
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# bc = BacktraceCleaner.new
|
2010-01-16 22:34:35 -05:00
|
|
|
# bc.add_filter { |line| line.gsub(Rails.root, '') }
|
2008-11-22 12:06:08 -05:00
|
|
|
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
|
|
|
|
# bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
|
|
|
|
#
|
|
|
|
# Inspired by the Quiet Backtrace gem by Thoughtbot.
|
|
|
|
class BacktraceCleaner
|
|
|
|
def initialize
|
|
|
|
@filters, @silencers = [], []
|
|
|
|
end
|
2010-01-16 22:34:35 -05:00
|
|
|
|
2008-11-22 12:06:08 -05:00
|
|
|
# Returns the backtrace after all filters and silencers has been run against it. Filters run first, then silencers.
|
2010-01-16 22:34:35 -05:00
|
|
|
def clean(backtrace, kind = :silent)
|
|
|
|
filtered = filter(backtrace)
|
|
|
|
|
|
|
|
case kind
|
|
|
|
when :silent
|
|
|
|
silence(filtered)
|
|
|
|
when :noise
|
|
|
|
noise(filtered)
|
|
|
|
else
|
|
|
|
filtered
|
|
|
|
end
|
2008-11-22 12:06:08 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
# Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
|
|
|
|
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
|
|
|
|
def add_filter(&block)
|
|
|
|
@filters << block
|
|
|
|
end
|
|
|
|
|
|
|
|
# Adds a silencer from the block provided. If the silencer returns true for a given line, it'll be excluded from the
|
|
|
|
# clean backtrace.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
|
|
|
|
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
|
|
|
|
def add_silencer(&block)
|
|
|
|
@silencers << block
|
|
|
|
end
|
|
|
|
|
|
|
|
# Will remove all silencers, but leave in the filters. This is useful if your context of debugging suddenly expands as
|
|
|
|
# you suspect a bug in the libraries you use.
|
|
|
|
def remove_silencers!
|
|
|
|
@silencers = []
|
|
|
|
end
|
|
|
|
|
2010-03-27 12:47:39 -04:00
|
|
|
def remove_filters!
|
|
|
|
@filters = []
|
|
|
|
end
|
|
|
|
|
2008-11-22 12:06:08 -05:00
|
|
|
private
|
|
|
|
def filter(backtrace)
|
|
|
|
@filters.each do |f|
|
|
|
|
backtrace = backtrace.map { |line| f.call(line) }
|
|
|
|
end
|
2010-01-16 22:34:35 -05:00
|
|
|
|
2008-11-22 12:06:08 -05:00
|
|
|
backtrace
|
|
|
|
end
|
2010-01-16 22:34:35 -05:00
|
|
|
|
2008-11-22 12:06:08 -05:00
|
|
|
def silence(backtrace)
|
|
|
|
@silencers.each do |s|
|
|
|
|
backtrace = backtrace.reject { |line| s.call(line) }
|
|
|
|
end
|
2010-01-16 22:34:35 -05:00
|
|
|
|
|
|
|
backtrace
|
|
|
|
end
|
|
|
|
|
|
|
|
def noise(backtrace)
|
|
|
|
@silencers.each do |s|
|
|
|
|
backtrace = backtrace.select { |line| s.call(line) }
|
|
|
|
end
|
|
|
|
|
2008-11-22 12:06:08 -05:00
|
|
|
backtrace
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|