Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/mix/tasks/sentry.send_test_event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ defmodule Mix.Tasks.Sentry.SendTestEvent do
type: :string
]

@requirements ["app.start"]

Comment on lines +29 to +30
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this Req-specific change inside the test command but I left it like this for now because I wanted to get some general feedback first.

Details why this is needed: https://elixirforum.com/t/argumenterror-unknown-registry-req-finch-on-a-simple-http-request-using-req-library/64638/9

@impl true
def run(args) when is_list(args) do
{opts, args} = OptionParser.parse!(args, strict: @switches)
Expand Down
11 changes: 11 additions & 0 deletions lib/sentry/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
"""
]
]

Expand Down Expand Up @@ -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)

Expand Down
32 changes: 32 additions & 0 deletions lib/sentry/req_client.ex
Original file line number Diff line number Diff line change
@@ -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)
Comment on lines +19 to +21
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Req decodes responses automatically. I choose to disable body decoding so the users can make use of the json_library option.


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}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should pattern match when Req is available.

Suggested change
{:ok, %{status: status, headers: headers, body: body}} = result -> {:ok, status, headers, body}
{:ok, %Req.Response{status: status, headers: headers, body: body}} = result -> {:ok, status, headers, body}

I transform the result into the Hackney-inspired form so everything else works.

{:error, _reason} = error -> error
end
end
end
6 changes: 3 additions & 3 deletions lib/sentry/transport.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Author

@krns krns Jan 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the is_list guard because it's highly Hackney-specific (Req response headers are a Map).

is_binary(resp_body) ->
{:ok, status, resp_headers, resp_body}

Expand All @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
],
Expand Down