Docs · SDK · Python

Python SDK.

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.

Install

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

Init

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", ""),
)

Init options

OptionDefaultNotes
dsnRequired. 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_breadcrumbs30Per-event breadcrumb buffer.
flush_batch_size10Events per POST batch.
flush_interval_s2.0Background flush interval in seconds.
install_excepthookTrueSet to False to skip patching sys.excepthook.

capture_exception

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

capture_message

# levels: "debug" | "info" | "warning" | "error" | "fatal"
coderadar.capture_message("background job started", level="info")
coderadar.capture_message("rate limit at 80%",      level="warning")

Breadcrumbs

coderadar.add_breadcrumb(
    category   = "db.query",
    message    = "SELECT * FROM orders WHERE user_id = ?",
    data       = {"user_id": user.id, "rows": 42},
    crumb_type = "query",
)

User context

coderadar.set_user({"id": user.id, "email": user.email, "plan": user.plan})

FastAPI middleware

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"})

Django middleware

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
]

Flush on shutdown

import coderadar
import signal, sys

def shutdown(sig, frame):
    coderadar.flush()
    sys.exit(0)

signal.signal(signal.SIGTERM, shutdown)

Common gotchas

  • Package name — The PyPI distribution name is coderadar-sdk but the import name is coderadar. This is standard Python convention for hyphenated package names.
  • threading.excepthook requires Python 3.8+ — On 3.7 and earlier, exceptions raised in non-main threads are only caught if you wrap the thread target manually.
  • Async frameworks — The SDK's internal flush uses a daemon 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.
  • flush() is synchronous — It blocks the calling thread until the queue drains or the request times out. Call it in a shutdown hook, not in a request handler.
  • Package not publishedcoderadar-sdk is not yet on PyPI. Install from source until a release is tagged.