From 8ce7aafe6bb06dbc74e812e6e73d6690868a8a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20van=20Diemen?= Date: Fri, 23 Aug 2024 08:39:49 +0200 Subject: [PATCH] Allow ObanTelemetry to check if it needs to report errors --- lib/tracing/oban_telemetry.ex | 75 +++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/lib/tracing/oban_telemetry.ex b/lib/tracing/oban_telemetry.ex index f682944..edaae67 100644 --- a/lib/tracing/oban_telemetry.ex +++ b/lib/tracing/oban_telemetry.ex @@ -1,4 +1,37 @@ defmodule Tracing.ObanTelemetry do + @moduledoc """ + Handles telemetry and events for Oban workers. + + Allows a function `reportable?/1` to be set in an oban worker to define in which case exceptions should be reported or + not. If `reportable?/1` does not exist, all errors will be reported. + + ## Example + + ```elixir + defmodule MyApp.Application do + use Application + + def start(_type, _args) do + # ... + Tracing.setup([:oban]) + Supervisor.start_link([], [name: MyApp.Supervisor]) + end + end + + defmodule MyApp.ObanWorker do + use Oban.Worker, queue: "webhooks" + + @impl Oban.Worker + def perform(args) do + # execute + end + + def reportable?(meta) do + meta.attempt >= 3 + end + end + ``` + """ require OpenTelemetry.Tracer alias __MODULE__ @@ -82,18 +115,46 @@ defmodule Tracing.ObanTelemetry do %{kind: kind, reason: reason, stacktrace: stacktrace} = meta, _ ) do - case Tracing.current_span() do - :undefined -> - nil + Tracing.set_attributes(meta: inspect(meta)) - _context -> - ctx = OpentelemetryTelemetry.set_current_telemetry_span(@tracer_id, meta) + with {:span, context} when context != :undefined <- {:span, Tracing.current_span()}, + {:reportable, true} <- {:reportable, reportable?(meta)} do + ctx = OpentelemetryTelemetry.set_current_telemetry_span(@tracer_id, meta) - exception = Exception.normalize(kind, reason, stacktrace) + exception = Exception.normalize(kind, reason, stacktrace) - Span.record_exception(ctx, exception, stacktrace, []) + Span.record_exception(ctx, exception, stacktrace, []) + Span.set_status(ctx, OpenTelemetry.status(:error, "")) + OpentelemetryTelemetry.end_telemetry_span(@tracer_id, meta) + else + {:reportable, false} -> + nil + + {:reportable, {:error, _}} -> + ctx = OpentelemetryTelemetry.set_current_telemetry_span(@tracer_id, meta) Span.set_status(ctx, OpenTelemetry.status(:error, "")) OpentelemetryTelemetry.end_telemetry_span(@tracer_id, meta) + + {:span, :undefined} -> + nil + end + end + + # Allows configurable reporting. By default it will always report, but it allows the oban worker module to specify if + # it needs a custom configurable report true|false option. + defp reportable?(%{job: %{worker: worker_name}} = meta) when is_binary(worker_name) do + module = + worker_name + |> String.split(".") + |> Module.safe_concat() + + if Code.ensure_loaded?(module) && function_exported?(module, :reportable?, 1) do + module.reportable?(meta) + else + true end + rescue + ArgumentError -> + {:error, RuntimeError.exception("unknown worker: #{worker_name}")} end end