2015-04-07 8 views
5

Ich habe ein Stück Rack-Middleware, die einen Mandanten über Subdomain lädt und einige Standardeinstellungen anwendet. Die Middleware ist zwar nicht hübsch, aber es ist gut genug. Wenn jedoch eine Ausnahme in der App ausgelöst wird, "fängt" die Middleware den vollständigen Stack-Trace ab. Wenn ich Trap sage, bedeutet das, dass es die erwartete Stack-Spur versteckt.Rack-Middleware "Trapping" Stack-Trace

Hier ist ein Beispiel.

ich wie so eine Ausnahme in einer ein Controller-Aktion werfe:

def index 
    throw "Exception in a Rails controller action" 
    @taxonomies = Spree::Taxonomy.all 
end 

Sie würden erwarten, dass der Stack-Trace diese Position verweisen würde, aber es funktioniert nicht. Stattdessen referenzieren Sie eine Zeile in der Middleware.

Completed 500 Internal Server Error in 139ms 

UncaughtThrowError (uncaught throw "Exception in a Rails controller action"): 
lib/tenant_manager/middleware/loader.rb:42:in `call' 

Warum passiert das? Hast du so etwas schon mal gesehen? Hier

ist die Middleware:

# lib/tenant_manager/middleware/loader.rb 
module TenantManager 
    module Middleware 
    class Loader 
    # Middleware to detect an tenant via subdomain early in 
    # the request process 
    # 
    # Usage: 
    # # config/application.rb 
    # config.middleware.use TenantManager::Middleware::Loader 
    # 
    # A scaled down version of https://github.com/radar/houser 

     def initialize(app) 
     @app = app 
     end 

     def call(env) 
     domain_parts = env['HTTP_HOST'].split('.') 
     if domain_parts.length > 2 
      subdomain = domain_parts.first 
      tenant = Leafer::Tenant.find_by_database(subdomain) 
      if tenant 
      ENV['CURRENT_TENANT_ID'] = tenant.id.to_s 
      ENV['RAILS_CACHE_ID'] = tenant.database 
      Spree::Image.change_paths tenant.database 
      Apartment::Tenant.process(tenant.database) do 
       country = Spree::Country.find_by_name('United States') 
       Spree.config do |config| 
       config.default_country_id = country.id if country.present? 
       config.track_inventory_levels = false 
       end 
       Spree::Auth::Config.set(:registration_step => false) 
      end 
      end 
     else 
      ENV['CURRENT_TENANT_ID'] = nil 
      ENV['RAILS_CACHE_ID'] = "" 
     end 
     @app.call(env) 
     end 

    end 
    end 
end 

Ich bin mit Rubin 2.2.0p0 und rails 4.1.8.

Ich habe die Webs nach diesem gesucht, konnte aber nichts finden, wahrscheinlich, weil ich nicht für das richtige Ding serching bin.

Irgendwelche Gedanken darüber, warum das passiert und was ich falsch mache?

Prost!

Antwort

7

Ich fand schließlich die Lösung dieses Problems. Es stellt sich heraus, dass die letzte Zeile in meiner Anwendung in der Middleware liegt. Ich habe den Rest des Codes in einem lokalen Rails-Modul ausgeführt, das sich in einem components-Verzeichnis befindet. Alles, was wir tun mussten, war einen neuen Schalldämpfer für BacktraceCleaner zu schaffen. Notice components dir ist jetzt enthalten.

Wenn Sie interessiert sind, hier ist ein Problem, das ich auf dem Schienen Projekt über die Replikation im Detail veröffentlicht. https://github.com/rails/rails/issues/22265

0

Sie machen nichts falsch. Viele Middleware-Anwendungen schließen jedoch Ausnahmen aus, um Bereinigungen vorzunehmen, einschließlich der Middleware, die Rack automatisch in den Entwicklungsmodus einfügt. Es gibt eine spezielle Rack-Middleware in der Entwicklung eingesetzt, die nicht abgefangene Ausnahmen und geben eine vernünftige HTML-Seite anstelle eines rohen Stack Dump fangen wird (die man oft gar nicht mit gemeinsamen Applikationsserver werden sehen.)

  • Sie können Fange die Ausnahme selbst an, indem du ein Start/Rescue/Ende um deine Toplevel machst. Denken Sie daran, "Ausnahme" zu fangen, nicht nur die Standard "Rettung" ohne Arg, wenn Sie alles bekommen wollen. Vielleicht möchten Sie die Ausnahme erneut auslösen, wenn Sie diesen Code belassen möchten.
  • Sie können im Produktionsmodus arbeiten - das könnte verhindern, dass die Middleware automatisch von Rack eingefügt wird.
  • Sie können herausfinden, welche Middleware eingefügt wird (in Rails: "Rake Middleware") und dann die Middleware manuell entfernen (in Rails "config.middleware.delete" oder "config.middleware.disable").

Es gibt wahrscheinlich andere Methoden.

3

Ihre Middleware scheint gut zu sein. Ich denke, du hast ein Problem mit deiner backtrace_cleaner-Einstellung. Vielleicht wird der Reiniger von einem Edelstein der dritten Partei übersteuert. Versuchen, einen Haltepunkt (Debugger) in der Steuerung Aktionsmethode vor der Fehlerbildung, und Druck:

puts env['action_dispatch.backtrace_cleaner'].instance_variable_get(:@silencers).map(&:source_location).map{|l| l.join(':')} 

die Quell Standorte aller Schalldämpfern, um zu sehen, welche nicht-app Spuren abzustreifen. Standardmäßig sollte nur Rails :: BacktraceCleaner verwendet werden, der unter railties-4.1.8/lib/rails/backtrace_cleaner gefunden wird.rb

direkt auf den Schalldämpfer Quellcode sehen:

puts env['action_dispatch.backtrace_cleaner'].instance_variable_get(:@silencers).map{|s| RubyVM::InstructionSequence.disasm s } 

Mehr von https://github.com/rails/rails/blob/master/railties/lib/rails/backtrace_cleaner.rb https://github.com/rails/rails/blob/master/activesupport/lib/active_support/backtrace_cleaner.rb