2012-06-20 4 views
108

Я хочу зарегистрировать текущую обратную трассировку (stacktrace) в приложении Rails 3 без возникшее исключение. Любая идея как?Получить текущую трассировку стека в Ruby без повышения исключения

Почему я хочу этого? Я пытаюсь отслеживать вызовы, которые выполняются, когда Rails ищет шаблон, чтобы я мог выбрать часть процесса для переопределения (потому что я хочу изменить путь представления для отдельного контроллера подкласса).

Я бы назвал это из файла: gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb. Я знаю, что это не лучшая практика, но я знаю, что она находится ниже по потоку от стека, откуда происходит поиск шаблонов.

+4

Грязного решение: поднять исключение там, спасти его немедленно и войти 'e.backtrace'. Я видел это в одном из проектов, над которыми я работаю. Не самый приятный подход, но он работает. Надеюсь услышать лучшее решение от кого-то еще. –

+0

Блестящий. Спасибо. – JellicleCat

ответ

155

Вы можете использовать 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 

Выход:

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

Очень удобно, очень просто - спасибо! –

+0

Разве это не 'Kernel.caller' - с точкой? 'Kernel.new.caller' здесь не определен – ecoologic

+7

Нет, технически' caller' является методом экземпляра. Поскольку модуль «Kernel» включен в каждый класс Ruby (кроме «BasicObject» в версии 1.9), он доступен как метод экземпляра для любого объекта (он частный, хотя). Вы не можете назвать его как «Kernel.new.caller» просто потому, что вы не можете создать экземпляр модуля (у него нет метода 'new'). –

3

Я использую это, чтобы показать страницу ошибки, когда исключение приподняты.

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 
5

Попробуйте использовать

Thread.current.backtrace 
Смежные вопросы