Skip to main content

Lightweight self-hosted observability for FastAPI.

Project description

⚡ fastapi-flare

Lightweight self-hosted observability for FastAPI.
Backed by Redis Streams or SQLite — no SaaS, no overhead.


Python FastAPI Redis License: MIT


fastapi-flare dashboard preview

What is fastapi-flare?

fastapi-flare is a self-hosted error tracking library for FastAPI applications. It automatically captures HTTP and unhandled exceptions, stores them in Redis Streams, and exposes a beautiful dark-theme dashboard — all with a single line of code.

No external services. No configuration files. No noise.


Features

🚀 One-line setup setup(app) and you're done
🔍 Auto-capture HTTP 4xx/5xx and unhandled Python exceptions
🖥️ Admin dashboard Built-in at /flare — dark theme, filters, pagination
🗄️ Dual storage Redis Streams (production) or SQLite (zero-infra)
🔥 Fire-and-forget Logging never blocks or affects your request handlers
⚙️ Background worker Async task drains queue to stream 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 as FLARE_* environment variables

Installation

pip install fastapi-flare

All features (SQLite backend, Zitadel JWT auth) are included in the base install.

Requirements: Python 3.11+, FastAPI. Redis is only required when using the default redis storage backend.


Quick Start

Redis (default — production-ready, durable):

from fastapi import FastAPI
from fastapi_flare import setup

app = FastAPI()
setup(app, redis_url="redis://localhost:6379")

SQLite (zero-infra — no Redis required):

from fastapi import FastAPI
from fastapi_flare import FlareConfig, setup

app = FastAPI()
setup(app, config=FlareConfig(storage_backend="sqlite", sqlite_path="flare.db"))

Visit http://localhost:8000/flare to open the error dashboard.


Storage Backends

Redis (default)

Uses a Redis List as buffer queue and a Redis Stream as durable storage. Best for production deployments where Redis is already available.

setup(app, config=FlareConfig(
    storage_backend="redis",           # default
    redis_url="redis://localhost:6379",
    redis_password=None,
    stream_key="flare:logs",
    queue_key="flare:queue",
))

Docker:

docker run -d -p 6379:6379 redis:7

SQLite

Stores everything in a local .db file. No external services, no Docker, no configuration — ideal for local development, small deployments, or air-gapped environments.

setup(app, config=FlareConfig(
    storage_backend="sqlite",
    sqlite_path="flare.db",            # path to the .db file
))

The SQLite backend uses WAL mode and indexed queries for efficient reads and writes.


Full Configuration

from fastapi_flare import setup, FlareConfig

setup(app, config=FlareConfig(
    # --- Backend (choose one) ---
    storage_backend="redis",           # "redis" | "sqlite"

    # Redis options (storage_backend="redis")
    redis_url="redis://localhost:6379",
    redis_password=None,
    stream_key="flare:logs",
    queue_key="flare:queue",

    # SQLite options (storage_backend="sqlite")
    # sqlite_path="flare.db",

    # --- Shared ---
    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 set via FLARE_* env vars — no code changes needed:

FLARE_REDIS_URL=redis://myhost:6379
FLARE_RETENTION_HOURS=72
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
Auto-refresh 30s polling toggle

Redis Data Model

fastapi-flare uses two Redis structures:

Key Type Purpose
flare:queue List Incoming buffer — LPUSH by handlers, RPOP by worker
flare:logs Stream Durable time-ordered storage — XADD / XREVRANGE

Stream entries are automatically trimmed by two policies applied on every worker cycle:

  1. Count-basedMAXLEN ~ keeps at most max_entries items
  2. Time-basedXTRIM MINID removes entries older than retention_hours

Log Entry Schema

Every captured error is stored as a structured FlareLogEntry:

class FlareLogEntry(BaseModel):
    id: str                    # Redis Stream entry ID (millisecond-precise)
    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

Manual Logging

You can 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(
    redis_url="redis://localhost:6379",
    dashboard_auth_dependency=verify_token,
))

Zitadel Authentication

fastapi-flare tem suporte nativo para proteger o dashboard /flare via Zitadel OIDC.
Existem dois modos de integração:

Modo Quando usar
Browser (PKCE) Usuários acessam /flare pelo navegador — redirecionados para o login do Zitadel automaticamente
Bearer Token Clientes de API enviam Authorization: Bearer <token> — sem redirecionamento

Requer o extra [auth]:

pip install 'fastapi-flare[auth]'

Pré-requisitos

No console do Zitadel:

  1. Crie uma Web Application dentro de um projeto (tipo: PKCE)
  2. Anote o Domain — ex: auth.mycompany.com
  3. Anote o Client ID da aplicação
  4. Anote o Project ID (visível nas configurações gerais do projeto)
  5. Para modo browser: registre a URL de callback — ex: https://myapp.com/flare/callback

Modo Browser (PKCE) — acesso pelo navegador

Quando zitadel_redirect_uri está configurado, abrir /flare no browser redireciona automaticamente para o Zitadel. Após o login, o Zitadel chama o callback, o token é salvo em cookie e o usuário é redirecionado de volta ao dashboard.

setup(app, config=FlareConfig(
    redis_url="redis://localhost:6379",
    zitadel_domain="auth.mycompany.com",
    zitadel_client_id="000000000000000001",
    zitadel_project_id="000000000000000002",
    zitadel_redirect_uri="https://myapp.com/flare/callback",
))

Via variáveis de ambiente:

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=<hex-de-32-bytes>  # python -c "import secrets; print(secrets.token_hex(32))"

O que acontece:

  1. Usuário abre https://myapp.com/flare no browser
  2. fastapi-flare detecta ausência de sessão → redireciona para /flare/auth/login
  3. /flare/auth/login gera PKCE challenge, salva code_verifier + state na sessão, redireciona para o Zitadel
  4. Usuário faz login na tela do Zitadel
  5. Zitadel redireciona para /flare/callback?code=...&state=...
  6. fastapi-flare valida o state, troca o code pelo access_token, chama /oidc/v1/userinfo
  7. Dados do usuário e timestamp de expiração salvos na sessão (cookie assinado flare_session)
  8. Usuário redirecionado para /flare — acesso liberado ✅

Importante: registre exatamente https://yourapp.com/flare/callback como Redirect URI no app do Zitadel.

Rotas criadas automaticamente:

Rota O que faz
GET /flare/auth/login Inicia o fluxo PKCE → redireciona ao Zitadel
GET /flare/callback Recebe o code, troca por token, cria sessão
GET /flare/auth/logout Limpa a sessão → redireciona ao login

Modo API (Bearer Token) — sem zitadel_redirect_uri

Quando zitadel_redirect_uri não está definido, a proteção valida o header Authorization: Bearer <token>. Ideal para quando o frontend já gerencia o fluxo PKCE e injeta o token nas requisições.

setup(app, config=FlareConfig(
    redis_url="redis://localhost:6379",
    zitadel_domain="auth.mycompany.com",
    zitadel_client_id="000000000000000001",
    zitadel_project_id="000000000000000002",
    # sem zitadel_redirect_uri → modo Bearer
))

Modo Manual — dependency customizada (avançado)

from fastapi_flare import setup, FlareConfig
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(
    redis_url="redis://localhost:6379",
    dashboard_auth_dependency=dep,
))

