Pure Python, no C extensions, zero third-party dependencies. Auto-captures unhandled exceptions via sys.excepthook and threading.excepthook. Tested on 3.10, 3.11, 3.12, 3.13.
The package is not yet on PyPI. Install from the repo or build a wheel locally.
# From the CodeRadar repo (editable install during development)
pip install -e ./sdks/python
# Or build and install a wheel
cd sdks/python && python -m build && pip install dist/coderadar_sdk-*.whl
When published, the install command will be:
pip install coderadar-sdk
# or: poetry add coderadar-sdk
# or: uv add coderadar-sdk
Call coderadar.init() once at process startup, before any frameworks load.
import os
import coderadar
coderadar.init(
dsn = os.environ["CODERADAR_DSN"],
environment = os.environ.get("ENV", "production"),
release = os.environ.get("RELEASE_SHA", ""),
)
| Option | Default | Notes |
|---|---|---|
dsn | — | Required. DSN URL or raw project key. |
environment | "production" | dev / staging / production / preview-* |
release | "" | Git SHA or semver. Attached to every event. |
endpoint | "https://ingest.coderadar.app/v1/events" | Override the ingest URL. |
max_breadcrumbs | 30 | Per-event breadcrumb buffer. |
flush_batch_size | 10 | Events per POST batch. |
flush_interval_s | 2.0 | Background flush interval in seconds. |
install_excepthook | True | Set to False to skip patching sys.excepthook. |
import coderadar
try:
risky_operation()
except Exception as exc:
coderadar.capture_exception(exc, ctx={
"tags": {"stage": "checkout"},
"service_name": "payments-service",
})
raise
Call with no arguments inside an except block to capture the current exception from sys.exc_info():
try:
risky_operation()
except Exception:
coderadar.capture_exception() # uses sys.exc_info()
raise
# levels: "debug" | "info" | "warning" | "error" | "fatal"
coderadar.capture_message("background job started", level="info")
coderadar.capture_message("rate limit at 80%", level="warning")
coderadar.add_breadcrumb(
category = "db.query",
message = "SELECT * FROM orders WHERE user_id = ?",
data = {"user_id": user.id, "rows": 42},
crumb_type = "query",
)
coderadar.set_user({"id": user.id, "email": user.email, "plan": user.plan})
The SDK does not yet ship a built-in FastAPI middleware class — wire it manually as an ASGI middleware or use a Starlette ExceptionMiddleware override:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import coderadar
app = FastAPI()
@app.middleware("http")
async def capture_errors(request: Request, call_next):
try:
return await call_next(request)
except Exception as exc:
coderadar.capture_exception(exc, ctx={
"tags": {
"http.method": request.method,
"http.path": request.url.path,
}
})
return JSONResponse(status_code=500, content={"detail": "Internal server error"})
Add a thin middleware class to settings.MIDDLEWARE:
# myapp/middleware.py
import coderadar
class CodeRadarMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_exception(self, request, exception):
coderadar.capture_exception(exception, ctx={
"tags": {
"http.method": request.method,
"http.path": request.path,
}
})
return None # let Django's default handler run
# settings.py
MIDDLEWARE = [
"myapp.middleware.CodeRadarMiddleware",
# ... rest of middleware
]
import coderadar
import signal, sys
def shutdown(sig, frame):
coderadar.flush()
sys.exit(0)
signal.signal(signal.SIGTERM, shutdown)
coderadar-sdk but the import name is coderadar. This is standard Python convention for hyphenated package names.threading.Timer, which is compatible with asyncio. However, if you need async-native capture (e.g. in a tight asyncio loop), call capture_exception() normally — it enqueues to a thread-safe queue and returns immediately.coderadar-sdk is not yet on PyPI. Install from source until a release is tagged.