Skip to main content
The AppSignal for Elixir package instruments HTTP requests performed by HTTPoison. HTTPoison is a popular HTTP client for Elixir. Unlike Finch and Tesla, HTTPoison does not emit telemetry events, so AppSignal cannot automatically instrument it. Instead, AppSignal provides wrapper modules that you opt into: Appsignal.HTTPoison as a drop-in client, and Appsignal.HTTPoison.Base for custom client modules. The response and error structs (%HTTPoison.Response{}, %HTTPoison.Error{}, …) are HTTPoison’s own types and are returned unchanged. AppSignal will wrap requests executed via Appsignal.HTTPoison as request.httpoison events on your performance samples’ event timeline, allowing you to see how much time HTTPoison spends making external API requests. This data may help inform you to move the API requests to a background job, or to introduce caching to help speed up performance and limit unnecessary API requests.

Configuration

HTTPoison instrumentation is opt-in. Choose the approach that best fits your application.

Using Appsignal.HTTPoison directly

Call Appsignal.HTTPoison instead of HTTPoison to make instrumented requests. Pattern-match on %HTTPoison.Response{...} and %HTTPoison.Error{...} as normal — these are HTTPoison’s own struct types, returned unchanged:
Do not use alias Appsignal.HTTPoison. This would shadow the HTTPoison module name, causing %HTTPoison.Response{} and %HTTPoison.Error{} pattern matches to fail.
defmodule MyAppWeb.PageController do
  use MyAppWeb, :controller

  def index(conn, _params) do
    case Appsignal.HTTPoison.get("https://api.example.com/users") do
      {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
        render(conn, :index, users: body)

      {:ok, %HTTPoison.Response{status_code: status}} ->
        conn |> put_status(status) |> text("Error")

      {:error, %HTTPoison.Error{reason: reason}} ->
        conn |> put_status(500) |> text("Error: #{reason}")
    end
  end
end

Custom client modules

If you use a custom HTTP client module based on HTTPoison.Base, replace use HTTPoison.Base with use Appsignal.HTTPoison.Base. No further changes are needed — inside the module, you can call methods like get/1 and post/3, and match on HTTPoison’s response and error structs as normal:
defmodule MyApp.ApiClient do
  # replace `use HTTPoison.Base` with `use Appsignal.HTTPoison.Base`
  use Appsignal.HTTPoison.Base

  def process_url(url) do
    "https://api.example.com" <> url
  end

  def users do
    case get("/users") do
      {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> {:ok, body}
      {:ok, %HTTPoison.Response{status_code: status}} -> {:error, status}
      {:error, %HTTPoison.Error{reason: reason}} -> {:error, reason}
    end
  end
end
All requests made through your custom client will then be instrumented automatically. If your module overrides request/5, make sure to call super to preserve the instrumentation:
defmodule MyApp.ApiClient do
  use Appsignal.HTTPoison.Base

  def request(method, url, body, headers, options) do
    # ... custom logic here ...
    super(method, url, body, headers, options)
  end
end