2015-04-07 25 views
5

Alt alan adı aracılığıyla bir kiracıyı yükleyen ve bazı varsayılan ayarları uygulayan bir parça Raf ara parçam var. Middleware, hoş değil, yeterince iyi iş yapar. Ancak, app içinde bir istisna atıldığında, middleware tam yığın izini "yakalar". Tuzak dediğimde, beklenen yığın izini gizler.Raf aracı "yığın yakalama" yığın izlemesi

İşte bir örnek.

ben şöyle bir bir kontrolör eylem istisna atan ediyorum:

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

Sen yığın izleme bu konuma başvuruda olacağını beklenir ama öyle değil. Bunun yerine, ara katmandaki bir satıra başvurulur.

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' 

Bu neden oluyor? Daha önce böyle bir şey gördün mü?

# 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 

ben yakut 2.2.0p0 ve rails 4.1.8 çalıştırıyorum: Burada

ara yazılımdır.

Bunun için ağları aradım ama bir şey bulamadım çünkü muhtemelen doğru şey için çıraklık yapmıyorum.

Bunun neden olduğu ve neyi yanlış yaptığım hakkındaki düşünceler nelerdir?

Şerefe!

cevap

7

bakınız. Benim uygulama olarak kabul edilir içinde son satırın middleware olduğunu ortaya çıkıyor. Kodun geri kalanını components dizininde bulunan yerel bir ray motoruyla çalıştırıyordum. Tek yapmamız gereken, BacktraceCleaner için yeni bir susturucu yaratmaktı. Bildirim bileşenleri dir artık dahil edilmiştir.

# config/initializers/backtrace_silencers.rb 
Rails.backtrace_cleaner.remove_silencers! 
Rails.backtrace_cleaner.add_silencer { |line| line !~ /^\/(app|config|lib|test|components)/} 

Burada ilginizi çekiyorsan, raylar projesinde bu makalenin nasıl çoğaltılacağına dair bir sorun var. https://github.com/rails/rails/issues/22265

0

Yanlış bir şey yapmıyorsunuz. Ancak, bir çok middleware, Rack'u otomatik olarak geliştirme modunda ekleyen ara katman dahil olmak üzere temizleme yapmak için istisnalar yapar. yakalanmamış özel durumları yakalamak ve makul bir HTML sayfası yerine bir ham yığın dökümü verecektir gelişiminde sokulan belirli Raf katman vardır (genellikle yaygın uygulama sunucuları ile hiç görmez.)

  • yapabilirsiniz Üst seviyenin etrafında bir başlangıç ​​/ kurtarma/sonu koyarak istisnayı kendiniz yakalayın. Her şeyi almak istiyorsanız, argüman olmadan sadece varsayılan "kurtarma" yi değil, "İstisna" nı yakalamayı unutmayın.
  • Eğer bu kodu terk ederseniz istisnai durumu yeniden atamak isteyebilirsiniz. Üretim modunda çalıştırabilirsiniz - bu, ara katman yazılımının Rack tarafından otomatik olarak eklenmesini durdurabilir.
  • Hangi middleware'in eklendiğini öğrenebilirsiniz (Rails: "rake middleware") ve sonra middleware'i (Rails "config.middleware.delete" veya "config.middleware.disable") el ile kaldırın.

Başka yöntemler de vardır.

3

Ara katman yazılımınız iyi görünüyor. Bence backtrace_cleaner ayarında bir sorun var. Belki de temizleyici bir 3. parti mücevher tarafından geçersiz kılınır. Hata yetiştirme önce kontrol işlemi yönteminde bir kesme noktası (ayıklayıcı) koymak deneyin ve baskı:

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

olmayan uygulama izleri kapalı şerit her susturucuların kaynak yerleri görmek için. Varsayılan olarak, sadece rails-4.1.8/lib/raylar/backtrace_cleaner'da bulunan Rails :: BacktraceCleaner kullanmalıdır.rb

doğrudan susturucu kaynak kodunu görmek için:

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

Sonunda bu çözüm bulundu daha fazla 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