Metadata-Version: 2.4
Name: overcast-sdk
Version: 2.0.0
Summary: Overcast SRE monitoring SDK for Python — one-line install, captures everything.
Home-page: https://github.com/overcast/sdk-python
Author: Overcast SRE
Author-email: sdk@overcastsre.com
Keywords: overcast monitoring logging error-tracking observability apm
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Provides-Extra: flask
Requires-Dist: flask>=2.0; extra == "flask"
Provides-Extra: django
Requires-Dist: django>=3.2; extra == "django"
Provides-Extra: fastapi
Requires-Dist: fastapi; extra == "fastapi"
Requires-Dist: starlette; extra == "fastapi"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: provides-extra
Dynamic: requires-python
Dynamic: summary

# overcast-sdk (Python) v2

Overcast SRE monitoring SDK for Python.  One install, one line â€” captures everything.

**Zero external dependencies** â€” uses only Python stdlib.

## Install

```bash
pip install overcast-sdk
```

## Quick Start

```python
import overcast_sdk

overcast_sdk.init(api_key="oc_...", service_name="my-api")
```

That's it.  The SDK automatically captures:

- All `logging.*` output (DEBUG through CRITICAL)
- All `print()` / stdout / stderr output
- Uncaught exceptions (`sys.excepthook`)
- Thread exceptions (`threading.excepthook`)
- Outgoing HTTP requests (`requests`, `httpx`)
- Stack traces with full context

## What's New in v2

| Feature | Description |
|---|---|
| **Breadcrumbs** | Trail of events leading up to an error |
| **Scoped context** | Per-request tags, user info, extra data via `contextvars` |
| **`before_send` hook** | Filter or modify events before they leave the process |
| **`send_default_pii`** | Opt-in PII (default: off â€” IPs and user agents stripped) |
| **Gzip compression** | Payloads are gzip-compressed before sending |
| **Rate-limit handling** | Respects server `429` / `Retry-After` responses |
| **Health monitoring** | Adaptive downsampling when the transport is unhealthy |
| **Background worker** | Single persistent daemon thread (no thread-per-flush) |
| **Safe serialization** | Cycle detection, depth/breadth limits, safe repr fallbacks |
| **Modular architecture** | Pluggable integration framework with auto-discovery |

## Scoped Context

```python
import overcast_sdk

# Tags appear on every event in the current request
overcast_sdk.set_tag("region", "us-east-1")
overcast_sdk.set_tag("tenant", "acme-corp")

# User context â€” who was affected?
overcast_sdk.set_user({"id": "usr_123", "email": "alice@acme.com"})

# Extra data â€” arbitrary key/value
overcast_sdk.set_extra("order_id", 456)

# Manual breadcrumbs
overcast_sdk.add_breadcrumb({
    "type": "user",
    "category": "checkout",
    "message": "User clicked 'Place Order'",
})
```

## `before_send` Hook

```python
def my_filter(event):
    # Drop noisy health-check logs
    if "/healthz" in event.get("message", ""):
        return None  # drop
    # Modify events
    event.setdefault("tags", {})["team"] = "platform"
    return event

overcast_sdk.init(
    api_key="oc_...",
    service_name="my-api",
    before_send=my_filter,
)
```

## Framework Middleware

### Flask

```python
from flask import Flask
from overcast_sdk import middleware_flask

app = Flask(__name__)
middleware_flask(app)
```

### FastAPI / Starlette (ASGI)

```python
from fastapi import FastAPI
from overcast_sdk import middleware_asgi

app = FastAPI()
app = middleware_asgi(app)
```

### Django

```python
# settings.py
MIDDLEWARE = [
    "overcast_sdk.middleware_django",
    ...
]
```

## Manual Logging

```python
overcast_sdk.error("Payment failed", order_id=123)
overcast_sdk.warn("Slow query detected", query_ms=4200)
overcast_sdk.info("User signed up", user_id="usr_456")
overcast_sdk.debug("Cache hit", key="session:abc")

try:
    risky_operation()
except Exception as exc:
    overcast_sdk.capture_exception(exc)
```

## Encryption

```python
overcast_sdk.init(
    api_key="oc_...",
    service_name="my-api",
    encrypt_payload=True,
    encryption_key="your-64-char-hex-key-here",  # 32 bytes in hex
)
```

## All Options

| Option | Default | Description |
|---|---|---|
| `api_key` | *required* | Your Overcast API key |
| `service_name` | `"python-app"` | Service name in the dashboard |
| `environment` | `$OVERCAST_ENVIRONMENT` / `$PYTHON_ENV` / `"production"` | Environment label |
| `base_url` | `"https://platform.overcastsre.com"` | API base URL |
| `capture_logging` | `True` | Capture `logging.*` calls |
| `capture_stdout` | `True` | Capture `print()` / stdout |
| `capture_stderr` | `True` | Capture stderr |
| `capture_exceptions` | `True` | Capture uncaught exceptions |
| `capture_threads` | `True` | Capture thread exceptions |
| `capture_http` | `True` | Capture outgoing HTTP requests |
| `capture_signals` | `True` | Capture SIGTERM / SIGINT |
| `slow_request_threshold` | `5.0` | Seconds before a request is "slow" |
| `batch_size` | `50` | Logs per batch |
| `flush_interval` | `5.0` | Flush interval in seconds |
| `log_sampling_rate` | `1.0` | 0.0â€“1.0 sampling for non-error logs |
| `send_default_pii` | `False` | Include IPs and user agents |
| `sanitize` | `True` | Redact PII (passwords, tokens, etc.) |
| `encrypt_payload` | `False` | AES-256-GCM encrypt payloads |
| `encryption_key` | `""` | 32-byte hex key |
| `enable_compression` | `True` | Gzip-compress payloads |
| `before_send` | `None` | `fn(event) -> event \| None` |
| `before_breadcrumb` | `None` | `fn(crumb, hint) -> crumb \| None` |
| `debug` | `False` | Print SDK debug output to stderr |

## Architecture

```
overcast_sdk/
â”œâ”€â”€ __init__.py              # Public exports
â”œâ”€â”€ api.py                   # Top-level functions (init, error, set_tag, â€¦)
â”œâ”€â”€ client.py                # OvercastClient â€” owns transport, scrubber, scope
â”œâ”€â”€ consts.py                # Constants, limits, default config
â”œâ”€â”€ scope.py                 # Scope + breadcrumbs (contextvars isolation)
â”œâ”€â”€ transport.py             # BackgroundWorker, batching, compression, rate-limiting
â”œâ”€â”€ serializer.py            # Cycle-safe serialization with depth/breadth limits
â”œâ”€â”€ scrubber.py              # PII scrubbing (key deny-list + regex patterns)
â”œâ”€â”€ utils.py                 # Internal helpers (capture_internal, safe_str, â€¦)
â””â”€â”€ integrations/
    â”œâ”€â”€ __init__.py          # Integration ABC, DidNotEnable, auto-discovery
    â”œâ”€â”€ _logging.py          # logging module capture
    â”œâ”€â”€ _stdlib.py           # stdout, stderr, excepthook, signals
    â”œâ”€â”€ _flask.py            # Flask middleware
    â”œâ”€â”€ _django.py           # Django middleware
    â”œâ”€â”€ _asgi.py             # ASGI / FastAPI middleware
    â”œâ”€â”€ _requests.py         # requests library capture
    â””â”€â”€ _httpx.py            # httpx library capture
```
