analytics/lib/oban_error_reporter.ex
ruslandoga f28a1b8086
Log Oban errors (and still report them to Sentry) (#4657)
* log oban errors in CE

* update changelog

* not just ce

* add comment
2024-10-08 10:26:35 +00:00

79 lines
2.2 KiB
Elixir

defmodule ObanErrorReporter do
use Plausible
require Logger
def handle_event(name, measurements, metadata, _) do
# handling telemetry event in a try/catch block
# to avoid handler detachment in the case of an error
# see https://hexdocs.pm/telemetry/telemetry.html#attach/4
try do
handle_event(name, measurements, metadata)
catch
kind, reason ->
message = Exception.format(kind, reason, __STACKTRACE__)
Logger.error(message)
end
end
defp handle_event([:oban, :job, :exception], measure, %{job: job} = meta) do
extra =
job
|> Map.take([:id, :args, :meta, :queue, :worker])
|> Map.merge(measure)
on_job_exception(job)
capture_error(meta, extra)
end
defp handle_event([:oban, :notifier, :exception], _timing, meta) do
extra = Map.take(meta, ~w(channel payload)a)
capture_error(meta, extra)
end
defp handle_event([:oban, :plugin, :exception], _timing, meta) do
extra = Map.take(meta, ~w(plugin)a)
capture_error(meta, extra)
end
defp on_job_exception(%Oban.Job{
queue: "analytics_imports",
args: %{"import_id" => import_id},
state: "executing",
attempt: attempt,
max_attempts: max_attempts
})
when attempt >= max_attempts do
site_import = Plausible.Repo.get(Plausible.Imported.SiteImport, import_id)
if site_import do
Plausible.Workers.ImportAnalytics.import_fail(site_import, [])
end
end
defp on_job_exception(%Oban.Job{
queue: "analytics_imports",
args: %{"import_id" => import_id},
state: "executing"
}) do
site_import = Plausible.Repo.get(Plausible.Imported.SiteImport, import_id)
if site_import do
Plausible.Workers.ImportAnalytics.import_fail_transient(site_import)
end
end
defp on_job_exception(_job), do: :ignore
# Logs the error and sends it to Sentry
defp capture_error(meta, extra) do
Logger.error(
# this message is ignored by Sentry
"Background job (#{inspect(extra)}) failed:\n\n " <>
Exception.format(:error, meta.reason, meta.stacktrace),
# Sentry report is built entirely from crash_reason
crash_reason: {meta.reason, meta.stacktrace},
sentry: %{extra: extra}
)
end
end