Skip to content

Commit 7f54b5d

Browse files
committed
feat(tracing): add first-class support for tracing Oban jobs
Treat Oban consumer spans as transaction roots so that Oban job executions are captured as independent transactions with proper trace context, span links, and child spans. Reworks phoenix_app integration tests to use Bypass for HTTP-level assertions and adds Playwright e2e tests for Oban job tracing.
1 parent cae7a50 commit 7f54b5d

12 files changed

Lines changed: 474 additions & 54 deletions

File tree

lib/sentry/opentelemetry/span_processor.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,15 @@ if Sentry.OpenTelemetry.VersionChecker.tracing_compatible?() do
6464
SpanStorage.span_exists?(parent_span_id)
6565
end
6666

67-
# Check if it's an HTTP server request span or a LiveView span
67+
# Check if it's an HTTP server request span, a LiveView span, or an Oban consumer span
6868
defp server_span?(%{kind: :server} = span_record) do
6969
http_server_span?(span_record) or liveview_span?(span_record)
7070
end
7171

72+
defp server_span?(%{kind: :consumer} = span_record) do
73+
oban_consumer_span?(span_record)
74+
end
75+
7276
defp server_span?(_), do: false
7377

7478
defp http_server_span?(%{kind: :server, attributes: attributes}) do
@@ -79,6 +83,10 @@ if Sentry.OpenTelemetry.VersionChecker.tracing_compatible?() do
7983
defp liveview_span?(%{origin: "opentelemetry_phoenix"}), do: true
8084
defp liveview_span?(_), do: false
8185

86+
defp oban_consumer_span?(%{kind: :consumer, attributes: attributes}) do
87+
Map.get(attributes, to_string(MessagingAttributes.messaging_system())) == :oban
88+
end
89+
8290
defp build_and_send_transaction(span_record) do
8391
child_span_records = SpanStorage.get_child_spans(span_record.span_id)
8492
transaction = build_transaction(span_record, child_span_records)

test_integrations/phoenix_app/config/test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ config :phoenix_live_view,
3232
enable_expensive_runtime_checks: true
3333

3434
config :sentry,
35-
dsn: "https://public@sentry.example.com/1",
35+
dsn: nil,
3636
environment_name: :dev,
3737
enable_source_code_context: true,
3838
root_source_code_paths: [File.cwd!()],
3939
test_mode: true,
40-
send_result: :sync,
40+
send_result: :none,
4141
traces_sample_rate: 1.0,
4242
enable_logs: true,
4343
logs: [

test_integrations/phoenix_app/lib/phoenix_app_web/controllers/page_controller.ex

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,24 @@ defmodule PhoenixAppWeb.PageController do
172172
}
173173
})
174174
end
175+
176+
def api_oban_job(conn, params) do
177+
alias PhoenixApp.Workers.TestWorker
178+
179+
sleep_time = Map.get(params, "sleep_time", "100") |> String.to_integer()
180+
should_fail = Map.get(params, "should_fail", "false") == "true"
181+
182+
{:ok, job} =
183+
%{"sleep_time" => sleep_time, "should_fail" => should_fail}
184+
|> TestWorker.new()
185+
|> OpentelemetryOban.insert()
186+
187+
json(conn, %{
188+
job_id: job.id,
189+
worker: job.worker,
190+
queue: job.queue,
191+
args: job.args,
192+
enqueued: true
193+
})
194+
end
175195
end

test_integrations/phoenix_app/lib/phoenix_app_web/live/test_worker_live.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ defmodule PhoenixAppWeb.TestWorkerLive do
7979
%{"sleep_time" => sleep_time, "should_fail" => should_fail},
8080
queue: queue
8181
)
82-
|> Oban.insert()
82+
|> OpentelemetryOban.insert()
8383
end
8484

8585
defp list_jobs do

test_integrations/phoenix_app/lib/phoenix_app_web/live/test_worker_live.html.heex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<label class="block text-sm font-medium text-gray-700">Sleep Time (ms)</label>
1010
<div class="mt-1">
1111
<input
12+
id="sleep-time-input"
1213
type="number"
1314
name="test_job[sleep_time]"
1415
value="1000"
@@ -45,6 +46,7 @@
4546

4647
<div>
4748
<button
49+
id="schedule-job-btn"
4850
type="submit"
4951
class="inline-flex justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
5052
>

test_integrations/phoenix_app/lib/phoenix_app_web/router.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ defmodule PhoenixAppWeb.Router do
5454
get "/error", PageController, :api_error
5555
get "/health", PageController, :health
5656
get "/api/data", PageController, :api_data
57+
post "/api/oban-job", PageController, :api_oban_job
5758
end
5859

