Pobierz bieżący ślad stosu w Rubim bez zgłaszania wyjątku


139

Chcę rejestrować bieżący ślad śledzenia (stacktrace) w aplikacji Rails 3 bez wystąpienia wyjątku. Każdy pomysł jak?

Dlaczego tego chcę? Próbuję prześledzić wywołania, które są wykonywane, gdy Railsy szukają szablonu, aby móc wybrać część procesu do przesłonięcia (ponieważ chcę zmienić ścieżkę widoku dla określonego mojego kontrolera podklasy).

Chciałbym wywołać ją z pliku: gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb. Wiem, że to nie jest najlepsza praktyka, ale wiem, że jest to poniżej stosu, z którego następuje wyszukiwanie szablonów.


4
Brudne rozwiązanie: zgłoś tam wyjątek, natychmiast go uratuj i zarejestruj e.backtrace. Widziałem to w jednym z projektów, nad którymi pracuję. Nie jest to najmilsze podejście, ale działa. Mam jednak nadzieję, że ktoś inny usłyszy lepsze rozwiązanie.
KL-7

Odpowiedzi:


185

Możesz użyć Kernel#caller:

# /tmp/caller.rb

def foo 
  puts caller # Kernel#caller returns an array of strings
end

def bar 
  foo 
end

def baz 
  bar 
end

baz

Wynik:

caller.rb:8:in `bar'
caller.rb:12:in `baz'
caller.rb:15:in `<main>'

Czy to nie jest Kernel.caller- z kropką? Kernel.new.callernie jest tutaj zdefiniowane
ecoologic,

8
Nie, technicznie callerjest to metoda instancji. Ponieważ Kernelmoduł jest zawarty w każdej klasie Ruby (z wyjątkiem BasicObject1.9), jest dostępny jako metoda instancji na każdym obiekcie (chociaż jest prywatny). Nie możesz tego wywołać tak Kernel.new.callerpo prostu, ponieważ nie możesz utworzyć instancji modułu (nie ma on newmetody).
KL-7,

ten obsługuje parametr pomijania dowolnej liczby wywołujących; patrz: stackoverflow.com/a/3829269/520567
akostadinov

7
Do ładnego druku - Rails.logger.debug caller.join("\n")lub puts caller.join("\n"). Dzięki.
Jignesh Gohel

20

Spróbuj użyć

Thread.current.backtrace

1
Zaletą tej odpowiedzi jest to, że zawiera ona bieżącą metodę w śladzie wstecznym, podczas gdy Kernel#callerpomija bieżącą metodę. Np. MyClass.new.returns_caller => ["(irb):42:in 'irb_binding'",...] Nie jest tak pomocny jak MyClass.new.returns_thread_backtrace => ["(irb):38:in 'backtrace'","(irb):38:in 'returns_thread_backtrace'","(irb):43:in 'irb_binding'",...]
stwr667

6

Używam tego, aby wyświetlić niestandardową stronę błędu, gdy zostanie zgłoszony wyjątek.

rescue_from Exception do |exception|
  logger.error exception.class
  logger.error exception.message
  logger.error exception.backtrace.join "\n"
  @exception = exception


  # ExceptionNotifier::Notifier.exception_notification env, @exception

  respond_to do |format|
    if [AbstractController::ActionNotFound, ActiveRecord::RecordNotFound, ActionController::RoutingError, ActionController::UnknownAction].include?(exception.class)
      format.html { render :template => "errors/404", :status => 404 }
      format.js   { render :nothing => true, :status => 404 }
      format.xml  { render :nothing => true, :status => 404 }
    elsif exception.class == CanCan::AccessDenied
      format.html {
        render :template => "errors/401", :status => 401 #, :layout => 'application'
      }
      # format.js   { render :json => { :errors => [exception.message] }, :status => 401 }
      # format.js   { render :js => 'alert("Hello 401")' }
      format.js   { render :template => 'errors/401.js.erb' }

    else
      ExceptionNotifier::Notifier.exception_notification(env, exception).deliver        
      format.html { render :template => "errors/500", :status => 500 } #, :layout => 'im2/application' }
      # format.js   { render :nothing => true, :status => 500 }
      format.js   { render :template => 'errors/500.js.erb' }

    end
  end
end
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.