160 votes

Obtenir la trace de la pile actuelle en Ruby sans lever une exception

Je veux enregistrer le backtrace actuel (stacktrace) dans une application Rails 3. sans une exception se produit. Vous savez comment ?

Pourquoi est-ce que je veux ça ? J'essaie de tracer les appels qui sont faits lorsque Rails cherche un modèle afin de pouvoir choisir une partie du processus à surcharger (parce que je veux changer le chemin de la vue pour un de mes contrôleurs sous-classés particuliers).

J'aimerais l'appeler depuis le dossier : gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb . Je sais que ce n'est pas la meilleure pratique, mais je sais que c'est en aval de la pile à partir de laquelle la recherche de modèles se fait.

4 votes

Sale solution : lever une exception à cet endroit, la sauver immédiatement et enregistrer e.backtrace . Je l'ai vu dans l'un des projets sur lesquels je travaille. Ce n'est pas l'approche la plus agréable, mais elle fonctionne. J'espère que quelqu'un d'autre trouvera une meilleure solution.

202voto

KL-7 Points 14154

Vous pouvez utiliser 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

Sortie :

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

0 votes

N'est-ce pas ? Kernel.caller - avec un point ? Kernel.new.caller n'est pas défini ici

8 votes

Non, techniquement caller est une méthode d'instance. Puisque Kernel est inclus dans chaque classe Ruby (à l'exception du module BasicObject en 1.9), elle est disponible comme méthode d'instance sur n'importe quel objet (elle est cependant privée). Vous ne pouvez pas l'appeler en tant que Kernel.new.caller simplement parce que vous ne pouvez pas instancier un module (il n'a pas de new méthode).

0 votes

Celui-ci supporte un paramètre permettant de sauter un nombre quelconque d'appelants ; voir : stackoverflow.com/a/3829269/520567

31voto

Rajat Bansal Points 549

Essayez d'utiliser

Thread.current.backtrace

7voto

Stefano Lampis Points 74

Je l'utilise pour afficher une page d'erreur personnalisée lorsqu'une exception est levée.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X