reqly
Self-hosted API monitoring for FastAPI and Flask — two lines of code. Latency percentiles, error rates and release tracking for every route, shipped to your own Reqly collector — which turns them into deploy-aware hourly alerts and weekly AI anomaly reports.
Install
pip install reqly
Usage
FastAPI
import reqly
from fastapi import FastAPI
app = FastAPI()
reqly.instrument(
app,
service_name="checkout-api",
collector_url="https://reqly.example.com",
api_key="your-ingest-key",
)
# Every route is now tracked: latency, errors, status codes, release
Flask
import reqly
from flask import Flask
app = Flask(__name__)
reqly.instrument(app, service_name="checkout-api") # settings from REQLY_* env vars
instrument() detects FastAPI or Flask by itself — no decorators, no middleware to wire up.
The release you're running is picked up automatically from your CI or host
(GITHUB_SHA, RENDER_GIT_COMMIT, VERCEL_GIT_COMMIT_SHA, …), so deploys show up in
Reqly with no extra code.
What you get
From the SDK, per request: method, route template (/orders/{id}, never the raw
path), status code, duration, error type, host, release, environment and
request/response body size.
In the Reqly dashboard and collector:
- p50 / p95 / p99 latency per route and per service — real percentiles from mergeable sketches, not the max of per-route numbers
- Error rates, status codes and top routes over 1h / 6h / 24h / 7d
- Deploy markers and per-release health — each release's error rate and p95
- Hourly alerts to Slack, Discord or a webhook when a route breaks from its usual weekday-hour pattern, with root-cause hints
- Weekly AI report — statistics find the anomalies, Groq (Llama 3.3-70b) writes the summary; plain-text fallback without an API key
An alert from the demo data looks like this:
🔴 Anomaly — flask-demo /orders (Friday 15:00-16:00 UTC, z=5.37)
• error rate 30.0% vs 2.2% usual · p95 6588ms vs 1576ms usual
• running release v2 — vs v1: errors 2.6% → 33.1%, p95 2072ms → 4501ms
• 100% of errors came from host pod-3, which served 23% of requests
Not on Python? Node, Java, Go and .NET apps can report to the same collector through OpenTelemetry — no Reqly SDK needed. See the OpenTelemetry guide.
Configuration
Every option can be passed to instrument() or set as an environment variable.
Resolution order: argument → environment variable → default.
| argument | environment variable | default |
|---|---|---|
service_name |
REQLY_SERVICE_NAME |
sys.argv[0] basename |
collector_url |
REQLY_COLLECTOR_URL |
http://localhost:8000 |
api_key |
REQLY_API_KEY |
None |
release |
REQLY_RELEASE, then CI variables (GITHUB_SHA, CI_COMMIT_SHA, RENDER_GIT_COMMIT, VERCEL_GIT_COMMIT_SHA, RAILWAY_GIT_COMMIT_SHA, HEROKU_SLUG_COMMIT, K_REVISION, …) |
auto-detected, else None |
environment |
REQLY_ENVIRONMENT |
None |
sample_rate |
REQLY_SAMPLE_RATE |
1.0 |
flush_interval_seconds |
REQLY_FLUSH_INTERVAL_SECONDS |
5.0 |
max_batch_size |
REQLY_MAX_BATCH_SIZE |
200 |
max_queue_size |
REQLY_MAX_QUEUE_SIZE |
2000 |
ignore_routes |
REQLY_IGNORE_ROUTES (comma-separated) |
/health,/metrics |
capture_request_body |
REQLY_CAPTURE_REQUEST_BODY |
False (not implemented yet) |
With sample_rate below 1.0, request counts in the dashboard are the sampled volume;
latency percentiles and error rates stay unbiased.
Design guarantees
Fail-open — any internal SDK error is caught and logged once; instrumentation disables itself rather than raise into your app. A slow or unreachable collector never blocks request threads — shipping happens on a background thread with strict HTTP timeouts.
Bounded cardinality — routes are recorded as the framework's matched template
(/users/{id}), never the raw path (/users/123). Unmatched paths (404s, scanners)
collapse into a single __unmatched__ bucket.
Bounded memory — events wait in a fixed-size in-memory queue; under backpressure the oldest events are dropped and counted instead of growing without limit.
Safe retries — batches are retried with exponential backoff on 408, 429 and any
5xx (for example a collector restart behind a proxy); other 4xx responses are dropped
immediately. Every event carries a unique event_id the collector deduplicates on, so a
retry never double-counts.
Pre-fork servers — under gunicorn --preload (or uWSGI without lazy-apps) each
forked worker restarts its own flush thread and HTTP connection pool, so workers' events
are shipped instead of silently queuing forever.
Compatibility
| Supported | |
|---|---|
| Python | 3.9 – 3.13 |
| FastAPI | 0.100+ |
| Flask | 2.3+ |
| Collector | any version; release, environment and body sizes are stored by collector 0.3.0+ and ignored by older ones |
Self-hosting the collector
The SDK sends data to a Reqly collector you run. The full stack — collector, TimescaleDB and dashboard — starts with Docker Compose:
git clone https://github.com/tanisheesh/reqly.git
cd reqly
docker compose up -d
Setup, configuration and AWS deployment: docs/SETUP.md · infra/DEPLOY.md · ingest API spec
Live demo
Reqly monitors EventFlow, a Flask event management app, in production:
- Demo app → eventflow-g2h5.onrender.com
- Metrics dashboard → reqly-eventflow-dashboard.onrender.com
Log in as Administrator (
admin@eventhub.com/Admin@123) → click Metrics in the nav.
Changelog
See CHANGELOG.md.
License
GPL-3.0-or-later — see LICENSE.
Metadata
Release files for reqly 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| reqly-0.2.0.tar.gz | 21.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| reqly-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.8 kB
Release files / reqly-0.2.0.tar.gz
| Download URL | reqly-0.2.0.tar.gz |
|---|---|
| Size | 21.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f21ea8d43e2f14031d0cc1dda62436da5f8288e272375894d8e7842911589987
|
|
BLAKE2b-256 checksum How to use checksums |
86ab1e6c8eb6ea69a354f093d14dd5199b0696b825577cb1e0c1af0333506c4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.14
|
Release files / reqly-0.2.0-py3-none-any.whl
| Download URL | reqly-0.2.0-py3-none-any.whl |
|---|---|
| Size | 16.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77ab2eabc6a221ee9f57b2d6fa06c0bc6b441a855d534f383aea5228aaf6c7ff
|
|
BLAKE2b-256 checksum How to use checksums |
3cd75f7a3d939b14c29081235c818911364a9b61b081fe7e18179ea19bdf5193
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.14
|