Migração de projeto — aceitar tokens do projeto antigo

FLARE_ZITADEL_OLD_CLIENT_ID=old-client-id
FLARE_ZITADEL_OLD_PROJECT_ID=old-project-id

Tokens dos dois projetos são aceitos até você remover os campos _old_*.


Como funciona internamente

  • A sessão é gerenciada pelo SessionMiddleware do Starlette — cookie flare_session assinado com HMAC usando zitadel_session_secret. Todo o conteúdo (user, tokens, expiração) fica dentro do cookie — sem banco, sem Redis para gerenciar sessões.
  • O code_verifier e state PKCE são armazenados na sessão (não em cookies separados), exatamente como recomendam as specs do PKCE.
  • Após o callback, fastapi-flare chama /oidc/v1/userinfo para buscar os dados reais do usuário (email, nome, etc.) e os salva na sessão.
  • Sessões expiram automaticamente após 1 hora — o usuário é redirecionado para login sem interrupção.
  • Use clear_jwks_cache() para resetar o cache de JWKS em testes (modo Bearer).

Running the Example

SQLite mode (no dependencies):

poetry run uvicorn examples.example:app --reload --port 8000

Redis mode:

# 1. Copy and configure environment
cp .env.example .env

# 2. Start Redis (Docker)
docker run -d -p 6379:6379 redis:7

# 3. Switch the example to Redis and run
# In examples/example.py, change:
#   FlareConfig(storage_backend="redis")  # and set FLARE_REDIS_URL in .env
poetry run uvicorn examples.example:app --reload --port 8000

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
api-watch Real-time monitoring, Flask/FastAPI
fastapi-flare Self-hosted, zero-config error visibility — no external services

fastapi-flare is for teams that want local, observable, production-ready error tracking without the overhead of a full observability platform.


Why not Sentry?

Sentry is a great product — but it comes with trade-offs that not every team wants to accept.

fastapi-flare Sentry
Hosting Self-hosted, your infra External SaaS
Account required No Yes
Infrastructure Redis only Kafka, ClickHouse, Postgres, …
Cost Zero Free tier → paid plans
Privacy Data never leaves your server Data sent to third-party
Setup One setup(app) call SDK + DSN + account config
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.
For large-scale teams who need release tracking, performance monitoring, and team workflows, Sentry remains the better fit.


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

fastapi_flare-0.1.2.tar.gz (55.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_flare-0.1.2-py3-none-any.whl (65.7 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_flare-0.1.2.tar.gz.

File metadata

  • Download URL: fastapi_flare-0.1.2.tar.gz
  • Upload date:
  • Size: 55.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.11.9 Windows/10

File hashes

Hashes for fastapi_flare-0.1.2.tar.gz
Algorithm Hash digest
SHA256 38f3d5ac60cd64e7b09c7b48ae09f6460ae0b0758a645ed7147a8b95b9c4a563
MD5 77ec54cae1bff9d858694431dcb034e2
BLAKE2b-256 2d3617cde43d8278fc3d349ea2bb30cf05d8b6e47d40b3c0d62b5c528104bc0f

See more details on using hashes here.

File details

Details for the file fastapi_flare-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: fastapi_flare-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 65.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.11.9 Windows/10

File hashes

Hashes for fastapi_flare-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c9801d052fc2c5816fa7115417020fcaf5a61e5345779c9ae299a15d94c39ada
MD5 690d44763169990b7c9629a636fd4883
BLAKE2b-256 9419b98b9a8f90d6ae2c6da1a0e55f706a7e74fedbc6f1b85002cc71ae0bcc3d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page