diff --git a/lib/mix/tasks/sentry.send_test_event.ex b/lib/mix/tasks/sentry.send_test_event.ex index 7a740733..dcf07d48 100644 --- a/lib/mix/tasks/sentry.send_test_event.ex +++ b/lib/mix/tasks/sentry.send_test_event.ex @@ -26,6 +26,8 @@ defmodule Mix.Tasks.Sentry.SendTestEvent do type: :string ] + @requirements ["app.start"] + @impl true def run(args) when is_list(args) do {opts, args} = OptionParser.parse!(args, strict: @switches) diff --git a/lib/sentry/config.ex b/lib/sentry/config.ex index a2407512..d6c50e13 100644 --- a/lib/sentry/config.ex +++ b/lib/sentry/config.ex @@ -322,6 +322,14 @@ defmodule Sentry.Config do connections to keep in the pool. Only applied if `:client` is set to `Sentry.HackneyClient`. """ + ], + req_opts: [ + type: :keyword_list, + default: [], + doc: """ + Options to be passed to `Req`. Only + applied if `:client` is set to `Sentry.ReqClient`. + """ ] ] @@ -559,6 +567,9 @@ defmodule Sentry.Config do @spec hackney_opts() :: keyword() def hackney_opts, do: fetch!(:hackney_opts) + @spec req_opts() :: keyword() + def req_opts, do: fetch!(:req_opts) + @spec before_send() :: (Sentry.Event.t() -> Sentry.Event.t()) | {module(), atom()} | nil def before_send, do: get(:before_send) diff --git a/lib/sentry/req_client.ex b/lib/sentry/req_client.ex new file mode 100644 index 00000000..abd81e48 --- /dev/null +++ b/lib/sentry/req_client.ex @@ -0,0 +1,32 @@ +defmodule Sentry.ReqClient do + @behaviour Sentry.HTTPClient + + @moduledoc """ + The built-in HTTP client. + + This client implements the `Sentry.HTTPClient` behaviour. + + It's based on the [Req](https://github.com/wojtekmach/req) HTTP client, + which is an *optional dependency* of this library. If you wish to use another + HTTP client, you'll have to implement your own `Sentry.HTTPClient`. See the + documentation for `Sentry.HTTPClient` for more information. + """ + + @impl true + def post(url, headers, body) do + opts = + Sentry.Config.req_opts() + |> Keyword.put(:decode_body, false) + |> Keyword.put(:url, url) + |> Keyword.put(:body, body) + + req = + Req.new(opts) + |> Req.merge(headers: headers) + + case Req.post(req) do + {:ok, %{status: status, headers: headers, body: body}} = result -> {:ok, status, headers, body} + {:error, _reason} = error -> error + end + end +end diff --git a/lib/sentry/transport.ex b/lib/sentry/transport.ex index a353b2b8..d9fc27e3 100644 --- a/lib/sentry/transport.ex +++ b/lib/sentry/transport.ex @@ -125,7 +125,7 @@ defmodule Sentry.Transport do defp client_post_and_validate_return_value(client, endpoint, headers, body) do case client.post(endpoint, headers, body) do {:ok, status, resp_headers, resp_body} - when is_integer(status) and status in 200..599 and is_list(resp_headers) and + when is_integer(status) and status in 200..599 and is_binary(resp_body) -> {:ok, status, resp_headers, resp_body} @@ -152,8 +152,8 @@ defmodule Sentry.Transport do |> Enum.map_join(", ", fn {name, value} -> "#{name}=#{value}" end) auth_headers = [ - {"User-Agent", @sentry_client}, - {"X-Sentry-Auth", "Sentry " <> auth_query} + {"user-agent", @sentry_client}, + {"x-sentry-auth", "Sentry " <> auth_query} ] {dsn.endpoint_uri, auth_headers} diff --git a/mix.exs b/mix.exs index acfb35fa..6e75c92d 100644 --- a/mix.exs +++ b/mix.exs @@ -51,7 +51,7 @@ defmodule Sentry.Mixfile do "Plug and Phoenix": [Sentry.PlugCapture, Sentry.PlugContext, Sentry.LiveViewHook], Loggers: [Sentry.LoggerBackend, Sentry.LoggerHandler], "Data Structures": [Sentry.Attachment, Sentry.CheckIn, Sentry.ClientReport], - HTTP: [Sentry.HTTPClient, Sentry.HackneyClient], + HTTP: [Sentry.HTTPClient, Sentry.HackneyClient, Sentry.ReqClient], Interfaces: [~r/^Sentry\.Interfaces/], Testing: [Sentry.Test] ],