defmodule ErrorTracking do require Logger alias ErrorTracking.{Limiter, Stacktrace} @enabled Application.get_env(:error_tracking, :enabled, true) defmacro __using__(_opts) do quote do use Plug.ErrorHandler use Sentry.Plug end end @doc "Captures errors in any form and sends them to sentry." @spec capture(any(), keyword()) :: Sentry.send_result() if @enabled do def capture(error, opts \\ []) do sentry_opts = prepare_opts(opts) cond do Exception.exception?(error) -> Sentry.capture_exception(error, sentry_opts) true -> unless Limiter.limited?(error) do Limiter.limit(error) Sentry.capture_message(as_string(error), sentry_opts) end end end else def capture(_, _ \\ []), do: :ignored end defp as_string(error) when is_binary(error), do: error defp as_string(error), do: inspect(error) defp prepare_opts(opts) do opts |> insert_stacktrace() |> prevent_invalid_json() end defp insert_stacktrace(opts) do Keyword.put_new( opts, :stacktrace, Stacktrace.get() ) end defp prevent_invalid_json(opts) do Keyword.update(opts, :extra, %{}, fn extra -> case Jason.encode(extra) do {:ok, _} -> extra _ -> %{invalid_json: true, original: inspect(extra)} end end) end end