Metadata-Version: 2.4
Name: bugtape
Version: 0.1.1
Summary: Report Python server errors to BugTape, with messages redacted. Streamlit, logging and Datadog trace links included.
Author-email: BugTape <hi@bugtape.ai>
License-Expression: Apache-2.0
Project-URL: Homepage, https://bugtape.ai/
Project-URL: Documentation, https://bugtape.ai/docs/python/
Keywords: error tracking,bug reports,streamlit,logging,exceptions
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Bug Tracking
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# bugtape (Python)

Report Python server errors to [BugTape](https://bugtape.ai/), with error messages redacted before they leave your process.

```bash
pip install bugtape
```

```python
import bugtape

bugtape.init(service="analytics")  # key from BUGTAPE_KEY
```

Each report carries a release, so BugTape can tell a fixed issue from a regression. It is `release=` if you pass one, else `BUGTAPE_RELEASE`, `DD_VERSION`, then the commit your CI or host sets (`GITHUB_SHA`, `VERCEL_GIT_COMMIT_SHA`, `RENDER_GIT_COMMIT` and others; see `bugtape.COMMIT_ENV_KEYS`).

In a short script, call `bugtape.flush()` before it ends. It returns `True` when every report since the last flush was accepted, and `False` on timeout or when one was rejected or could not be sent (`debug=True` logs why).

That reports:

- uncaught exceptions in the main thread and in threads,
- `logging` records at ERROR and above (with their exception when there is one),
- anything you pass to `bugtape.capture_exception()` or `bugtape.capture_message()`,
- uncaught exceptions in Streamlit pages (turned on automatically when Streamlit is imported).

## What leaves your server

- The exception type, a **redacted** message, and the stack: file, function and line for each frame.
- Never frame locals or source lines.
- Redaction replaces quoted values, numbers and amounts, emails, SQL, URLs with credentials, cloud paths and ids. `KeyError: 'Acme Pty Ltd'` is sent as `KeyError: '[redacted]'`. Python type names such as `'int'` are kept.
- Redaction works by pattern: a bare name written into a message (`f"no rate for {client}"`) is not recognised. Log arguments (`log.error("failed for %s", client)`) are never sent.
- Add your own patterns with `extra_redactions=[(r"regex", "[replacement]")]`, inspect and change every report with `before_send=lambda payload: payload`, or send only the exception type with `send_messages=False`.

## Streamlit

```python
import streamlit as st
import bugtape

bugtape.init(service="analytics")  # Streamlit is detected; page errors are reported

st.title("Revenue")
```

Errors still appear in the app exactly as before. Each report names the page and the Streamlit session.

## Datadog

If your app runs `ddtrace`, each report carries the active trace and span ids, and the BugTape console links to the trace in Datadog. BugTape never starts Datadog itself.

## Options

| Option | Default | |
|---|---|---|
| `api_key` | `BUGTAPE_KEY` | Capture key (`bt_live_…` / `bt_test_…`) |
| `service` | `BUGTAPE_SERVICE`, `DD_SERVICE`, `app` | Name of this app |
| `release` / `environment` | `BUGTAPE_RELEASE`, `DD_VERSION` / `BUGTAPE_ENVIRONMENT`, `DD_ENV` | |
| `endpoint` | `https://app.bugtape.ai/v1/ingest` | |
| `redact` | `True` | Turn message redaction off only for data you know is safe |
| `capture_uncaught` / `capture_logging` | `True` | |
| `streamlit` | auto | `True` to require it, `False` to skip |

Reports are sent from a background thread with a 5 second timeout and at most 30 per minute. BugTape never raises into your app.

Docs: https://bugtape.ai/docs/python/
