Skip to main content

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.

PyPI Python License: GPL v3


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:

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)

Source distribution for reqly 0.2.0
File Size Uploaded
reqly-0.2.0.tar.gz 21.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for reqly 0.2.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page