5960
# Other scopes may use custom stacks.

test_integrations/phoenix_app/mix.exs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,7 @@ defmodule PhoenixApp.MixProject do
7171
{:opentelemetry_semantic_conventions, "~> 1.27"},
7272
{:opentelemetry_bandit, "~> 0.1"},
7373
{:opentelemetry_phoenix, "~> 2.0"},
74-
# TODO: Update once merged
75-
{:opentelemetry_oban, "~> 1.1",
76-
github: "open-telemetry/opentelemetry-erlang-contrib",
77-
branch: "main",
78-
sparse: "instrumentation/opentelemetry_oban"},
74+
{:opentelemetry_oban, "~> 1.2"},
7975
{:opentelemetry_ecto, "~> 1.2"},
8076
{:opentelemetry_logger_metadata, "~> 0.2.0"},
8177
{:hackney, "~> 1.18"},

test_integrations/phoenix_app/mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"opentelemetry_ecto": {:hex, :opentelemetry_ecto, "1.2.0", "2382cb47ddc231f953d3b8263ed029d87fbf217915a1da82f49159d122b64865", [:mix], [{:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:opentelemetry_process_propagator, "~> 0.2", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "70dfa2e79932e86f209df00e36c980b17a32f82d175f0068bf7ef9a96cf080cf"},
4949
"opentelemetry_exporter": {:hex, :opentelemetry_exporter, "1.10.0", "972e142392dbfa679ec959914664adefea38399e4f56ceba5c473e1cabdbad79", [:rebar3], [{:grpcbox, ">= 0.0.0", [hex: :grpcbox, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.7.0", [hex: :opentelemetry, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.5.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:tls_certificate_check, "~> 1.18", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}], "hexpm", "33a116ed7304cb91783f779dec02478f887c87988077bfd72840f760b8d4b952"},
5050
"opentelemetry_logger_metadata": {:hex, :opentelemetry_logger_metadata, "0.2.0", "b92116d5e5df698830dc607a8d033e7992d665aa55ea11698dc0bdba9712f6e0", [:mix, :rebar3], [{:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "ef64cce2b5e49e5fcaf86ef67813b2fb2c2b9bee828229619abffb1087374783"},
51-
"opentelemetry_oban": {:git, "https://github.com/open-telemetry/opentelemetry-erlang-contrib.git", "94e25887f7de87cbccc8ac35c598f281639b3f22", [branch: "main", sparse: "instrumentation/opentelemetry_oban"]},
51+
"opentelemetry_oban": {:hex, :opentelemetry_oban, "1.2.0", "4cbdfaa533deda678b6b534ee806636359107b70b0687accd57074b1c440d383", [:mix], [{:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:oban, "~> 2.0", [hex: :oban, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.2", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:opentelemetry_semantic_conventions, "~> 1.27", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}, {:opentelemetry_telemetry, "~> 1.1", [hex: :opentelemetry_telemetry, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0c96790ad689ba6af6ca64ca2a148543c48090a2ae1c46cce2fd1b32d71b5f71"},
5252
"opentelemetry_phoenix": {:hex, :opentelemetry_phoenix, "2.0.1", "c664cdef205738cffcd409b33599439a4ffb2035ef6e21a77927ac1da90463cb", [:mix], [{:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.4", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:opentelemetry_process_propagator, "~> 0.3", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: false]}, {:opentelemetry_semantic_conventions, "~> 1.27", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}, {:opentelemetry_telemetry, "~> 1.1", [hex: :opentelemetry_telemetry, repo: "hexpm", optional: false]}, {:otel_http, "~> 0.2", [hex: :otel_http, repo: "hexpm", optional: false]}, {:plug, ">= 1.11.0", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a24fdccdfa6b890c8892c6366beab4a15a27ec0c692b0f77ec2a862e7b235f6e"},
5353
"opentelemetry_process_propagator": {:hex, :opentelemetry_process_propagator, "0.3.0", "ef5b2059403a1e2b2d2c65914e6962e56371570b8c3ab5323d7a8d3444fb7f84", [:mix, :rebar3], [{:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "7243cb6de1523c473cba5b1aefa3f85e1ff8cc75d08f367104c1e11919c8c029"},
5454
"opentelemetry_semantic_conventions": {:hex, :opentelemetry_semantic_conventions, "1.27.0", "acd0194a94a1e57d63da982ee9f4a9f88834ae0b31b0bd850815fe9be4bbb45f", [:mix, :rebar3], [], "hexpm", "9681ccaa24fd3d810b4461581717661fd85ff7019b082c2dff89c7d5b1fc2864"},

0 commit comments

Comments
 (0)