Skip to content

MakFly/errorwatch-sdk-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ErrorWatch SDK for Python

PyPI Python License

Self-hosted error monitoring for FastAPI, Starlette, and any async-Python app — a Sentry-compatible-ish SDK that ships errors to your own ErrorWatch instance.

  • Async-first: fire-and-forget on httpx.AsyncClient, never blocks the request hot path.
  • Sync fallback: usable from CLIs, workers, or atexit hooks.
  • ASGI middleware: drop-in for FastAPI/Starlette.
  • contextvars scope: tags, user, breadcrumbs propagate naturally across await boundaries.
  • stdlib logging bridge: log records become breadcrumbs and (optionally) events.
  • Zero crash guarantee: the SDK never propagates an exception to your app.

Install

pip install errorwatch-sdk[fastapi]

Or, from a sibling clone (monorepo / local dev):

pip install -e /Users/kev/Documents/lab/sandbox/errorwatch/packages/sdk-python

Requires Python 3.9+ and httpx.


Quick start (FastAPI)

# app/main.py
from fastapi import FastAPI
import errorwatch
from errorwatch.integrations.fastapi import install, lifespan_shutdown_hook

errorwatch.init(
    api_key="ew_xxx",                       # or env var ERRORWATCH_API_KEY
    endpoint="https://errorwatch.example",  # your self-hosted instance
    environment="production",
    release="api@1.4.2",
    project_root="/srv/app",                # for in_app frame detection
)

app = FastAPI()
install(app)                  # ASGI middleware: captures unhandled exceptions
lifespan_shutdown_hook(app)   # flushes pending sends on graceful shutdown

That's it — every unhandled exception in any route is reported with full stack, source context, request URL, method, headers (sensitive ones filtered), and the current scope (user/tags/breadcrumbs).


Manual capture

import errorwatch

try:
    risky_call()
except Exception:
    errorwatch.capture_exception()       # uses sys.exc_info()

errorwatch.capture_message("payment retry exhausted", level="warning")

Scope, tags, user, breadcrumbs

import errorwatch

errorwatch.set_user({"id": "u_42", "email": "alice@example.com"})
errorwatch.set_tag("tenant", "kweli")
errorwatch.set_extra("invoice_id", "inv_8821")

errorwatch.add_breadcrumb(
    category="db",
    message="SELECT * FROM orders WHERE …",
    level="info",
    data={"rows": 312},
)

Each request gets its own isolated scope thanks to contextvars, so concurrent FastAPI requests never see each other's user/tags.

For ad-hoc isolation (e.g. inside a background task):

from errorwatch import push_scope

with push_scope() as s:
    s.set_tag("job", "nightly-export")
    do_thing()  # tag visible only inside this block

Logging bridge

import logging
from errorwatch.integrations.logging import BreadcrumbHandler, EventHandler

root = logging.getLogger()
root.addHandler(BreadcrumbHandler(level=logging.INFO))   # every log → breadcrumb
root.addHandler(EventHandler(level=logging.ERROR))       # errors → events

Configuration

Option Env var Default Description
api_key ERRORWATCH_API_KEY Project API key. SDK is inert if empty.
endpoint ERRORWATCH_ENDPOINT https://api.errorwatch.io Base URL — SDK appends /api/v1/envelope.
environment ERRORWATCH_ENVIRONMENT production Free-form env label.
release ERRORWATCH_RELEASE Release identifier (commit SHA, semver…).
project_root ERRORWATCH_PROJECT_ROOT Used to mark frames as in_app.
sample_rate 1.0 Client-side sampling (0.0 – 1.0).
max_breadcrumbs 50 Ring buffer size per scope.
max_context_lines 5 Source lines before/after each frame.
send_default_pii False If False, sensitive headers (auth, cookie…) are filtered.
timeout 5.0 HTTP request timeout (s).
before_send None Callable[[payload], payload | None] — drop by returning None.
debug False Logs transport diagnostics to the errorwatch logger.

Wire format

The SDK posts to POST {endpoint}/api/v1/envelope with header X-API-Key: <key>. Payload is the v2 enriched event shape — same as the official PHP SDK:

{
  "event_id": "4f7d…",
  "timestamp": "2026-05-12T11:23:45.123Z",
  "platform": "python",
  "level": "error",
  "sdk": { "name": "errorwatch-python", "version": "0.1.0" },
  "contexts": { "runtime": { "name": "python", "version": "3.12.3" },  },
  "exception": { "type": "ValueError", "value": "boom" },
  "frames": [
    {
      "filename": "/srv/app/services/billing.py",
      "function": "charge_card",
      "lineno": 88,
      "in_app": true,
      "context_line": "    raise ValueError('boom')",
      "pre_context": ["def charge_card(amount):", "    if amount < 0:"],
      "post_context": ["", "def refund(amount):"]
    }
  ],
  "environment": "production",
  "release": "api@1.4.2",
  "server_name": "ip-10-0-3-12",
  "tags": { "tenant": "kweli" },
  "user": { "id": "u_42" },
  "request": {
    "url": "https://api.example/orders",
    "method": "POST",
    "headers": { "host": "api.example", "authorization": "[Filtered]" },
    "query_string": "page=2"
  },
  "breadcrumbs": [  ]
}

Architecture

┌──────────────────────── your FastAPI app ─────────────────────────┐
│                                                                   │
│   request ──▶ ErrorWatchMiddleware ──▶ route handler ──▶ response │
│                       │                                           │
│                       │ on exception                              │
│                       ▼                                           │
│            ┌──────────────────────┐                               │
│            │ Client.capture_*()   │                               │
│            └──────────┬───────────┘                               │
│                       │                                           │
│            ┌──────────▼───────────┐                               │
│            │ Scope.apply_to_event │  user / tags / breadcrumbs    │
│            └──────────┬───────────┘                               │
│                       │                                           │
│            ┌──────────▼───────────┐    fire-and-forget            │
│            │ AsyncTransport.send  │ ──────────────┐               │
│            └──────────────────────┘               │               │
└────────────────────────────────────────────────────┼──────────────┘
                                                    │ httpx POST
                                                    ▼
                                  https://errorwatch.example/api/v1/envelope

Development

cd packages/sdk-python
pip install -e ".[dev,fastapi]"
pytest -q
ruff check .
mypy errorwatch

License

MIT — see LICENSE.

About

ErrorWatch SDK for Python — async-first error monitoring for FastAPI, Starlette, and ASGI apps

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors