diff --git a/sentry-sidekiq/CHANGELOG.md b/sentry-sidekiq/CHANGELOG.md index 7eaaa51fb..675828521 100644 --- a/sentry-sidekiq/CHANGELOG.md +++ b/sentry-sidekiq/CHANGELOG.md @@ -2,11 +2,15 @@ Individual gem's changelog has been deprecated. Please check the [project changelog](https://github.com/getsentry/sentry-ruby/blob/master/CHANGELOG.md). +## Unreleased + +- Add `report_errors_via_rails` config [#2701](https://github.com/getsentry/sentry-ruby/pull/2701) + ## 4.4.0 ### Features -- Make Sidekiq job context more readable [#1410](https://github.com/getsentry/sentry-ruby/pull/1410) +- Make Sidekiq job context more readable [#1410](https://github.com/getsentry/sentry-ruby/pull/1410) **Before** diff --git a/sentry-sidekiq/lib/sentry/sidekiq/configuration.rb b/sentry-sidekiq/lib/sentry/sidekiq/configuration.rb index fba2dfc18..27700c0c4 100644 --- a/sentry-sidekiq/lib/sentry/sidekiq/configuration.rb +++ b/sentry-sidekiq/lib/sentry/sidekiq/configuration.rb @@ -27,10 +27,14 @@ class Configuration # Whether we should inject headers while enqueuing the job in order to have a connected trace attr_accessor :propagate_traces + # Report exceptions via `Rails.error` instead of directly to the Sentry client + attr_accessor :report_errors_via_rails + def initialize @report_after_job_retries = false @report_only_dead_jobs = false @propagate_traces = true + @report_errors_via_rails = false end end end diff --git a/sentry-sidekiq/lib/sentry/sidekiq/error_handler.rb b/sentry-sidekiq/lib/sentry/sidekiq/error_handler.rb index 1ff14eb99..55899b483 100644 --- a/sentry-sidekiq/lib/sentry/sidekiq/error_handler.rb +++ b/sentry-sidekiq/lib/sentry/sidekiq/error_handler.rb @@ -47,17 +47,22 @@ def call(ex, context, sidekiq_config = nil) return if attempt < attempt_threshold end - Sentry::Sidekiq.capture_exception( - ex, - contexts: { sidekiq: context_filter.filtered }, - hint: { background: false } - ) + report_error(ex, context_filter.filtered, hint: { background: false }) ensure scope&.clear end private + def report_error(ex, context, hint: {}) + if Sentry.configuration.sidekiq.report_errors_via_rails && defined?(::Rails) + mechanism = Sentry::Mechanism.new(type: "sidekiq", handled: false) + ::Rails.error.report(ex, context: { sidekiq: context, hint: hint.merge(mechanism: mechanism) }, handled: false) + else + Sentry::Sidekiq.capture_exception(ex, contexts: { sidekiq: context }, hint: hint) + end + end + def retryable?(context) retry_option = context.dig(:job, "retry") # when `retry` is not specified, it's default is `true` and it means 25 retries. diff --git a/sentry-sidekiq/spec/sentry/sidekiq/configuration_spec.rb b/sentry-sidekiq/spec/sentry/sidekiq/configuration_spec.rb index 3fa83a217..eddfae16f 100644 --- a/sentry-sidekiq/spec/sentry/sidekiq/configuration_spec.rb +++ b/sentry-sidekiq/spec/sentry/sidekiq/configuration_spec.rb @@ -38,4 +38,10 @@ expect(subject.propagate_traces).to eq(true) end end + + describe "#report_errors_via_rails" do + it "has correct default value" do + expect(subject.report_errors_via_rails).to eq(false) + end + end end diff --git a/sentry-sidekiq/spec/sentry/sidekiq/error_handler_spec.rb b/sentry-sidekiq/spec/sentry/sidekiq/error_handler_spec.rb index d1e835d6b..4a7074db0 100644 --- a/sentry-sidekiq/spec/sentry/sidekiq/error_handler_spec.rb +++ b/sentry-sidekiq/spec/sentry/sidekiq/error_handler_spec.rb @@ -104,4 +104,33 @@ expect(event[:transaction]).to eq("Sidekiq/HardWorker") end end + + context "when `report_errors_via_rails` is true" do + before do + Sentry.configuration.sidekiq.report_errors_via_rails = true + end + + it "reports errors via Rails.error instead of the Sentry client" do + error_reporter = spy("Rails.error") + stub_const("Rails", double(error: error_reporter)) + + exception = build_exception + + subject.call(exception, context) + + expect(transport.events.count).to eq(0) + + expect(error_reporter).to have_received(:report) do |*args| + ex = args[0] + error_context = args[1][:context] + handled = args[1][:handled] + + expect(ex).to eq(exception) + expect(error_context[:sidekiq]).to eq(context) + expect(error_context[:hint][:background]).to eq(false) + expect(error_context[:hint][:mechanism].type).to eq("sidekiq") + expect(handled).to eq(false) + end + end + end end