From 7c79ec48dfb702e58fdd0bdc2f121c2cb20f8089 Mon Sep 17 00:00:00 2001 From: Adrien Cohen <18153974+adriencohen@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:47:13 +0100 Subject: [PATCH 1/2] feat(oban): add option to include job tags into reported exception tags --- lib/sentry/application.ex | 2 +- lib/sentry/config.ex | 8 ++++++ .../integrations/oban/error_reporter.ex | 25 +++++++++++++------ .../integrations/oban/error_reporter_test.exs | 24 +++++++++++++++--- test/sentry/logger_handler_test.exs | 3 ++- 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/lib/sentry/application.ex b/lib/sentry/application.ex index 77c56da7..04593b78 100644 --- a/lib/sentry/application.ex +++ b/lib/sentry/application.ex @@ -79,7 +79,7 @@ defmodule Sentry.Application do end if config[:oban][:capture_errors] do - Sentry.Integrations.Oban.ErrorReporter.attach() + Sentry.Integrations.Oban.ErrorReporter.attach(config[:oban]) end if config[:quantum][:cron][:enabled] do diff --git a/lib/sentry/config.ex b/lib/sentry/config.ex index 5b1f88f8..d107de00 100644 --- a/lib/sentry/config.ex +++ b/lib/sentry/config.ex @@ -51,6 +51,14 @@ defmodule Sentry.Config do tuples. *Available since 10.3.0*. """ ], + oban_tags: [ + type: :boolean, + default: false, + doc: """ + Whether to include Oban job tags in Sentry error tags. When enabled, the `job.tags` + will be joined with a "," and added as an `oban_tags` tag to Sentry events. + """ + ], cron: [ doc: """ Configuration options for configuring [*crons*](https://docs.sentry.io/product/crons/) diff --git a/lib/sentry/integrations/oban/error_reporter.ex b/lib/sentry/integrations/oban/error_reporter.ex index 3a11ba0a..fe0899a8 100644 --- a/lib/sentry/integrations/oban/error_reporter.ex +++ b/lib/sentry/integrations/oban/error_reporter.ex @@ -4,14 +4,14 @@ defmodule Sentry.Integrations.Oban.ErrorReporter do # See this blog post: # https://getoban.pro/articles/enhancing-error-reporting - @spec attach() :: :ok - def attach do + @spec attach(keyword()) :: :ok + def attach(config \\ []) when is_list(config) do _ = :telemetry.attach( __MODULE__, [:oban, :job, :exception], &__MODULE__.handle_event/4, - :no_config + config ) :ok @@ -21,32 +21,41 @@ defmodule Sentry.Integrations.Oban.ErrorReporter do [atom(), ...], term(), %{required(:job) => struct(), optional(term()) => term()}, - :no_config + keyword() ) :: :ok def handle_event( [:oban, :job, :exception], _measurements, %{job: job, kind: kind, reason: reason, stacktrace: stacktrace} = _metadata, - :no_config + config ) do if report?(reason) do - report(job, kind, reason, stacktrace) + report(job, kind, reason, stacktrace, config) else :ok end end - defp report(job, kind, reason, stacktrace) do + defp report(job, kind, reason, stacktrace, config) do stacktrace = case {apply(Oban.Worker, :from_string, [job.worker]), stacktrace} do {{:ok, atom_worker}, []} -> [{atom_worker, :process, 1, []}] _ -> stacktrace end + base_tags = %{oban_worker: job.worker, oban_queue: job.queue, oban_state: job.state} + + tags = + if config[:oban_tags] === true and is_list(job.tags) and not Enum.empty?(job.tags) do + Map.put(base_tags, :oban_tags, Enum.join(job.tags, ",")) + else + base_tags + end + opts = [ stacktrace: stacktrace, - tags: %{oban_worker: job.worker, oban_queue: job.queue, oban_state: job.state}, + tags: tags, fingerprint: [job.worker, "{{ default }}"], extra: Map.take(job, [:args, :attempt, :id, :max_attempts, :meta, :queue, :tags, :worker]), diff --git a/test/sentry/integrations/oban/error_reporter_test.exs b/test/sentry/integrations/oban/error_reporter_test.exs index 0d48fcdb..5c3370cb 100644 --- a/test/sentry/integrations/oban/error_reporter_test.exs +++ b/test/sentry/integrations/oban/error_reporter_test.exs @@ -4,7 +4,7 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do alias Sentry.Integrations.Oban.ErrorReporter defmodule MyWorker do - use Oban.Worker + use Oban.Worker, tags: ["tag1", "tag2"] @impl Oban.Worker def perform(%Oban.Job{}), do: :ok @@ -154,11 +154,29 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do assert Sentry.Test.pop_sentry_reports() == [] end end + + test "includes oban_tags when config option is enabled" do + Sentry.Test.start_collecting() + + emit_telemetry_for_failed_job(:error, %RuntimeError{message: "oops"}, [], oban_tags: true) + + assert [event] = Sentry.Test.pop_sentry_reports() + assert event.tags.oban_tags == "tag1,tag2" + end + + test "excludes oban_tags when config option is disabled" do + Sentry.Test.start_collecting() + + emit_telemetry_for_failed_job(:error, %RuntimeError{message: "oops"}, [], oban_tags: false) + + assert [event] = Sentry.Test.pop_sentry_reports() + assert is_nil(Map.get(event.tags, :oban_tags)) + end end ## Helpers - defp emit_telemetry_for_failed_job(kind, reason, stacktrace) do + defp emit_telemetry_for_failed_job(kind, reason, stacktrace, config \\ []) do job = %{"id" => "123", "entity" => "user", "type" => "delete"} |> MyWorker.new() @@ -169,7 +187,7 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do [:oban, :job, :exception], %{}, %{job: job, kind: kind, reason: reason, stacktrace: stacktrace}, - :no_config + config ) job diff --git a/test/sentry/logger_handler_test.exs b/test/sentry/logger_handler_test.exs index 5e1e4b7b..47cbd558 100644 --- a/test/sentry/logger_handler_test.exs +++ b/test/sentry/logger_handler_test.exs @@ -678,7 +678,8 @@ defmodule Sentry.LoggerHandlerTest do %ArgumentError{ message: ":sync_threshold and :discard_threshold cannot be used together, one of them must be nil" - }, _}}} = + }, + _}}} = :logger.update_handler_config( handler_name, :config, From e2b781ef3c79948216b4411e819a7950e2cf2802 Mon Sep 17 00:00:00 2001 From: Adrien Cohen <18153974+adriencohen@users.noreply.github.com> Date: Mon, 22 Dec 2025 10:35:15 +0100 Subject: [PATCH 2/2] fix: rename oban_tags option to add_oban_tags_as_tags --- lib/sentry/config.ex | 2 +- lib/sentry/integrations/oban/error_reporter.ex | 3 ++- .../sentry/integrations/oban/error_reporter_test.exs | 12 ++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/sentry/config.ex b/lib/sentry/config.ex index d107de00..8693db7a 100644 --- a/lib/sentry/config.ex +++ b/lib/sentry/config.ex @@ -51,7 +51,7 @@ defmodule Sentry.Config do tuples. *Available since 10.3.0*. """ ], - oban_tags: [ + add_oban_tags_as_tags: [ type: :boolean, default: false, doc: """ diff --git a/lib/sentry/integrations/oban/error_reporter.ex b/lib/sentry/integrations/oban/error_reporter.ex index fe0899a8..e4624be5 100644 --- a/lib/sentry/integrations/oban/error_reporter.ex +++ b/lib/sentry/integrations/oban/error_reporter.ex @@ -46,7 +46,8 @@ defmodule Sentry.Integrations.Oban.ErrorReporter do base_tags = %{oban_worker: job.worker, oban_queue: job.queue, oban_state: job.state} tags = - if config[:oban_tags] === true and is_list(job.tags) and not Enum.empty?(job.tags) do + if config[:add_oban_tags_as_tags] === true and is_list(job.tags) and + not Enum.empty?(job.tags) do Map.put(base_tags, :oban_tags, Enum.join(job.tags, ",")) else base_tags diff --git a/test/sentry/integrations/oban/error_reporter_test.exs b/test/sentry/integrations/oban/error_reporter_test.exs index 5c3370cb..27d6f175 100644 --- a/test/sentry/integrations/oban/error_reporter_test.exs +++ b/test/sentry/integrations/oban/error_reporter_test.exs @@ -155,19 +155,23 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do end end - test "includes oban_tags when config option is enabled" do + test "includes oban_tags when add_oban_tags_as_tags config option is enabled" do Sentry.Test.start_collecting() - emit_telemetry_for_failed_job(:error, %RuntimeError{message: "oops"}, [], oban_tags: true) + emit_telemetry_for_failed_job(:error, %RuntimeError{message: "oops"}, [], + add_oban_tags_as_tags: true + ) assert [event] = Sentry.Test.pop_sentry_reports() assert event.tags.oban_tags == "tag1,tag2" end - test "excludes oban_tags when config option is disabled" do + test "excludes add_oban_tags_as_tags when config option is disabled" do Sentry.Test.start_collecting() - emit_telemetry_for_failed_job(:error, %RuntimeError{message: "oops"}, [], oban_tags: false) + emit_telemetry_for_failed_job(:error, %RuntimeError{message: "oops"}, [], + add_oban_tags_as_tags: false + ) assert [event] = Sentry.Test.pop_sentry_reports() assert is_nil(Map.get(event.tags, :oban_tags))