diff --git a/lib/sentry/integrations/oban/error_reporter.ex b/lib/sentry/integrations/oban/error_reporter.ex index c26bf1da..daf2f8a0 100644 --- a/lib/sentry/integrations/oban/error_reporter.ex +++ b/lib/sentry/integrations/oban/error_reporter.ex @@ -24,7 +24,7 @@ defmodule Sentry.Integrations.Oban.ErrorReporter do :no_config ) :: :ok def handle_event([:oban, :job, :exception], _measurements, %{job: job} = _metadata, :no_config) do - %{reason: exception, stacktrace: stacktrace} = job.unsaved_error + %{reason: reason, stacktrace: stacktrace} = job.unsaved_error stacktrace = case {apply(Oban.Worker, :from_string, [job.worker]), stacktrace} do @@ -32,19 +32,32 @@ defmodule Sentry.Integrations.Oban.ErrorReporter do _ -> stacktrace end - _ = - Sentry.capture_exception(exception, + fingerprint_opts = + if is_exception(reason) do + [inspect(reason.__struct__), Exception.message(reason)] + else + [inspect(reason)] + end + + opts = + [ stacktrace: stacktrace, tags: %{oban_worker: job.worker, oban_queue: job.queue, oban_state: job.state}, - fingerprint: [ - inspect(exception.__struct__), - inspect(job.worker), - Exception.message(exception) - ], + fingerprint: [inspect(job.worker)] ++ fingerprint_opts, extra: Map.take(job, [:args, :attempt, :id, :max_attempts, :meta, :queue, :tags, :worker]), integration_meta: %{oban: %{job: job}} - ) + ] + + _ = + if is_exception(reason) do + Sentry.capture_exception(reason, opts) + else + Sentry.capture_message( + "Oban job #{job.worker} errored out: %s", + opts ++ [interpolation_parameters: [inspect(reason)]] + ) + end :ok end diff --git a/test/sentry/integrations/oban/error_reporter_test.exs b/test/sentry/integrations/oban/error_reporter_test.exs index a4b56936..41139327 100644 --- a/test/sentry/integrations/oban/error_reporter_test.exs +++ b/test/sentry/integrations/oban/error_reporter_test.exs @@ -50,5 +50,49 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do assert event.tags.oban_worker == "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker" assert %{job: %Oban.Job{}} = event.integration_meta.oban end + + test "reports non-exception errors to Sentry" do + job = + %{"id" => "123", "entity" => "user", "type" => "delete"} + |> MyWorker.new() + |> Ecto.Changeset.apply_action!(:validate) + |> Map.replace!(:unsaved_error, %{ + reason: :undef, + kind: :error, + stacktrace: [] + }) + + Sentry.Test.start_collecting() + + assert :ok = + ErrorReporter.handle_event( + [:oban, :job, :exception], + %{}, + %{job: job}, + :no_config + ) + + assert [event] = Sentry.Test.pop_sentry_reports() + assert %{job: %Oban.Job{}} = event.integration_meta.oban + + assert event.message == %Sentry.Interfaces.Message{ + formatted: + "Oban job Sentry.Integrations.Oban.ErrorReporterTest.MyWorker errored out: :undef", + message: + "Oban job Sentry.Integrations.Oban.ErrorReporterTest.MyWorker errored out: %s", + params: [":undef"] + } + + assert [%Sentry.Interfaces.Thread{stacktrace: %{frames: [stacktrace]}}] = event.threads + + assert stacktrace.module == MyWorker + + assert stacktrace.function == + "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker.process/1" + + assert event.tags.oban_queue == "default" + assert event.tags.oban_state == "available" + assert event.tags.oban_worker == "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker" + end end end