How to monitor FastAPI
Monitor a FastAPI app with an API check on a health route that touches its dependencies, per-route latency and error rate from tracing, exceptions in an error tracker, and the server's process and memory. Vigil's Python SDK wraps the app in one line and instruments SQLAlchemy, httpx, requests and redis; any Sentry SDK sends exceptions.
What can go wrong with FastAPI
- Blocking calls in async endpoints. A synchronous database driver,
requestscall ortime.sleepinside anasync defroute blocks the event loop; every request on that worker waits. - Connection pool exhausted. SQLAlchemy's default pool is 5 connections plus 10 overflow with a 30-second wait; under load requests fail with
QueuePool limit of size 5 overflow 10 reached. - Startup failures. An exception in the lifespan handler stops the worker from starting; with several workers some may serve while others crash-loop.
- Unhandled exceptions. They become 500 responses with a generic body; the traceback lives only in the worker's stderr.
- Memory growth. Large responses or caches held in module globals grow the worker until it is killed.
The signals that matter, with alert thresholds
| Signal | Alert when | Why it matters |
|---|---|---|
| Health route | non-2xx twice, or > 1 s | Users are affected. |
| p95 per route | > 2× the weekly normal | Blocking or a slow dependency. |
| 5xx share | > 1% of requests | Errors. |
| Pool wait / slow queries | new top entries | Pool or query problems. |
| Exceptions | new issue or a spike | Bugs, often after a deploy. |
| Worker memory | steady growth | Leak. |
Thresholds are starting points. Tune them after a week of data: an alert nobody acts on should be raised or removed.
How to check FastAPI by hand
curl -fsS -w '\n%{http_code} %{time_total}s\n' http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/openapi.json | python3 -m json.tool | head -20
sudo py-spy dump --pid $(pgrep -f 'uvicorn' | head -1)
systemctl status myapi journalctl -u myapi -p err --since '1 hour ago'
How to watch FastAPI with Vigil
- In New monitor create an API check on
/healthwith assertions such asjson status == okandjson database == ok, and a response-time limit. - Add the host under Servers and run the one-line installer it shows (
curl -fsSL https://puzaricloud.in/install-server-agent.sh | sh -s -- --token <token>). The agent is one Python file with no dependencies; CPU, memory, disk, inode and load rules start working with the first report. Add the API's systemd unit to the services to watch. - Download
/vigil-apm.pynext to your code and wrap the app:import vigil_apm; app = vigil_apm.init(service="api", app=app). SQLAlchemy, httpx, requests and redis calls are instrumented; spans go to the agent on 127.0.0.1:9111. - The server's Traces tab then shows routes with latency histograms and Apdex, stored slow traces, slow queries by total time, slow outbound calls, N+1 detection and deploy impact.
- Create a project under Errors and pass its DSN to
sentry_sdk.init(); the FastAPI integration is enabled automatically.
Every alert goes to the channels you pick: email, Slack, Telegram, Discord, Microsoft Teams, Pushover, webhooks or on-call paging. Failures are confirmed by a second check before anyone is woken up.
FastAPI monitoring FAQ
How do I find blocking code in async routes?
In a trace, a route whose time is not covered by child spans spent it in Python itself; if several unrelated routes slow down together, something is blocking the loop. Use def (not async def) for routes that call blocking libraries, so FastAPI runs them in a thread pool.
OpenTelemetry or the Vigil SDK?
The Vigil SDK is one file and one line, tuned for the agent. If you already use OpenTelemetry, keep it and send OTLP to Vigil (quick start); both land in the same views.
Is Vigil itself monitored this way?
Yes. Vigil is a FastAPI application; its own API health is an API check on its status page and its exceptions go to its own error tracking.