Plug & play auto-logging middleware for FastAPI with async I/O, structured JSON logs, request IDs, loguru integration, and a built-in dashboard
Project description
fastapi-api-logger
Plug & play auto-logging middleware for FastAPI with async I/O, structured JSON logs, request tracing, loguru integration, and a built-in dashboard.
Features
- Zero-config middleware — add one line and all requests are logged
- Structured JSON logs — timestamp, method, endpoint, status, status_code, response_time_ms
- Correlation / Request ID — unique ID per request, forwarded from API gateways, injected into response headers
- Day-wise log files —
logs/2026-03-25.log,logs/2026-03-26.log, ... - Async & non-blocking — logging never slows your API (bounded queue + background writer)
- Status categorization — SUCCESS (2xx), REDIRECT (3xx), WARNING (4xx), ERROR (5xx)
- Error tracebacks — full traceback captured for 5xx errors
- Request/response body capture — opt-in, with automatic sensitive field masking
- Loguru integration — optionally pipe all logs through loguru with configurable levels
- Built-in dashboard — web UI at
/logsto browse, filter, and search logs in real-time - Configurable log rotation — auto-deletes log files older than N days (you choose how many)
- Pure ASGI — works with FastAPI, Starlette, or any ASGI framework
Quick Start
Install
pip install fastapi-api-logger
# With loguru support
pip install fastapi-api-logger[loguru]
# With everything
pip install fastapi-api-logger[all]
Basic Usage (2 lines)
from fastapi import FastAPI
from fastapi_logger import LoggingMiddleware
app = FastAPI()
app.add_middleware(LoggingMiddleware)
That's it! All requests are now logged to logs/YYYY-MM-DD.log with unique request IDs.
Full-Featured Usage
from fastapi import FastAPI
from fastapi_logger import LoggingMiddleware, LogConfig, create_dashboard_router
app = FastAPI()
config = LogConfig(
log_dir="logs",
excluded_paths=["/health", "/docs", "/openapi.json"],
enable_request_body=True,
enable_response_body=True,
sensitive_fields={"password", "token", "secret"},
# Request ID
enable_request_id=True,
request_id_header="X-Request-ID",
# Loguru
enable_loguru=True,
# Dashboard
enable_dashboard=True,
dashboard_prefix="/logs",
# Rotation — delete logs older than 7 days
log_rotation_days=7,
)
app.add_middleware(LoggingMiddleware, config=config)
# Mount the dashboard (visit http://localhost:8000/logs)
app.mount("", create_dashboard_router(config))
Correlation / Request ID
Every request gets a unique ID (UUID4). This is essential for debugging in production.
$ curl -v http://localhost:8000/users/1
< x-request-id: a1b2c3d4e5f6...
How it works:
- If the client sends
X-Request-IDheader (e.g., from an API gateway), the middleware uses it - Otherwise, a new UUID is generated
- The ID is added to the response headers AND the log entry
- Your endpoint can access it via
request.scope["state"]["request_id"]
@app.get("/users/{user_id}")
async def get_user(user_id: int, request: Request):
request_id = request.scope["state"]["request_id"]
return {"id": user_id, "request_id": request_id}
Loguru Integration
Enable loguru to get beautiful colored terminal output alongside file logging:
config = LogConfig(
enable_loguru=True,
loguru_level_success="INFO", # 2xx
loguru_level_warning="WARNING", # 4xx
loguru_level_error="ERROR", # 5xx
)
Output:
2026-03-25 14:30:00 | INFO | [a1b2c3d4] GET /users/1 → 200 SUCCESS (42.1ms)
2026-03-25 14:30:01 | WARNING | [b2c3d4e5] GET /users/0 → 404 WARNING (3.2ms)
2026-03-25 14:30:02 | ERROR | [c3d4e5f6] GET /crash → 500 ERROR (1.1ms)
Install loguru: pip install fastapi-api-logger[loguru]
Dashboard
A built-in web UI to browse your logs — no React, no npm, just enable it:
config = LogConfig(enable_dashboard=True, dashboard_prefix="/logs")
app.mount("", create_dashboard_router(config))
Visit http://localhost:8000/logs to see:
- Real-time log entries (auto-refreshes every 5s)
- Stats cards: total, success, warning, error counts + avg response time
- Filters: by status, method, endpoint search, date picker
- Sorting: newest, oldest, or slowest first
- Color-coded response times: green (<100ms), yellow (<500ms), red (>500ms)
- Expandable tracebacks and request bodies
Configuration Reference
All Options
| Field | Type | Default | Description |
|---|---|---|---|
log_dir |
str |
"logs" |
Directory for log files |
log_format |
"json" / "text" |
"json" |
Log output format |
excluded_paths |
list[str] |
["/health", ...] |
Glob patterns to skip |
enable_request_body |
bool |
False |
Capture request body |
enable_response_body |
bool |
False |
Capture response body |
sensitive_fields |
set[str] |
{"password", ...} |
Fields to mask as *** |
max_body_size |
int |
10000 |
Max body bytes to capture |
log_rotation_days |
int |
30 |
Auto-delete logs older than N days (0 = keep forever) |
include_traceback |
bool |
True |
Include traceback for 5xx errors |
enable_request_id |
bool |
True |
Generate unique request ID per request |
request_id_header |
str |
"X-Request-ID" |
Header name for request ID |
inject_response_header |
bool |
True |
Add request ID to response headers |
enable_loguru |
bool |
False |
Also emit logs through loguru |
loguru_level_success |
str |
"INFO" |
Loguru level for 2xx |
loguru_level_warning |
str |
"WARNING" |
Loguru level for 4xx |
loguru_level_error |
str |
"ERROR" |
Loguru level for 5xx |
enable_dashboard |
bool |
False |
Enable the /logs web UI |
dashboard_prefix |
str |
"/logs" |
URL prefix for dashboard routes |
dashboard_page_size |
int |
100 |
Entries per page in dashboard |
Log Format
{
"timestamp": "2026-03-25T14:30:00.123456+00:00",
"method": "POST",
"endpoint": "/orders",
"status": "SUCCESS",
"status_code": 201,
"response_time_ms": 85.23,
"request_id": "a1b2c3d4e5f67890abcdef1234567890",
"client_ip": "127.0.0.1",
"request_body": "{\"item\": \"widget\", \"password\": \"***\"}",
"response_body": "{\"id\": 42}"
}
Architecture
Request → LoggingMiddleware (pure ASGI)
├─ Generates/extracts Request ID
├─ Injects X-Request-ID response header
├─ Measures response time (perf_counter)
├─ Captures status code, method, path
├─ Optionally captures request/response body
├─ Masks sensitive fields
└─ Enqueues log entry (non-blocking, O(1))
↓
asyncio.Queue (bounded, 10k max)
↓
AsyncLogWriter (background task)
├─ Day-wise file: logs/YYYY-MM-DD.log
├─ Auto-rotation: deletes old files
└─ Optional: loguru sink
Development
git clone https://github.com/paresh/fastapi-api-logger.git
cd fastapi-api-logger
pip install -e ".[dev]"
# Run tests (51 tests)
pytest tests/ -v
# Run the demo app
uvicorn examples.demo_app:app --reload
# Visit http://localhost:8000/logs for the dashboard
Publishing to PyPI
# Install build tools
pip install build twine
# Build
python -m build
# Verify
twine check dist/*
# Upload to TestPyPI (testing)
twine upload --repository testpypi dist/*
# Upload to PyPI (production)
twine upload dist/*
Versioning
Update version in two places:
pyproject.toml→version = "X.Y.Z"src/fastapi_logger/__init__.py→__version__ = "X.Y.Z"
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_api_logger-0.2.1.tar.gz.
File metadata
- Download URL: fastapi_api_logger-0.2.1.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0df85cd3647fcac721947a363dc9bda32af4c1fdc95621230e101f801fed658
|
|
| MD5 |
2f8639a7ac02166be552e1fbc1d62a9e
|
|
| BLAKE2b-256 |
dc698bc79c6500c8c6d5561a507e68b7b57d49ad17a9a9f30ba51a490fb2e162
|
File details
Details for the file fastapi_api_logger-0.2.1-py3-none-any.whl.
File metadata
- Download URL: fastapi_api_logger-0.2.1-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13ea0a37a4b79f894d4994391fd01fa90274e0d27d317a358e53fdc8da97185e
|
|
| MD5 |
6e3dd2e00b864235392e640582e4276d
|
|
| BLAKE2b-256 |
6a96b8b0b0532fe1556041c9185fe0b5a04b05dd045f66d6db2bfec238304191
|