Metadata-Version: 2.4
Name: vestara
Version: 0.1.0
Summary: Python SDK for Vestara crash reporting and remote logging.
License-Expression: Apache-2.0
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# Vestara Python SDK

Server-side Python SDK for Vestara crash reporting and remote logging.

**Requires Python 3.8+** — zero external runtime dependencies.

## Installation

```bash
pip install vestara
```

## Quick Start

```python
import vestara

vestara.init(
    token="YOUR_SDK_TOKEN",
    environment="production",
    app_version="1.0.0",
    target_category="python_worker",
    service_name="Python Worker",
    app_identifier="python-worker",
)

vestara.log("info", "Server started", {"port": 3000})
```

Default endpoint: `https://api.vestara.dev`. No `api_url` needed for normal Vestara SaaS usage.

## Runtime target metadata

You can provide metadata to identify this application in the dashboard:
- `target_category`: The kind of target (e.g., `python_worker`).
- `service_name`: Human-readable name (e.g., `Python Worker`).
- `app_identifier`: Technical identifier (e.g., `python-worker`).

## API

### `vestara.init(options)`

Initializes the SDK. Must be called before any other API.

```python
vestara.init(
    token="YOUR_SDK_TOKEN",
    environment="production",  # production | staging | development
    app_version="1.0.0",
    target_category="python_worker",
    service_name="Python Worker",
    app_identifier="python-worker",
    before_send=None,  # optional callback
)
```

### `before_send` hook

The `before_send` option lets you inspect, modify, or drop events before they are queued:

```python
def redact_sensitive(event):
    # Redact sensitive fields
    if "password" in event.get("payload", {}).get("data", {}):
        event = dict(event)
        event["payload"] = dict(event["payload"])
        event["payload"]["data"] = dict(event["payload"]["data"])
        event["payload"]["data"]["password"] = "[REDACTED]"
        return event
    
    # Drop noisy health checks
    if event.get("payload", {}).get("message") == "health-check":
        return None
    
    return event

vestara.init(
    token="YOUR_SDK_TOKEN",
    before_send=redact_sensitive,
)
```

Behavior:
- Return a modified event dict to send the modified version
- Return `None` to drop the event
- If the hook raises an exception, the original event is sent (fail-open)

Note: The Vestara backend also applies server-side redaction as a safety layer.

Optional `api_url` for local development, staging, or self-hosted:

```python
vestara.init(
    token="YOUR_SDK_TOKEN",
    api_url="http://localhost:3000",
    environment="development",
)
```

### `vestara.log(level, message, data?)`

Sends a log event.

```python
vestara.log("info", "Request processed", {"request_id": "123"})
vestara.log("warn", "Slow query detected", {"duration": 2000})
vestara.log("error", "Database connection failed", {"host": "db.example.com"})
```

Supported levels: `debug`, `info`, `warn`, `error`, `fatal`.

### `vestara.capture_exception(error, context?)`

Captures a Python exception.

```python
try:
    result = process_data()
except Exception as e:
    vestara.capture_exception(e, {"operation": "process_data"})
```

### `vestara.set_user(context)`

Associates a user with future events.

```python
vestara.set_user({"id": "user-123", "email": "user@example.com"})
```

## What is Automatically Captured

- **Uncaught exceptions**: `sys.excepthook` captures unhandled exceptions. The original hook is called after capture.
- **Thread exceptions**: `threading.excepthook` captures uncaught exceptions in threads. The original hook is called after capture.
- **Graceful shutdown**: Remaining events are flushed on process exit via `atexit`.
- **Periodic flush**: Events are sent every 10 seconds in a background daemon thread.

## What is NOT Supported in V1

- **Async/await exceptions**: Only synchronous thread exceptions are captured automatically.
- **Django/FastAPI/Flask integration**: Not built-in. Wrap your exception handlers or call `vestara.capture_exception()` manually.
- **Structured logging frameworks**: Not auto-instrumented.
- **Distributed tracing / APM**: Not implemented.
- **Guaranteed persistence**: Queue is in-memory only. SIGKILL or sudden process termination will lose queued events.
- **File-backed queue**: Not implemented.

## Offline Queue

Events are queued in memory (not persisted to disk).

- Max 500 events
- Logs dropped (not crashes) when queue is full
- Crash events evict the oldest log when queue is full
- Events are sent in batches of up to 50 every 10 seconds
- Crash events are sent immediately
- Remaining events are flushed on `atexit` (best-effort, may not complete on SIGKILL)

## Device Settings

The SDK polls `/v1/sdk/device-settings` every 60 seconds. If `logging_enabled` is `false`, log events are suppressed. Crash events are always sent regardless of this setting.

## SDK Token

Find your SDK token in the Vestara dashboard under **Settings → SDK & Token**.

> The SDK token is write-only — it can only ingest events. It cannot read your data.

## License

This SDK is licensed under the Apache License 2.0.

Copyright 2026 Ahsan Iqbal.

Vestara, the Vestara name, logos, domain, and related branding are not granted under this license.
