我有一个Rack中间件,通过子域加载租户,并应用一些默认设置.中间件虽然不漂亮,但它的工作还不错.但是,当在应用程序中抛出异常时,中间件会“捕获”完整的堆栈跟踪.当我说陷阱时,我的意思是它隐藏了预期的堆栈跟踪.
这是一个例子.
我在控制器动作中抛出一个异常,如下所示:
def index throw "Exception in a Rails controller action" @taxonomies = Spree::Taxonomy.all end
您可能希望堆栈跟踪引用此位置,但它不会.相反,它引用中间件中的一行.
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'
为什么会这样?你以前见过这样的吗?
这是中间件:
# 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
我正在运行ruby 2.2.0p0和rails 4.1.8.
我已经在网上搜索了这个,但找不到任何东西,可能是因为我没有找到正确的东西.
有关为什么会发生这种情况以及我做错了什么的任何想法?
干杯!
解决方法
我终于找到了解决方案.事实证明,我认为应用程序的最后一行是在中间件中.我在位于组件目录中的本地rails引擎中运行其余代码.我们所需要做的就是为BacktraceCleaner创建一个新的消音器.注意组件dir现在包含在内.
# config/initializers/backtrace_silencers.rb Rails.backtrace_cleaner.remove_silencers! Rails.backtrace_cleaner.add_silencer { |line| line !~ /^\/(app|config|lib|test|components)/}
如果您对此感兴趣,我在rails项目上发布了一个有关如何详细复制此问题的问题. https://github.com/rails/rails/issues/22265