Lightweight self-hosted debugger and metrics dashboard for FastAPI.
Project description
โก fastapi-flare
Lightweight self-hosted debugger and metrics dashboard for FastAPI.
Zero-config by default (SQLite) โ PostgreSQL-ready for production.
What is fastapi-flare?
fastapi-flare is a self-hosted error tracking and metrics library for FastAPI applications.
It automatically captures HTTP and unhandled exceptions, stores them locally or in PostgreSQL, and exposes a dark-theme dashboard โ all with a single line of code.
No external services. No SaaS. No noise.
Features
| ๐ One-line setup | setup(app) โ works immediately, no config required |
| ๐ Auto-capture | HTTP 4xx/5xx and unhandled Python exceptions |
| ๐ฅ๏ธ Admin dashboard | Built-in at /flare โ dark theme, filters, pagination |
| ๐๏ธ Dual storage | SQLite (zero-config default) or PostgreSQL (production) |
| ๐ฅ Fire-and-forget | Logging never blocks your request handlers |
| โ๏ธ Background worker | Async task runs retention cleanup every 5 seconds |
| ๐ Retention policies | Time-based (default 7 days) + count-based (10k entries) |
| ๐ Auth-ready | Protect the dashboard with any FastAPI Depends() |
| ๐ Env-configurable | All settings available via FLARE_* environment variables |
Installation
pip install fastapi-flare
Requirements: Python 3.11+, FastAPI.
aiosqliteandasyncpgare bundled โ no extra installs needed for either backend.
Quick Start
Zero-config (SQLite, works immediately):
from fastapi import FastAPI
from fastapi_flare import setup
app = FastAPI()
setup(app)
# Dashboard at http://localhost:8000/flare
# Creates flare.db automatically โ no setup required.
PostgreSQL (production):
from fastapi_flare import setup, FlareConfig
setup(app, config=FlareConfig(
storage_backend="postgresql",
pg_dsn="postgresql://user:password@localhost:5432/mydb",
))
Storage Backends
SQLite (default)
Zero-config local file storage. Works immediately without any external dependencies.
Ideal for development, quick testing, small deployments, and air-gapped environments.
setup(app, config=FlareConfig(
storage_backend="sqlite", # default โ can be omitted
sqlite_path="flare.db", # path to the .db file
))
Via environment variables:
FLARE_STORAGE_BACKEND=sqlite
FLARE_SQLITE_PATH=/data/flare.db
Uses WAL mode and indexed queries for efficient reads and writes.
PostgreSQL (production)
Production-grade backend using asyncpg with a connection pool.
Direct INSERT on every log entry โ no intermediate buffer or drain step.
setup(app, config=FlareConfig(
storage_backend="postgresql",
pg_dsn="postgresql://user:password@localhost:5432/mydb",
))
Via environment variables:
FLARE_STORAGE_BACKEND=postgresql
FLARE_PG_DSN=postgresql://user:password@localhost:5432/mydb
Special characters in passwords:
URL-encode@as%40,#as%23,&as%26, etc.
Example:password@123โFLARE_PG_DSN=postgresql://user:password%40123@host:5432/db
The table flare_logs (or your custom name) is created automatically on first connection.
Multi-Project Isolation
You can run multiple independent APIs storing their logs in the same PostgreSQL server.
Two isolation strategies are available โ choose what fits best:
Strategy 1 โ One database per project (full isolation)
Each API points to a different database. Complete separation at the database level.
# API checkout
FLARE_PG_DSN=postgresql://user:pass@host:5432/checkout_db
# API auth
FLARE_PG_DSN=postgresql://user:pass@host:5432/auth_db
# API orders
FLARE_PG_DSN=postgresql://user:pass@host:5432/orders_db
Strategy 2 โ One database, separate tables (centralized)
All APIs share one database, each writing to its own table.
Simpler to manage โ one database to back up, one server to monitor.
# All APIs point to the same database
FLARE_PG_DSN=postgresql://user:pass@host:5432/mydb
# Each project gets its own table
FLARE_PG_TABLE_NAME=flare_logs_checkout # API checkout
FLARE_PG_TABLE_NAME=flare_logs_auth # API auth
FLARE_PG_TABLE_NAME=flare_logs_orders # API orders
Each table is created automatically by flare on first connection.
Full Configuration
from fastapi_flare import setup, FlareConfig
setup(app, config=FlareConfig(
# โโ Storage (choose one) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
storage_backend="sqlite", # "sqlite" (default) | "postgresql"
# SQLite options
sqlite_path="flare.db",
# PostgreSQL options
pg_dsn="postgresql://user:pass@localhost:5432/mydb",
pg_table_name="flare_logs", # custom table name for multi-project setups
# โโ Retention โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
max_entries=10_000, # count-based cap
retention_hours=168, # time-based retention (7 days)
# โโ Dashboard โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
dashboard_path="/flare",
dashboard_title="My App โ Errors",
dashboard_auth_dependency=None, # e.g. Depends(verify_token)
# โโ Worker โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
worker_interval_seconds=5,
worker_batch_size=100,
))
Environment Variables
All options can be configured via FLARE_* environment variables โ no code changes needed:
FLARE_STORAGE_BACKEND=postgresql
FLARE_PG_DSN=postgresql://user:pass@localhost:5432/mydb
FLARE_PG_TABLE_NAME=flare_logs
FLARE_RETENTION_HOURS=72
FLARE_MAX_ENTRIES=5000
FLARE_DASHBOARD_PATH=/errors
FLARE_DASHBOARD_TITLE="Production Errors"
Dashboard
The built-in dashboard gives you full visibility into your application errors without leaving your infrastructure.
| Feature | Detail |
|---|---|
| URL | {dashboard_path} (default /flare) |
| Stats cards | Errors/Warnings in last 24h, total entries, latest error time |
| Filters | Level (ERROR / WARNING), event name, full-text search |
| Table | Timestamp, level badge, event, message, endpoint, HTTP status |
| Detail modal | Full message, error, stack trace, request metadata, context JSON |
| Storage overview | Backend info, connection status, pool stats (PostgreSQL) or file size (SQLite) |
| Auto-refresh | 30s polling toggle |
Log Entry Schema
Every captured error is stored as a structured FlareLogEntry:
class FlareLogEntry(BaseModel):
id: str # backend-native ID (row id for PG/SQLite)
timestamp: datetime
level: Literal["ERROR", "WARNING"]
event: str # e.g. "http_exception", "unhandled_exception"
message: str
request_id: str | None # UUID from X-Request-ID header
endpoint: str | None
http_method: str | None
http_status: int | None
ip_address: str | None
duration_ms: int | None
error: str | None
stack_trace: str | None
context: dict | None # additional structured data
request_body: dict | None # captured request body (if enabled)
Manual Logging
Push custom log entries from anywhere in your application:
from fastapi_flare.queue import push_log
await push_log(
config,
level="ERROR",
event="payment_failed",
message="Stripe charge declined",
context={"order_id": "ord_123", "amount": 2500},
)
Protecting the Dashboard
Secure the dashboard using any FastAPI dependency:
from fastapi import HTTPException, Security
from fastapi.security import HTTPBearer
bearer = HTTPBearer()
def verify_token(token=Security(bearer)):
if token.credentials != "my-secret":
raise HTTPException(status_code=401, detail="Unauthorized")
setup(app, config=FlareConfig(
dashboard_auth_dependency=verify_token,
))
Zitadel Authentication
fastapi-flare has built-in support for protecting the /flare dashboard via Zitadel OIDC.
Two integration modes are available:
| Mode | When to use |
|---|---|
| Browser (PKCE) | Users access /flare from a browser โ automatically redirected to the Zitadel login page |
| Bearer Token | API clients send Authorization: Bearer <token> โ no redirect |
Prerequisites
In the Zitadel console:
- Create a Web Application inside a project (type: PKCE / User Agent)
- Note the Domain โ e.g.
auth.mycompany.com - Note the Client ID of the application
- Note the Project ID (visible in the project's general settings)
- For browser mode: register the callback URL โ e.g.
https://myapp.com/flare/callback
Browser Mode (PKCE)
setup(app, config=FlareConfig(
zitadel_domain="auth.mycompany.com",
zitadel_client_id="000000000000000001",
zitadel_project_id="000000000000000002",
zitadel_redirect_uri="https://myapp.com/flare/callback",
zitadel_session_secret="<32-byte-hex>",
))
Via environment variables:
FLARE_ZITADEL_DOMAIN=auth.mycompany.com
FLARE_ZITADEL_CLIENT_ID=000000000000000001
FLARE_ZITADEL_PROJECT_ID=000000000000000002
FLARE_ZITADEL_REDIRECT_URI=https://myapp.com/flare/callback
FLARE_ZITADEL_SESSION_SECRET=<32-byte-hex>
# Generate: python -c "import secrets; print(secrets.token_hex(32))"
Flow:
- User opens
/flareโ no session โ redirected to/flare/auth/login - PKCE challenge generated โ redirected to Zitadel login
- User logs in โ Zitadel redirects to
callback-url?code=... fastapi-flareexchanges code for token โ creates signed session cookie- User redirected to
/flareโ access granted โ
Routes created automatically:
| Route | Purpose |
|---|---|
GET /flare/auth/login |
Starts the PKCE flow โ redirects to Zitadel |
GET <callback-path> |
Receives the code, exchanges it, creates the session |
GET /flare/auth/logout |
Clears the session โ redirects to login |
API Mode (Bearer Token)
When zitadel_redirect_uri is not set, the dashboard validates the Authorization: Bearer <token> header directly. No redirect flow.
Manual Mode (custom dependency)
from fastapi_flare.zitadel import make_zitadel_dependency
dep = make_zitadel_dependency(
domain="auth.mycompany.com",
client_id="000000000000000001",
project_id="000000000000000002",
)
setup(app, config=FlareConfig(dashboard_auth_dependency=dep))
Running the Example
# Zero-config SQLite (no setup needed)
poetry run uvicorn examples.example:app --reload --port 8000
# Dashboard at http://localhost:8000/flare
PostgreSQL example โ set in your .env:
FLARE_STORAGE_BACKEND=postgresql
FLARE_PG_DSN=postgresql://user:pass@localhost:5432/mydb
Test routes:
| Route | Behavior |
|---|---|
GET / |
Returns 200 OK |
GET /boom |
Triggers RuntimeError โ captured as ERROR |
GET /items/999 |
Triggers HTTPException 404 โ captured as WARNING |
GET /flare |
Opens the error dashboard |
Comparison
| Project | What it does |
|---|---|
sentry-sdk |
Full error tracking SaaS โ more features, external dependency |
fastapi-analytics |
Endpoint analytics / performance โ not error-focused |
fastapi-middleware-logger |
HTTP logging only, no storage or dashboard |
fastapi-flare |
Self-hosted, zero-config error tracking โ SQLite or PostgreSQL |
Why not Sentry?
| fastapi-flare | Sentry | |
|---|---|---|
| Hosting | Self-hosted, your infra | External SaaS |
| Account required | No | Yes |
| Setup | One setup(app) call |
SDK + DSN + account config |
| Storage | SQLite or PostgreSQL | Kafka, ClickHouse, Postgres, โฆ |
| Cost | Zero | Free tier โ paid plans |
| Privacy | Data never leaves your server | Data sent to third-party |
| Customization | Full source access | Configuration only |
fastapi-flare is the right choice when you need fast, private, zero-dependency error visibility โ especially in self-hosted, air-gapped, or cost-sensitive environments.
License
MIT ยฉ Gabriel
Project details
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_flare-0.2.0.tar.gz.
File metadata
- Download URL: fastapi_flare-0.2.0.tar.gz
- Upload date:
- Size: 80.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.11.9 Windows/10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a762d2e879bd76743c9774e27bee7a39ff7c3c89bc6565fc90734ecf2b5c22e2
|
|
| MD5 |
3cf20f5ad1afed6e3935ca954f7ad02d
|
|
| BLAKE2b-256 |
d4e6cb1de73a53f4434f278be38d783cbb2e889d45cce0e5c515056c7b13d565
|
File details
Details for the file fastapi_flare-0.2.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_flare-0.2.0-py3-none-any.whl
- Upload date:
- Size: 94.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.11.9 Windows/10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7efa731757ab1cd025b0d0c615d2a54f13780ff350b9fe05c652bd6755cebe98
|
|
| MD5 |
e57b6582ed0c8fee4ecc4ea6425030ae
|
|
| BLAKE2b-256 |
9a708bc40b45c95d199d69780aa6f07bde9f25a790da7e9136a64733d89c7ca6
|