defmodule Sentry.HackneyClient do
@behaviour Sentry.HTTPClient
@moduledoc """
The built-in HTTP client.
This client implements the `Sentry.HTTPClient` behaviour.
It's based on the [hackney](https://github.com/benoitc/hackney) Erlang 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.
Sentry starts its own hackney pool called `:sentry_pool`. If you need to set other
[hackney configuration options](https://github.com/benoitc/hackney/blob/master/doc/hackney.md#request5)
for things such as proxies, using your own pool, or response timeouts, the `:hackney_opts`
configuration is passed directly to hackney for each request. See the configuration
documentation in the `Sentry` module.
"""
@hackney_pool_name :sentry_pool
@impl true
def child_spec do
if Code.ensure_loaded?(:hackney) and Code.ensure_loaded?(:hackney_pool) do
case Application.ensure_all_started(:hackney) do
{:ok, _apps} -> :ok
{:error, reason} -> raise "failed to start the :hackney application: #{inspect(reason)}"
end
:hackney_pool.child_spec(
@hackney_pool_name,
timeout: Sentry.Config.hackney_timeout(),
max_connections: Sentry.Config.max_hackney_connections()
)
else
raise """
cannot start the :sentry application because the HTTP client is set to \
Sentry.HackneyClient (which is the default), but the Hackney library is not loaded. \
Add :hackney to your dependencies to fix this.
"""
end
end
@impl true
def post(url, headers, body) do
hackney_opts =
Sentry.Config.hackney_opts()
|> Keyword.put_new(:pool, @hackney_pool_name)
case :hackney.request(:post, url, headers, body, [:with_body] ++ hackney_opts) do
{:ok, _status, _headers, _body} = result -> result
{:error, _reason} = error -> error
end
end
end