Python
pip install fictura, two lines in main.py, and the logger.error calls you already write become issues.
For FastAPI or any ASGI app. Zero dependencies, one stdlib-only module. Prefer vendoring? The same file is served at https://api.fictura.co/sdk/fictura.py.
pip install ficturaWire it
import os
from fastapi import FastAPI
from fictura import Fictura
fictura = Fictura(
api_base="https://api.fictura.co",
api_key="gk_...", # Dashboard → Setup → SDK app key
release=os.getenv("GIT_SHA"),
environment=os.getenv("ENV", "production"),
# Optional: however your auth middleware stashes the user.
get_user_id=lambda scope: ((scope.get("state") or {}).get("user") or {}).get("id"),
)
app = FastAPI()
app.add_middleware(fictura.middleware)Set get_user_id
Without it every issue arrives anonymous and "users affected" stays at zero. With it, an error links straight to that user's event history.
What gets captured
Unhandled exceptions, via the middleware — your own error handling is untouched; it re-raises after queueing. And every logger.error(...) you already write: constructing Fictura() attaches a logging handler, so this is already an issue:
try:
result = await gemini.generate(prompt)
except Exception as e:
logger.error(f"Generation failed: {e}") # ← already reported
return fallback()You get the full traceback even though nothing passed exc_info= — inside an except block the exception is still live and gets picked up. A log line with no exception in flight still becomes an issue, grouped by its call site. Anything explicit goes through fictura.capture_exception(e, route="/api/v1/generate", level="warning"); an exception that is logged and re-raised is reported once.
Options
| Argument | Default | |
|---|---|---|
capture_logs | True | Report log records. False for crashes only. |
log_level | logging.ERROR | Lower it to WARNING to widen the net. |
environment | "production" | Keeps staging noise out of production's list. |
release | None | Which deploy an error came from. |
Guarantees
Never raises into your app, never blocks a response. Reporting happens on a daemon thread with a bounded queue that drops oldest-first, batches of 20, a 2s HTTP timeout, and no retry storms. If we're down, your app doesn't notice. Smoke test: python -m fictura exercises all three capture paths; the events appear on the Issues page within seconds.