Middleware stack trace

I have a piece of Rack middleware that downloads a tenant through a subdomain and applies some default settings. The intermediate level tool, although not very beautiful, does the job quite well. However, when an exception is thrown in the application, the trap middleware tracks the full stack. When I say "trap", I mean that it hides the expected stack trace.

Here is an example.

I throw an exception to the controller action as follows:

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

You expect the stack trace to reference this location, but it is not. Instead, it refers to a line in the 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' 

Why is this happening? Have you seen anything like this before?

Here is the 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 

I am running ruby ​​2.2.0p0 and rails 4.1.8 .

I searched the web pages for this, but could not find anything, perhaps because I am not angry at the right thing.

Any thoughts on why this is happening and what I am doing wrong?

Hooray!

+6
source share
3 answers

I finally found a solution. It turns out that the last line in what is considered my application is in the middleware. I used the rest of the code in the local rails engine located in the components directory. All we had to do was create a new silencer for the BacktraceCleaner . Note that the dir component is now enabled.

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

If you're interested, this is a problem that I posted in a rails project on how to do this in detail. https://github.com/rails/rails/issues/22265

+7
source

Your middleware seems good. I think you have a problem setting backtrace_cleaner. Perhaps the cleaner is redefined by a third-party stone. Try to place a breakpoint (debugger) in the controller action method before raising the error and print:

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

to see the original locations of all silencers that remove traces other than the application. By default, it should only use Rails :: BacktraceCleaner, which it finds on railties-4.1.8 / lib / rails / backtrace_cleaner.rb

To directly see the silencer source code:

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

See https://github.com/rails/rails/blob/master/railties/lib/rails/backtrace_cleaner.rb https://github.com/rails/rails/blob/master/activesupport/lib/active_support/ for details backtrace_cleaner.rb

+3
source

You are not doing anything wrong. But there are many intermediate exceptions to clean up, including the middleware that Rack automatically inserts into development mode. There is a specific Rack middleware inserted into development that will catch uncaught exceptions and produce a reasonable HTML page instead of an unprocessed stack dump (which you often won't see at all with regular application servers).

  • You can catch the exception yourself by setting the start / save / end of your top level. Remember to catch the β€œException”, not just the β€œrescue” by default with no argument if you want to get everything. And you might want to throw an exception again if you are going to leave this code.
  • You can run in run mode - this can stop the automatic addition of middleware using Rack.
  • You can find out which middleware is inserted (in Rails: "rake middleware") and then remove the middleware manually (in Rails "config.middleware.delete" or "config.middleware.disable").

Perhaps there are other methods.

+1
source

Source: https://habr.com/ru/post/984808/


All Articles