reqly 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {reqly-0.2.0 → reqly-0.4.0}/PKG-INFO +241 -206
- {reqly-0.2.0 → reqly-0.4.0}/README.md +31 -5
- {reqly-0.2.0 → reqly-0.4.0}/pyproject.toml +10 -3
- {reqly-0.2.0 → reqly-0.4.0}/reqly/__init__.py +52 -19
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/client.py +14 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/config.py +7 -0
- reqly-0.4.0/reqly/core/openapi_push.py +58 -0
- reqly-0.4.0/reqly/integrations/django.py +142 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/integrations/fastapi.py +40 -6
- reqly-0.4.0/reqly/integrations/litestar.py +13 -0
- reqly-0.4.0/reqly/integrations/starlette.py +37 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly.egg-info/PKG-INFO +241 -206
- {reqly-0.2.0 → reqly-0.4.0}/reqly.egg-info/SOURCES.txt +6 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly.egg-info/requires.txt +11 -0
- {reqly-0.2.0 → reqly-0.4.0}/setup.cfg +4 -4
- reqly-0.4.0/tests/test_more_frameworks.py +250 -0
- reqly-0.4.0/tests/test_openapi_push.py +170 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/__init__.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/buffer.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/capture.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/sampling.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/core/shipper.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/integrations/__init__.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly/integrations/flask.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly.egg-info/dependency_links.txt +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/reqly.egg-info/top_level.txt +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_buffer.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_capture.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_fastapi_integration.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_flask_integration.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_instrument.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_sampling.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_shipper.py +0 -0
- {reqly-0.2.0 → reqly-0.4.0}/tests/test_v2_fields.py +0 -0
|
@@ -1,206 +1,241 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: reqly
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Self-hosted API monitoring for FastAPI and
|
|
5
|
-
Author: Tanish Poddar
|
|
6
|
-
License-Expression: GPL-3.0-or-later
|
|
7
|
-
Project-URL: Homepage, https://reqly.tanisheesh.in
|
|
8
|
-
Project-URL: Repository, https://github.com/tanisheesh/reqly
|
|
9
|
-
Project-URL: Issues, https://github.com/tanisheesh/reqly/issues
|
|
10
|
-
Project-URL: Documentation, https://github.com/tanisheesh/reqly/blob/main/docs/SETUP.md
|
|
11
|
-
Project-URL: Changelog, https://github.com/tanisheesh/reqly/blob/main/sdk/CHANGELOG.md
|
|
12
|
-
Project-URL: Live Demo, https://reqly-eventflow-dashboard.onrender.com
|
|
13
|
-
Keywords: observability,apm,monitoring,fastapi,flask,telemetry,metrics,latency,percentiles,alerting,anomaly-detection,release-tracking,self-hosted,timescaledb
|
|
14
|
-
Classifier: Development Status :: 4 - Beta
|
|
15
|
-
Classifier: Intended Audience :: Developers
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
-
Classifier: Topic :: System :: Monitoring
|
|
24
|
-
Classifier: Framework ::
|
|
25
|
-
Classifier: Framework ::
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
| |
|
|
168
|
-
|
|
169
|
-
|
|
|
170
|
-
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reqly
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Self-hosted API monitoring for FastAPI, Flask, Django, Starlette and Litestar in two lines: latency percentiles, error rates and release tracking per route, with deploy-aware alerts and weekly AI anomaly reports.
|
|
5
|
+
Author: Tanish Poddar
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://reqly.tanisheesh.in
|
|
8
|
+
Project-URL: Repository, https://github.com/tanisheesh/reqly
|
|
9
|
+
Project-URL: Issues, https://github.com/tanisheesh/reqly/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/tanisheesh/reqly/blob/main/docs/SETUP.md
|
|
11
|
+
Project-URL: Changelog, https://github.com/tanisheesh/reqly/blob/main/sdk/CHANGELOG.md
|
|
12
|
+
Project-URL: Live Demo, https://reqly-eventflow-dashboard.onrender.com
|
|
13
|
+
Keywords: observability,apm,monitoring,fastapi,flask,django,starlette,litestar,telemetry,metrics,latency,percentiles,alerting,anomaly-detection,release-tracking,self-hosted,timescaledb
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: System :: Monitoring
|
|
24
|
+
Classifier: Framework :: Django
|
|
25
|
+
Classifier: Framework :: FastAPI
|
|
26
|
+
Classifier: Framework :: Flask
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
30
|
+
Provides-Extra: fastapi
|
|
31
|
+
Requires-Dist: fastapi>=0.100; extra == "fastapi"
|
|
32
|
+
Provides-Extra: starlette
|
|
33
|
+
Requires-Dist: starlette>=0.27; extra == "starlette"
|
|
34
|
+
Provides-Extra: litestar
|
|
35
|
+
Requires-Dist: litestar>=2.0; extra == "litestar"
|
|
36
|
+
Provides-Extra: flask
|
|
37
|
+
Requires-Dist: flask>=2.3; extra == "flask"
|
|
38
|
+
Provides-Extra: django
|
|
39
|
+
Requires-Dist: django>=4.2; extra == "django"
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
42
|
+
Requires-Dist: fastapi>=0.100; extra == "dev"
|
|
43
|
+
Requires-Dist: litestar>=2.0; extra == "dev"
|
|
44
|
+
Requires-Dist: flask>=2.3; extra == "dev"
|
|
45
|
+
Requires-Dist: django>=4.2; extra == "dev"
|
|
46
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
47
|
+
|
|
48
|
+
# reqly
|
|
49
|
+
|
|
50
|
+
**Self-hosted API monitoring for FastAPI, Flask, Django, Starlette and Litestar — two lines of code.**
|
|
51
|
+
Latency percentiles, error rates and release tracking for every route, shipped to your own
|
|
52
|
+
[Reqly](https://github.com/tanisheesh/reqly) collector — which turns them into deploy-aware
|
|
53
|
+
hourly alerts and weekly AI anomaly reports.
|
|
54
|
+
|
|
55
|
+
[](https://pypi.org/project/reqly/)
|
|
56
|
+
[](https://pypi.org/project/reqly/)
|
|
57
|
+
[](https://github.com/tanisheesh/reqly/blob/main/LICENSE)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Install
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install reqly
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
**FastAPI**
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import reqly
|
|
73
|
+
from fastapi import FastAPI
|
|
74
|
+
|
|
75
|
+
app = FastAPI()
|
|
76
|
+
reqly.instrument(
|
|
77
|
+
app,
|
|
78
|
+
service_name="checkout-api",
|
|
79
|
+
collector_url="https://reqly.example.com",
|
|
80
|
+
api_key="your-ingest-key",
|
|
81
|
+
)
|
|
82
|
+
# Every route is now tracked: latency, errors, status codes, release
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Flask**
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import reqly
|
|
89
|
+
from flask import Flask
|
|
90
|
+
|
|
91
|
+
app = Flask(__name__)
|
|
92
|
+
reqly.instrument(app, service_name="checkout-api") # settings from REQLY_* env vars
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Starlette / Litestar** — same call:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
reqly.instrument(app, service_name="checkout-api")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Django** (also Django REST Framework and Django Ninja) — Django has no app object, so add
|
|
102
|
+
the middleware first in `MIDDLEWARE`:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# settings.py
|
|
106
|
+
MIDDLEWARE = [
|
|
107
|
+
"reqly.integrations.django.ReqlyMiddleware",
|
|
108
|
+
# ...
|
|
109
|
+
]
|
|
110
|
+
REQLY = {"service_name": "checkout-api", "api_key": "your-ingest-key"} # optional
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`instrument()` detects the framework by itself — no decorators, no middleware to wire up.
|
|
114
|
+
Routes are recorded as templates in one style across frameworks: Django's
|
|
115
|
+
`users/<int:pk>/` and DRF's `^users/(?P<pk>[^/.]+)/$` both become `/users/{pk}/`.
|
|
116
|
+
The release you're running is picked up automatically from your CI or host
|
|
117
|
+
(`GITHUB_SHA`, `RENDER_GIT_COMMIT`, `VERCEL_GIT_COMMIT_SHA`, …), so deploys show up in
|
|
118
|
+
Reqly with no extra code.
|
|
119
|
+
|
|
120
|
+
## What you get
|
|
121
|
+
|
|
122
|
+
From the SDK, per request: method, **route template** (`/orders/{id}`, never the raw
|
|
123
|
+
path), status code, duration, error type, host, **release**, environment and
|
|
124
|
+
request/response **body size**.
|
|
125
|
+
|
|
126
|
+
In the Reqly dashboard and collector:
|
|
127
|
+
|
|
128
|
+
- **p50 / p95 / p99 latency** per route and per service — real percentiles from
|
|
129
|
+
mergeable sketches, not the max of per-route numbers
|
|
130
|
+
- **Error rates, status codes and top routes** over 1h / 6h / 24h / 7d
|
|
131
|
+
- **Deploy markers and per-release health** — each release's error rate and p95
|
|
132
|
+
- **Hourly alerts** to Slack, Discord or a webhook when a route breaks from its usual
|
|
133
|
+
weekday-hour pattern, with **root-cause hints**
|
|
134
|
+
- **API surface vs your OpenAPI spec** — undocumented endpoints that get traffic, documented
|
|
135
|
+
ones nobody calls, and deprecated ones still in use (`push_openapi=True`)
|
|
136
|
+
- **Weekly AI report** — statistics find the anomalies, Groq (gpt-oss-120b) writes the
|
|
137
|
+
summary; plain-text fallback without an API key
|
|
138
|
+
|
|
139
|
+
An alert from the demo data looks like this:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
🔴 Anomaly — flask-demo /orders (Friday 15:00-16:00 UTC, z=5.37)
|
|
143
|
+
• error rate 30.0% vs 2.2% usual · p95 6588ms vs 1576ms usual
|
|
144
|
+
• running release v2 — vs v1: errors 2.6% → 33.1%, p95 2072ms → 4501ms
|
|
145
|
+
• 100% of errors came from host pod-3, which served 23% of requests
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Not on Python?** Node, Java, Go and .NET apps can report to the same collector through
|
|
149
|
+
OpenTelemetry — no Reqly SDK needed. See the
|
|
150
|
+
[OpenTelemetry guide](https://github.com/tanisheesh/reqly/blob/main/docs/OTEL.md).
|
|
151
|
+
|
|
152
|
+
## Configuration
|
|
153
|
+
|
|
154
|
+
Every option can be passed to `instrument()` or set as an environment variable.
|
|
155
|
+
Resolution order: **argument → environment variable → default**.
|
|
156
|
+
|
|
157
|
+
| argument | environment variable | default |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `service_name` | `REQLY_SERVICE_NAME` | `sys.argv[0]` basename |
|
|
160
|
+
| `collector_url` | `REQLY_COLLECTOR_URL` | `http://localhost:8000` |
|
|
161
|
+
| `api_key` | `REQLY_API_KEY` | `None` |
|
|
162
|
+
| `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` |
|
|
163
|
+
| `environment` | `REQLY_ENVIRONMENT` | `None` |
|
|
164
|
+
| `sample_rate` | `REQLY_SAMPLE_RATE` | `1.0` |
|
|
165
|
+
| `flush_interval_seconds` | `REQLY_FLUSH_INTERVAL_SECONDS` | `5.0` |
|
|
166
|
+
| `max_batch_size` | `REQLY_MAX_BATCH_SIZE` | `200` |
|
|
167
|
+
| `max_queue_size` | `REQLY_MAX_QUEUE_SIZE` | `2000` |
|
|
168
|
+
| `ignore_routes` | `REQLY_IGNORE_ROUTES` (comma-separated) | `/health,/metrics` |
|
|
169
|
+
| `push_openapi` | `REQLY_PUSH_OPENAPI` | `False` — upload the app's OpenAPI spec (FastAPI, Litestar) on the first request |
|
|
170
|
+
| `capture_request_body` | `REQLY_CAPTURE_REQUEST_BODY` | `False` (not implemented yet) |
|
|
171
|
+
|
|
172
|
+
With `sample_rate` below 1.0, request counts in the dashboard are the sampled volume;
|
|
173
|
+
latency percentiles and error rates stay unbiased.
|
|
174
|
+
|
|
175
|
+
## Design guarantees
|
|
176
|
+
|
|
177
|
+
**Fail-open** — any internal SDK error is caught and logged once; instrumentation disables
|
|
178
|
+
itself rather than raise into your app. A slow or unreachable collector never blocks
|
|
179
|
+
request threads — shipping happens on a background thread with strict HTTP timeouts.
|
|
180
|
+
|
|
181
|
+
**Bounded cardinality** — routes are recorded as the framework's matched template
|
|
182
|
+
(`/users/{id}`), never the raw path (`/users/123`). Unmatched paths (404s, scanners)
|
|
183
|
+
collapse into a single `__unmatched__` bucket.
|
|
184
|
+
|
|
185
|
+
**Bounded memory** — events wait in a fixed-size in-memory queue; under backpressure the
|
|
186
|
+
oldest events are dropped and counted instead of growing without limit.
|
|
187
|
+
|
|
188
|
+
**Safe retries** — batches are retried with exponential backoff on `408`, `429` and any
|
|
189
|
+
`5xx` (for example a collector restart behind a proxy); other `4xx` responses are dropped
|
|
190
|
+
immediately. Every event carries a unique `event_id` the collector deduplicates on, so a
|
|
191
|
+
retry never double-counts.
|
|
192
|
+
|
|
193
|
+
**Pre-fork servers** — under gunicorn `--preload` (or uWSGI without lazy-apps) each
|
|
194
|
+
forked worker restarts its own flush thread and HTTP connection pool, so workers' events
|
|
195
|
+
are shipped instead of silently queuing forever.
|
|
196
|
+
|
|
197
|
+
## Compatibility
|
|
198
|
+
|
|
199
|
+
| | Supported |
|
|
200
|
+
|---|---|
|
|
201
|
+
| Python | 3.9 – 3.13 |
|
|
202
|
+
| FastAPI | 0.100+ (including routes in `app.mount()`ed sub-apps) |
|
|
203
|
+
| Starlette | 0.27+ (including `Mount`) |
|
|
204
|
+
| Litestar | 2.0+ |
|
|
205
|
+
| Flask | 2.3+ |
|
|
206
|
+
| Django | 4.2+, sync and async views; DRF and Django Ninja |
|
|
207
|
+
| Collector | any version; `release`, `environment` and body sizes are stored by collector 0.3.0+ and ignored by older ones; `push_openapi` needs 0.7.0+ |
|
|
208
|
+
|
|
209
|
+
## Self-hosting the collector
|
|
210
|
+
|
|
211
|
+
The SDK sends data to a Reqly collector you run. The full stack — collector,
|
|
212
|
+
TimescaleDB and dashboard — starts with Docker Compose:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
git clone https://github.com/tanisheesh/reqly.git
|
|
216
|
+
cd reqly
|
|
217
|
+
docker compose up -d
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Setup, configuration and AWS deployment:
|
|
221
|
+
[docs/SETUP.md](https://github.com/tanisheesh/reqly/blob/main/docs/SETUP.md) ·
|
|
222
|
+
[infra/DEPLOY.md](https://github.com/tanisheesh/reqly/blob/main/infra/DEPLOY.md) ·
|
|
223
|
+
[ingest API spec](https://github.com/tanisheesh/reqly/blob/main/docs/INGEST_SPEC.md)
|
|
224
|
+
|
|
225
|
+
## Live demo
|
|
226
|
+
|
|
227
|
+
Reqly monitors [EventFlow](https://eventflow-g2h5.onrender.com), a Flask event management
|
|
228
|
+
app, in production:
|
|
229
|
+
|
|
230
|
+
- **Demo app** → [eventflow-g2h5.onrender.com](https://eventflow-g2h5.onrender.com)
|
|
231
|
+
- **Metrics dashboard** → [reqly-eventflow-dashboard.onrender.com](https://reqly-eventflow-dashboard.onrender.com)
|
|
232
|
+
|
|
233
|
+
> Log in as **Administrator** (`admin@eventhub.com` / `Admin@123`) → click **Metrics** in the nav.
|
|
234
|
+
|
|
235
|
+
## Changelog
|
|
236
|
+
|
|
237
|
+
See [CHANGELOG.md](https://github.com/tanisheesh/reqly/blob/main/sdk/CHANGELOG.md).
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
GPL-3.0-or-later — see [LICENSE](https://github.com/tanisheesh/reqly/blob/main/LICENSE).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# reqly
|
|
2
2
|
|
|
3
|
-
**Self-hosted API monitoring for FastAPI and
|
|
3
|
+
**Self-hosted API monitoring for FastAPI, Flask, Django, Starlette and Litestar — two lines of code.**
|
|
4
4
|
Latency percentiles, error rates and release tracking for every route, shipped to your own
|
|
5
5
|
[Reqly](https://github.com/tanisheesh/reqly) collector — which turns them into deploy-aware
|
|
6
6
|
hourly alerts and weekly AI anomaly reports.
|
|
@@ -45,7 +45,27 @@ app = Flask(__name__)
|
|
|
45
45
|
reqly.instrument(app, service_name="checkout-api") # settings from REQLY_* env vars
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
**Starlette / Litestar** — same call:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
reqly.instrument(app, service_name="checkout-api")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Django** (also Django REST Framework and Django Ninja) — Django has no app object, so add
|
|
55
|
+
the middleware first in `MIDDLEWARE`:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# settings.py
|
|
59
|
+
MIDDLEWARE = [
|
|
60
|
+
"reqly.integrations.django.ReqlyMiddleware",
|
|
61
|
+
# ...
|
|
62
|
+
]
|
|
63
|
+
REQLY = {"service_name": "checkout-api", "api_key": "your-ingest-key"} # optional
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`instrument()` detects the framework by itself — no decorators, no middleware to wire up.
|
|
67
|
+
Routes are recorded as templates in one style across frameworks: Django's
|
|
68
|
+
`users/<int:pk>/` and DRF's `^users/(?P<pk>[^/.]+)/$` both become `/users/{pk}/`.
|
|
49
69
|
The release you're running is picked up automatically from your CI or host
|
|
50
70
|
(`GITHUB_SHA`, `RENDER_GIT_COMMIT`, `VERCEL_GIT_COMMIT_SHA`, …), so deploys show up in
|
|
51
71
|
Reqly with no extra code.
|
|
@@ -64,7 +84,9 @@ In the Reqly dashboard and collector:
|
|
|
64
84
|
- **Deploy markers and per-release health** — each release's error rate and p95
|
|
65
85
|
- **Hourly alerts** to Slack, Discord or a webhook when a route breaks from its usual
|
|
66
86
|
weekday-hour pattern, with **root-cause hints**
|
|
67
|
-
- **
|
|
87
|
+
- **API surface vs your OpenAPI spec** — undocumented endpoints that get traffic, documented
|
|
88
|
+
ones nobody calls, and deprecated ones still in use (`push_openapi=True`)
|
|
89
|
+
- **Weekly AI report** — statistics find the anomalies, Groq (gpt-oss-120b) writes the
|
|
68
90
|
summary; plain-text fallback without an API key
|
|
69
91
|
|
|
70
92
|
An alert from the demo data looks like this:
|
|
@@ -97,6 +119,7 @@ Resolution order: **argument → environment variable → default**.
|
|
|
97
119
|
| `max_batch_size` | `REQLY_MAX_BATCH_SIZE` | `200` |
|
|
98
120
|
| `max_queue_size` | `REQLY_MAX_QUEUE_SIZE` | `2000` |
|
|
99
121
|
| `ignore_routes` | `REQLY_IGNORE_ROUTES` (comma-separated) | `/health,/metrics` |
|
|
122
|
+
| `push_openapi` | `REQLY_PUSH_OPENAPI` | `False` — upload the app's OpenAPI spec (FastAPI, Litestar) on the first request |
|
|
100
123
|
| `capture_request_body` | `REQLY_CAPTURE_REQUEST_BODY` | `False` (not implemented yet) |
|
|
101
124
|
|
|
102
125
|
With `sample_rate` below 1.0, request counts in the dashboard are the sampled volume;
|
|
@@ -129,9 +152,12 @@ are shipped instead of silently queuing forever.
|
|
|
129
152
|
| | Supported |
|
|
130
153
|
|---|---|
|
|
131
154
|
| Python | 3.9 – 3.13 |
|
|
132
|
-
| FastAPI | 0.100+ |
|
|
155
|
+
| FastAPI | 0.100+ (including routes in `app.mount()`ed sub-apps) |
|
|
156
|
+
| Starlette | 0.27+ (including `Mount`) |
|
|
157
|
+
| Litestar | 2.0+ |
|
|
133
158
|
| Flask | 2.3+ |
|
|
134
|
-
|
|
|
159
|
+
| Django | 4.2+, sync and async views; DRF and Django Ninja |
|
|
160
|
+
| Collector | any version; `release`, `environment` and body sizes are stored by collector 0.3.0+ and ignored by older ones; `push_openapi` needs 0.7.0+ |
|
|
135
161
|
|
|
136
162
|
## Self-hosting the collector
|
|
137
163
|
|
|
@@ -4,14 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "reqly"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "Self-hosted API monitoring for FastAPI and
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
description = "Self-hosted API monitoring for FastAPI, Flask, Django, Starlette and Litestar in two lines: latency percentiles, error rates and release tracking per route, with deploy-aware alerts and weekly AI anomaly reports."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
license = "GPL-3.0-or-later"
|
|
12
12
|
authors = [{ name = "Tanish Poddar" }]
|
|
13
13
|
keywords = [
|
|
14
|
-
"observability", "apm", "monitoring", "fastapi", "flask", "
|
|
14
|
+
"observability", "apm", "monitoring", "fastapi", "flask", "django",
|
|
15
|
+
"starlette", "litestar", "telemetry",
|
|
15
16
|
"metrics", "latency", "percentiles", "alerting", "anomaly-detection",
|
|
16
17
|
"release-tracking", "self-hosted", "timescaledb"
|
|
17
18
|
]
|
|
@@ -26,6 +27,7 @@ classifiers = [
|
|
|
26
27
|
"Programming Language :: Python :: 3.13",
|
|
27
28
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
28
29
|
"Topic :: System :: Monitoring",
|
|
30
|
+
"Framework :: Django",
|
|
29
31
|
"Framework :: FastAPI",
|
|
30
32
|
"Framework :: Flask",
|
|
31
33
|
]
|
|
@@ -43,11 +45,16 @@ Changelog = "https://github.com/tanisheesh/reqly/blob/main/sdk/CHANGELOG.md"
|
|
|
43
45
|
|
|
44
46
|
[project.optional-dependencies]
|
|
45
47
|
fastapi = ["fastapi>=0.100"]
|
|
48
|
+
starlette = ["starlette>=0.27"]
|
|
49
|
+
litestar = ["litestar>=2.0"]
|
|
46
50
|
flask = ["flask>=2.3"]
|
|
51
|
+
django = ["django>=4.2"]
|
|
47
52
|
dev = [
|
|
48
53
|
"pytest>=8.0",
|
|
49
54
|
"fastapi>=0.100",
|
|
55
|
+
"litestar>=2.0",
|
|
50
56
|
"flask>=2.3",
|
|
57
|
+
"django>=4.2",
|
|
51
58
|
"httpx>=0.27",
|
|
52
59
|
]
|
|
53
60
|
|