Metadata-Version: 2.4
Name: changewatcher
Version: 1.0.2
Summary: ChangeWatch Python SDK for error and performance monitoring
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/aarizbobbydeol/changewatch
Project-URL: Source, https://github.com/aarizbobbydeol/changewatch/tree/main/sdk
Project-URL: Issues, https://github.com/aarizbobbydeol/changewatch/issues
Project-URL: Changelog, https://github.com/aarizbobbydeol/changewatch/blob/main/CHANGELOG.md
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# ChangeWatch Python SDK

Reports errors, slow requests and a request count per minute to a self-hosted
[ChangeWatch](https://github.com/aarizbobbydeol/changewatch) server, so it can tell you within
minutes whether a deploy broke something. Works with FastAPI, Django and Flask. No dependencies,
Python 3.9 or newer.

```bash
pip install changewatcher
```

Imported as `changewatch`. Straight from GitHub instead: `pip install "git+https://github.com/aarizbobbydeol/changewatch.git#subdirectory=sdk"`.

```python
import os
import changewatch
from changewatch import ASGIMiddleware
from fastapi import FastAPI

cw = changewatch.init(
    api_key=os.environ["CHANGEWATCH_API_KEY"],   # cw_ingest_...
    release=os.environ.get("GIT_SHA"),           # ties events to the deploy
    endpoint="https://changewatch.example.com",
)

app = FastAPI()
app.add_middleware(ASGIMiddleware, client=cw)   # errors, latency, heartbeats
```

**Django** (WSGI or ASGI, sync and async views): call `changewatch.init(...)` in `settings.py` as above, then put the middleware first:

```python
MIDDLEWARE = [
    "changewatch.DjangoMiddleware",   # first, so it sees every request
    # ... your other middleware
]
```

**Flask** (and its errors that Flask answers with a 500 itself):

```python
from flask import Flask
app = Flask(__name__)
changewatch.instrument_flask(app)
```

**Any other WSGI app** (Bottle, Falcon, Pyramid on gunicorn or uWSGI): `app = changewatch.WSGIMiddleware(app)`. A request that raises or answers 5xx counts as failed.

Optional: `capture_logs=True` attaches the app's last 50 log lines (WARNING and above, or
`log_level=`) to each error; `capture_logged_errors=True` (on its own or with `capture_logs`) also
reports exceptions that are caught and only logged with `logger.exception(...)`. An exception that
is logged and then raised on is reported once, with the request's path and method. Only lines that
reach the root logger count (as in your own log output). The SDK adds no logging handler, so
`logging.basicConfig()` and `dictConfig()` work as usual, before or after `init()`.

The SDK never raises into your app and never blocks a request: events go into a bounded queue
that a background thread sends in batches. Secrets and personal data (emails, IPs, tokens) are
removed before anything leaves the process. `CHANGEWATCH_DISABLED=1` turns it off.
