PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/activesupport/lib/active_support/backtrace_cleaner.rb

https://github.com/stcatz/rails
Ruby | 99 lines | 49 code | 12 blank | 38 comment | 0 complexity | 6fbc625340d5fc4510a05b6f29060110 MD5 | raw file
  1. module ActiveSupport
  2. # Backtraces often include many lines that are not relevant for the context under review. This makes it hard to find the
  3. # signal amongst the backtrace noise, and adds debugging time. With a BacktraceCleaner, filters and silencers are used to
  4. # remove the noisy lines, so that only the most relevant lines remain.
  5. #
  6. # Filters are used to modify lines of data, while silencers are used to remove lines entirely. The typical filter use case
  7. # is to remove lengthy path information from the start of each line, and view file paths relevant to the app directory
  8. # instead of the file system root. The typical silencer use case is to exclude the output of a noisy library from the
  9. # backtrace, so that you can focus on the rest.
  10. #
  11. # ==== Example:
  12. #
  13. # bc = BacktraceCleaner.new
  14. # bc.add_filter { |line| line.gsub(Rails.root, '') }
  15. # bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
  16. # bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
  17. #
  18. # To reconfigure an existing BacktraceCleaner (like the default one in Rails) and show as much data as possible, you can
  19. # always call <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the backtrace to a pristine state. If you
  20. # need to reconfigure an existing BacktraceCleaner so that it does not filter or modify the paths of any lines of the
  21. # backtrace, you can call BacktraceCleaner#remove_filters! These two methods will give you a completely untouched backtrace.
  22. #
  23. # Inspired by the Quiet Backtrace gem by Thoughtbot.
  24. class BacktraceCleaner
  25. def initialize
  26. @filters, @silencers = [], []
  27. end
  28. # Returns the backtrace after all filters and silencers have been run against it. Filters run first, then silencers.
  29. def clean(backtrace, kind = :silent)
  30. filtered = filter(backtrace)
  31. case kind
  32. when :silent
  33. silence(filtered)
  34. when :noise
  35. noise(filtered)
  36. else
  37. filtered
  38. end
  39. end
  40. # Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
  41. #
  42. # Example:
  43. #
  44. # # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
  45. # backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
  46. def add_filter(&block)
  47. @filters << block
  48. end
  49. # Adds a silencer from the block provided. If the silencer returns true for a given line, it will be excluded from
  50. # the clean backtrace.
  51. #
  52. # Example:
  53. #
  54. # # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
  55. # backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
  56. def add_silencer(&block)
  57. @silencers << block
  58. end
  59. # Will remove all silencers, but leave in the filters. This is useful if your context of debugging suddenly expands as
  60. # you suspect a bug in one of the libraries you use.
  61. def remove_silencers!
  62. @silencers = []
  63. end
  64. def remove_filters!
  65. @filters = []
  66. end
  67. private
  68. def filter(backtrace)
  69. @filters.each do |f|
  70. backtrace = backtrace.map { |line| f.call(line) }
  71. end
  72. backtrace
  73. end
  74. def silence(backtrace)
  75. @silencers.each do |s|
  76. backtrace = backtrace.reject { |line| s.call(line) }
  77. end
  78. backtrace
  79. end
  80. def noise(backtrace)
  81. @silencers.each do |s|
  82. backtrace = backtrace.select { |line| s.call(line) }
  83. end
  84. backtrace
  85. end
  86. end
  87. end