Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get "Application Trace" instead of full verbose backtrace in Rails?

In Rails default error page of development environment, you can view three backtraces, 1. Application Trace, 2. Framework Trace and 3. Full Trace.

But how can I get "Application Trace" in Rails controllers. Full Trace (exception.backtrace) is too much for me. Now I'm doing like this:

exception.backtrace.select {|line| line =~ /myappname/i }

Is this a correct way? Or are there other cooler ways to get it?

like image 830
chikaram Avatar asked Feb 24 '14 05:02

chikaram


1 Answers

I looked up rails sources to see how it is implemented. ActionSupport has class BacktraceCleaner, which is self describable I guess. Using it Rails adds filters to backtraces: in ActionDispatch::ExceptionWrapper :

def application_trace
  clean_backtrace(:silent)
end

def framework_trace
  clean_backtrace(:noise)
end

def full_trace
  clean_backtrace(:all)
end

clean_backtrace turns out to be calling clean method on instance of BacktraceCleaner (available for users in Rails.backtrace_cleaner), which, in turn, just applies filters. You can read rails/active_support/lib/active_support/backtrace_cleaner.rb to see how it is implemented, I can assure you it's very simple.

Actual filters for application backtrace are defined in railties/lib/rails/backtrace_cleaner.rb:

module Rails
  class BacktraceCleaner < ActiveSupport::BacktraceCleaner
    APP_DIRS_PATTERN = /^\/?(app|config|lib|test)/
    RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/

    def initialize
      super
      add_filter   { |line| line.sub("#{Rails.root}/", '') }
      add_filter   { |line| line.sub(RENDER_TEMPLATE_PATTERN, '') }
      add_filter   { |line| line.sub('./', '/') } # for tests

      add_gem_filters
      add_silencer { |line| line !~ APP_DIRS_PATTERN }
    end

    private
      def add_gem_filters
        gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
        return if gems_paths.empty?

        gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
        add_filter { |line| line.sub(gems_regexp, '\2 (\3) \4') }
      end
  end
end

And add_silencer, checking for APP_DIRS_PATTERN = /^\/?(app|config|lib|test)/ tells us that you was pretty much close :) don't be confused by filters: they just cut full path to files.

Having sad that, I suggest you use Rails.backtrace_cleaner for the job. It is cooler way that you are looking for

like image 105
lobanovadik Avatar answered Nov 11 '22 14:11

lobanovadik