-
Notifications
You must be signed in to change notification settings - Fork 815
docs: Add FastAPI + Uvicorn monitoring example #1103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,123 @@ | ||||||
--- | ||||||
title: FastAPI + Uvicorn | ||||||
weight: 6 | ||||||
--- | ||||||
|
||||||
This guide demonstrates how to integrate Prometheus metrics into a [FastAPI](https://fastapi.tiangolo.com/) application using the native [Uvicorn](https://www.uvicorn.org/) ASGI server with production-ready multiprocess support. | ||||||
|
||||||
### Basic Implementation | ||||||
Save the following in a `myapp.py` file: | ||||||
|
||||||
```python | ||||||
import os | ||||||
from fastapi import FastAPI | ||||||
from prometheus_client import make_asgi_app, Counter, Gauge, CollectorRegistry, multiprocess | ||||||
from fastapi.responses import JSONResponse | ||||||
import psutil | ||||||
|
||||||
app = FastAPI() | ||||||
|
||||||
Define metrics with multiprocess aggregation | ||||||
REQUEST_COUNT = Counter( | ||||||
"http_requests_total", | ||||||
"Total HTTP requests by endpoint", | ||||||
["endpoint"], | ||||||
registry=CollectorRegistry() # Isolated registry | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typically we recommend not assigning any registry when using multiprocess. What about just leaving a comment here like |
||||||
) | ||||||
CPU_USAGE = Gauge( | ||||||
"system_cpu_usage_percent", | ||||||
"Current CPU utilization percentage (aggregated)", | ||||||
multiprocess_mode='livesum' # Critical for worker aggregation | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not critical for an example, but |
||||||
) | ||||||
|
||||||
def create_metrics_app(): | ||||||
"""Create multiprocess-aware metrics endpoint""" | ||||||
registry = CollectorRegistry() | ||||||
multiprocess.MultiProcessCollector( | ||||||
registry, | ||||||
path=os.environ.get( # Explicit path handling | ||||||
'PROMETHEUS_MULTIPROC_DIR', | ||||||
'/tmp/prometheus' # Fallback path | ||||||
) | ||||||
) | ||||||
return make_asgi_app(registry=registry) | ||||||
|
||||||
Mount endpoint with trailing slash | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
app.mount("/metrics/", create_metrics_app()) | ||||||
|
||||||
@app.get("/") | ||||||
async def home(): | ||||||
REQUEST_COUNT.labels(endpoint="/").inc() | ||||||
CPU_USAGE.set(psutil.cpu_percent(interval=None)) # System-wide measurement | ||||||
return JSONResponse({"status": "ok"}) | ||||||
``` | ||||||
|
||||||
### Key Configuration | ||||||
1. **Multiprocess Aggregation** | ||||||
Required for gauge metrics in worker environments: | ||||||
```python | ||||||
# Supported modes: livesum/max/liveall | ||||||
Gauge(..., multiprocess_mode='livesum') | ||||||
``` | ||||||
|
||||||
2. **Registry Isolation** | ||||||
Prevents metric conflicts between components: | ||||||
```python | ||||||
REQUEST_COUNT = Counter(..., registry=CollectorRegistry()) | ||||||
``` | ||||||
|
||||||
### Running the Application | ||||||
```bash | ||||||
1. Install dependencies with psutil | ||||||
pip install fastapi uvicorn prometheus-client psutil | ||||||
|
||||||
2. Single-process mode (development) | ||||||
uvicorn myapp:app --port 8000 | ||||||
|
||||||
3. Multiprocess mode (production) | ||||||
export PROMETHEUS_MULTIPROC_DIR=./metrics_data # Persistent storage | ||||||
mkdir -p $PROMETHEUS_MULTIPROC_DIR | ||||||
uvicorn myapp:app --port 8000 --workers 4 | ||||||
|
||||||
4. Generate load for verification | ||||||
for i in {1..100}; do curl -s http://localhost:8000/ & done | ||||||
|
||||||
5. Verify aggregated metrics | ||||||
curl -s http://localhost:8000/metrics/ | grep -E 'http_requests_total|system_cpu_usage_percent' | ||||||
``` | ||||||
|
||||||
### Expected Output | ||||||
```text | ||||||
TYPE http_requests_total counter | ||||||
http_requests_total{endpoint="/"} 100.0 | ||||||
TYPE system_cpu_usage_percent gauge | ||||||
system_cpu_usage_percent 68.5 # Aggregated across workers | ||||||
``` | ||||||
|
||||||
### Production Checklist | ||||||
1. **Directory Configuration** | ||||||
```bash | ||||||
chmod 750 ./metrics_data # Secure write permissions | ||||||
``` | ||||||
2. **Storage Management** | ||||||
- Use dedicated volume for `PROMETHEUS_MULTIPROC_DIR` | ||||||
- Implement cleanup cron job: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than a cron-job it is usually best practice to delete the data (if it exists) when your service restarts. Otherwise some problems with counter resets can occur. |
||||||
```bash | ||||||
0 * * * * find /path/to/metrics_data -name '*.db' -mtime +7 -delete | ||||||
``` | ||||||
3. **Validation Tools** | ||||||
```bash | ||||||
# Check active worker count | ||||||
ps aux | grep -c '[u]vicorn.*worker' | ||||||
# Monitor data files | ||||||
watch -n 5 'ls -lh $PROMETHEUS_MULTIPROC_DIR | grep .db' | ||||||
``` | ||||||
|
||||||
### Troubleshooting | ||||||
| Symptom | Solution | Verification Command | | ||||||
|------------------------|-------------------------------|-----------------------------------| | ||||||
| PID labels in metrics | Add `multiprocess_mode` param | `grep 'multiprocess_mode' myapp.py` | | ||||||
| Missing .db files | Check directory permissions | `ls -ld $PROMETHEUS_MULTIPROC_DIR` | | ||||||
| Stale values | Verify endpoint activation | `curl -I http://localhost:8000/` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.