How to Monitor Tesla with Vigilmon
Tesla is Elixir's composable HTTP client library. Its middleware stack — retry, logging, caching, OAuth — makes it the go-to choice for building integrations in Phoenix and Umbrella apps. But HTTP clients are silent failure points: if an external API your Tesla client depends on goes down, your app may degrade silently with no immediate error surfaced to users.
This tutorial wires up monitoring for Tesla-dependent services:
- A health endpoint that exercises your Tesla adapters
- HTTP uptime monitoring with Vigilmon
- Heartbeat monitors to catch silent adapter failures
- Telemetry integration for request latency tracking
- Alerts when upstream APIs degrade
Why Monitor Tesla?
| Signal | What it catches | |---|---| | Adapter availability | Finch/Hackney/Mint adapter startup failures | | Upstream API health | Third-party API downtime your app depends on | | Retry exhaustion | Middleware retry storms that mask upstream failures | | Request latency | P95 spikes from slow external services | | SSL/TLS errors | Certificate issues on upstream endpoints |
A standard uptime check only confirms your Phoenix app responds — it won't catch a Tesla client that can't reach a payment gateway or authentication service.
Step 1: Add a Tesla Health Check Endpoint
Create a dedicated health check that actually exercises your Tesla clients:
# lib/my_app/health/tesla_health.ex
defmodule MyApp.Health.TeslaHealth do
@moduledoc """
Exercises configured Tesla clients to verify upstream connectivity.
"""
def check_all do
checks = [
{"payments_api", &check_payments_api/0},
{"auth_service", &check_auth_service/0}
]
results = Enum.map(checks, fn {name, check_fn} ->
case check_fn.() do
:ok -> {name, :ok}
{:error, reason} -> {name, {:error, reason}}
end
end)
failed = Enum.filter(results, fn {_, status} -> status != :ok end)
if Enum.empty?(failed) do
{:ok, %{status: "ok", checks: length(checks)}}
else
{:error, %{status: "degraded", failed: Enum.map(failed, &elem(&1, 0))}}
end
end
defp check_payments_api do
case MyApp.PaymentsClient.health_check() do
{:ok, _} -> :ok
error -> {:error, inspect(error)}
end
end
defp check_auth_service do
case MyApp.AuthClient.ping() do
{:ok, _} -> :ok
error -> {:error, inspect(error)}
end
end
end
Wire it into a Phoenix controller:
# lib/my_app_web/controllers/health_controller.ex
defmodule MyAppWeb.HealthController do
use MyAppWeb, :controller
def tesla(conn, _params) do
case MyApp.Health.TeslaHealth.check_all() do
{:ok, result} ->
json(conn, result)
{:error, result} ->
conn
|> put_status(503)
|> json(result)
end
end
end
Add the route:
# lib/my_app_web/router.ex
scope "/health", MyAppWeb do
get "/tesla", HealthController, :tesla
end
Step 2: Set Up a Tesla Client with Telemetry Middleware
Tesla ships with a telemetry middleware you can attach to track request durations:
# lib/my_app/clients/payments_client.ex
defmodule MyApp.PaymentsClient do
use Tesla
plug Tesla.Middleware.BaseUrl, Application.compile_env(:my_app, :payments_api_url)
plug Tesla.Middleware.JSON
plug Tesla.Middleware.Telemetry
plug Tesla.Middleware.Retry,
delay: 500,
max_retries: 3,
max_delay: 4_000,
should_retry: fn
{:ok, %{status: status}} when status in [429, 500, 502, 503] -> true
{:ok, _} -> false
{:error, _} -> true
end
plug Tesla.Middleware.Logger
adapter Tesla.Adapter.Finch, name: MyApp.Finch
def health_check do
get("/health")
end
end
Attach a telemetry handler to capture latency:
# lib/my_app/telemetry.ex
defmodule MyApp.Telemetry do
def setup do
:telemetry.attach(
"tesla-request-stop",
[:tesla, :request, :stop],
&handle_request_stop/4,
nil
)
end
def handle_request_stop(_event, %{duration: duration}, metadata, _config) do
url = metadata[:env] && metadata.env.url || "unknown"
status = metadata[:env] && metadata.env.status || 0
duration_ms = System.convert_time_unit(duration, :native, :millisecond)
:telemetry.execute(
[:my_app, :http_client, :request],
%{duration: duration_ms},
%{url: url, status: status}
)
end
end
Step 3: Add Vigilmon Uptime Monitoring
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your health endpoint:
https://yourapp.com/health/tesla. - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Under Advanced, add a Response body contains check:
"status":"ok". - Click Save.
Vigilmon now verifies your Tesla clients can reach their upstream services every minute.
Step 4: Add a Heartbeat for Background Tesla Workers
If you use Tesla in background jobs or GenServers that poll external APIs, add a heartbeat that stops pinging Vigilmon when the integration fails:
# lib/my_app/workers/api_sync_worker.ex
defmodule MyApp.Workers.ApiSyncWorker do
use GenServer
@interval :timer.minutes(1)
@vigilmon_heartbeat_url "https://vigilmon.online/api/heartbeat/YOUR_HEARTBEAT_ID"
def start_link(_), do: GenServer.start_link(__MODULE__, nil, name: __MODULE__)
def init(_) do
schedule()
{:ok, %{consecutive_failures: 0}}
end
def handle_info(:sync, %{consecutive_failures: failures} = state) do
new_state =
case sync_data() do
:ok ->
ping_vigilmon()
%{state | consecutive_failures: 0}
{:error, _reason} ->
%{state | consecutive_failures: failures + 1}
end
schedule()
{:noreply, new_state}
end
defp sync_data do
case MyApp.PaymentsClient.get("/transactions/recent") do
{:ok, %{status: 200}} -> :ok
error -> {:error, error}
end
end
defp ping_vigilmon do
Tesla.get!(vigilmon_client(), @vigilmon_heartbeat_url)
end
defp vigilmon_client do
Tesla.client([Tesla.Middleware.FollowRedirects])
end
defp schedule, do: Process.send_after(self(), :sync, @interval)
end
To create the heartbeat in Vigilmon:
- Click Add Monitor → Cron / Heartbeat.
- Set the expected ping interval to
1 minute. - Copy the generated heartbeat URL into
@vigilmon_heartbeat_url.
Step 5: Set Up Alerts
- Go to Alert Channels → Add Channel.
- Choose Slack, Email, or PagerDuty.
- Set alert thresholds: notify after 2 consecutive failures.
- Assign the channel to your HTTP monitor and heartbeat monitor.
For critical payment or auth integrations, also add an on-call escalation:
- Create a second alert channel with PagerDuty or OpsGenie.
- Set it to trigger after 1 failure (no grace period for critical services).
- Assign it only to monitors for critical upstream dependencies.
Key Metrics to Watch
| Metric | Vigilmon feature | What to alert on |
|---|---|---|
| Upstream API availability | HTTP monitor on /health/tesla | Any 5xx or timeout |
| Background sync health | Heartbeat monitor | Missing ping for > 2 min |
| Response time | Response time chart | P95 > 3s over 5 minutes |
| SSL certificate | Cert expiry monitor | Expires in < 14 days |
| Retry storm detection | Heartbeat gap | Heartbeat missing during retry window |
Conclusion
Tesla's middleware architecture makes HTTP integrations elegant in Elixir — but it also means failures can be absorbed silently by retry middleware before they surface. With a health endpoint that exercises real Tesla clients, a heartbeat that stops when sync fails, and Vigilmon monitoring both, you'll catch upstream API degradation before it affects your users.
Get started free at vigilmon.online.