diff --git a/lib/raven/base.rb b/lib/raven/base.rb index 23c401e07..6fbdf7d15 100644 --- a/lib/raven/base.rb +++ b/lib/raven/base.rb @@ -228,6 +228,15 @@ def load_integration(integration) self.logger.warn "Unable to load raven/integrations/#{integration}: #{error}" end + def rails_safely_prepend(module_name, opts = {}) + return if opts[:to].nil? + if opts[:to].respond_to?(:prepend, true) + opts[:to].send(:prepend, Raven::Rails::Overrides.const_get(module_name)) + else + opts[:to].send(:include, Raven::Rails::Overrides.const_get("Old" + module_name)) + end + end + # For cross-language compat alias :captureException :capture_exception alias :captureMessage :capture_message diff --git a/lib/raven/integrations/rails.rb b/lib/raven/integrations/rails.rb index af9bbc178..e0f01297a 100644 --- a/lib/raven/integrations/rails.rb +++ b/lib/raven/integrations/rails.rb @@ -2,14 +2,25 @@ module Raven class Rails < ::Rails::Railtie + require 'raven/integrations/rails/overrides/streaming_reporter' + require 'raven/integrations/rails/controller_methods' + initializer "raven.use_rack_middleware" do |app| app.config.middleware.insert 0, Raven::Rack end initializer 'raven.action_controller' do ActiveSupport.on_load :action_controller do - require 'raven/integrations/rails/controller_methods' include Raven::Rails::ControllerMethods + if ::Rails::VERSION::STRING >= "4.0.0" + Raven.rails_safely_prepend("StreamingReporter", :to => ActionController::Live) + end + end + end + + initializer 'raven.action_view' do + ActiveSupport.on_load :action_view do + Raven.rails_safely_prepend("StreamingReporter", :to => ActionView::StreamingTemplateRenderer::Body) end end @@ -23,19 +34,13 @@ class Rails < ::Rails::Railtie config.after_initialize do if Raven.configuration.rails_report_rescued_exceptions - require 'raven/integrations/rails/middleware/debug_exceptions_catcher' + require 'raven/integrations/rails/overrides/debug_exceptions_catcher' if defined?(::ActionDispatch::DebugExceptions) exceptions_class = ::ActionDispatch::DebugExceptions elsif defined?(::ActionDispatch::ShowExceptions) exceptions_class = ::ActionDispatch::ShowExceptions end - unless exceptions_class.nil? - if exceptions_class.respond_to?(:prepend, true) - exceptions_class.send(:prepend, Raven::Rails::Middleware::DebugExceptionsCatcher) - else - exceptions_class.send(:include, Raven::Rails::Middleware::OldDebugExceptionsCatcher) - end - end + Raven.rails_safely_prepend("DebugExceptionsCatcher", :to => exceptions_class) end end diff --git a/lib/raven/integrations/rails/middleware/debug_exceptions_catcher.rb b/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb similarity index 97% rename from lib/raven/integrations/rails/middleware/debug_exceptions_catcher.rb rename to lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb index 4335dc5dd..db9d67be4 100644 --- a/lib/raven/integrations/rails/middleware/debug_exceptions_catcher.rb +++ b/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb @@ -1,6 +1,6 @@ module Raven class Rails - module Middleware + module Overrides module DebugExceptionsCatcher def render_exception(env_or_request, exception) begin diff --git a/lib/raven/integrations/rails/overrides/streaming_reporter.rb b/lib/raven/integrations/rails/overrides/streaming_reporter.rb new file mode 100644 index 000000000..bdfca63ad --- /dev/null +++ b/lib/raven/integrations/rails/overrides/streaming_reporter.rb @@ -0,0 +1,23 @@ +module Raven + class Rails + module Overrides + module StreamingReporter + def log_error(exception) + Raven.capture_exception(exception) + super + end + end + + module OldStreamingReporter + def self.included(base) + base.send(:alias_method_chain, :log_error, :raven) + end + + def log_error_with_raven(exception) + Raven.capture_exception(exception) + log_error_without_raven(exception) + end + end + end + end +end diff --git a/spec/raven/integrations/rails/middleware/debug_exceptions_catcher_spec.rb b/spec/raven/integrations/rails/middleware/debug_exceptions_catcher_spec.rb index 7f93ea698..c9cdef31b 100644 --- a/spec/raven/integrations/rails/middleware/debug_exceptions_catcher_spec.rb +++ b/spec/raven/integrations/rails/middleware/debug_exceptions_catcher_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -require 'raven/integrations/rails/middleware/debug_exceptions_catcher' +require 'raven/integrations/rails/overrides/debug_exceptions_catcher' -describe Raven::Rails::Middleware::DebugExceptionsCatcher do +describe Raven::Rails::Overrides::DebugExceptionsCatcher do let(:middleware) do Class.new do def initialize(app) @@ -28,7 +28,7 @@ def render_exception(_, exception) context "using include" do before do - middleware.send(:include, Raven::Rails::Middleware::OldDebugExceptionsCatcher) + middleware.send(:include, Raven::Rails::Overrides::OldDebugExceptionsCatcher) end it "shows the exception" do @@ -51,7 +51,7 @@ def render_exception(_, exception) context "using prepend" do before do skip "prepend not available" unless middleware.respond_to?(:prepend, true) - middleware.send(:prepend, Raven::Rails::Middleware::DebugExceptionsCatcher) + middleware.send(:prepend, Raven::Rails::Overrides::DebugExceptionsCatcher) end it "shows the exception" do diff --git a/spec/raven/integrations/rails/overrides/debug_exceptions_catcher_spec.rb b/spec/raven/integrations/rails/overrides/debug_exceptions_catcher_spec.rb new file mode 100644 index 000000000..c9cdef31b --- /dev/null +++ b/spec/raven/integrations/rails/overrides/debug_exceptions_catcher_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' +require 'raven/integrations/rails/overrides/debug_exceptions_catcher' + +describe Raven::Rails::Overrides::DebugExceptionsCatcher do + let(:middleware) do + Class.new do + def initialize(app) + @app = app + end + + def call(env) + @app.call(env) + rescue => e + render_exception(env, e) + end + + def render_exception(_, exception) + [500, exception.message, {}] + end + end + end + + let(:app) do + lambda { |_| raise "app error" } # rubocop:disable Style/Lambda + end + + let(:env) { {} } + + context "using include" do + before do + middleware.send(:include, Raven::Rails::Overrides::OldDebugExceptionsCatcher) + end + + it "shows the exception" do + expect(middleware.new(app).call(env)).to eq([500, "app error", {}]) + end + + it "captures the exception" do + expect(Raven::Rack).to receive(:capture_exception) + middleware.new(app).call(env) + end + + context "when an error is raised" do + it "shows the original exception" do + allow(Raven::Rack).to receive(:capture_exception).and_raise("raven error") + expect(middleware.new(app).call(env)).to eq([500, "app error", {}]) + end + end + end + + context "using prepend" do + before do + skip "prepend not available" unless middleware.respond_to?(:prepend, true) + middleware.send(:prepend, Raven::Rails::Overrides::DebugExceptionsCatcher) + end + + it "shows the exception" do + expect(middleware.new(app).call(env)).to eq([500, "app error", {}]) + end + + it "captures the exception" do + expect(Raven::Rack).to receive(:capture_exception) + middleware.new(app).call(env) + end + + context "when an error is raised" do + it "shows the original exception" do + allow(Raven::Rack).to receive(:capture_exception).and_raise("raven error") + expect(middleware.new(app).call(env)).to eq([500, "app error", {}]) + end + end + end +end