Skip to content

Commit

Permalink
Support non-exception error values from Oban jobs (#807)
Browse files Browse the repository at this point in the history
  • Loading branch information
savhappy authored Oct 12, 2024
1 parent 5571faa commit 7d26e0c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 9 deletions.
31 changes: 22 additions & 9 deletions lib/sentry/integrations/oban/error_reporter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,40 @@ 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
{{:ok, atom_worker}, []} -> [{atom_worker, :process, 1, []}]
_ -> 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
Expand Down
44 changes: 44 additions & 0 deletions test/sentry/integrations/oban/error_reporter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 7d26e0c

Please sign in to comment.