Metadata-Version: 2.5
Name: ct_obs_app
Version: 0.1.1
Summary: Python client for the obs-app.ctsoftware.co.uk (obs_app) ingestion API - logs, metrics and traces.
Project-URL: Homepage, https://github.com/cturner91/obs-app-sdk
Project-URL: Repository, https://github.com/cturner91/obs-app-sdk
Author-email: Conor Turner <conor_turner@hotmail.com>
License: MIT
License-File: LICENSE
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Logging
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Requires-Dist: requests>=2.25
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# obs-app-sdk

Python client for the [obs-app.ctsoftware.co.uk](https://obs-app.ctsoftware.co.uk) ingestion API - send logs,
metrics and traces from your application.

## Install

```bash
pip install ct_obs_app
```

(the PyPI project is named `ct_obs_app`; the importable module is `obs_app_sdk` - see Quickstart below)

## Get an API key

Log in at the obs_app dashboard and copy your API key from the profile page (rotate it there
too, if needed). The SDK authenticates every request with it.

## Quickstart

```python
from obs_app_sdk import Client, CaptureTrace

client = Client(api_key="your-api-key")

# Logging
client.log("Something happened", level=4)  # 1=Critical .. 5=Debug, default 4=Info
client.log_batch([{"message": "a"}, {"message": "b"}])

# Metrics
client.add_metric(value=1.0, metric="request_duration_ms", auto_create=True)
client.add_metrics([
    {"metric": "request_duration_ms", "value": 12.3},
    {"metric": "queue_depth", "value": 4},
], auto_create=True)

# Traces - nested context managers build one tree, sent as a single request when the
# outermost one exits
with CaptureTrace(client, "handle_request"):
    with CaptureTrace(client, "query_db"):
        ...
    with CaptureTrace(client, "render_response"):
        ...

# Or submit logs/metrics/traces together in one request (validated all-or-nothing)
client.ingest(
    logs={"logs": [{"message": "started"}]},
    metrics={"metrics": [{"metric": "request_duration_ms", "value": 12.3}]},
    traces=[{"start": "...", "end": "...", "text": "handled"}],
)
```

## Stdlib logging integration

```python
import logging
from obs_app_sdk import Client, ObsAppLogHandler

client = Client(api_key="your-api-key")
logging.getLogger().addHandler(ObsAppLogHandler(client))
```

Each stdlib log record becomes one `POST /api/log/` call. For high-volume logging, call
`client.log_batch(...)` directly instead of relying on the handler.

## Error handling

All methods raise on non-2xx responses:

- `ObsAppApiKeyError` - missing/invalid API key (HTTP 401)
- `ObsAppValidationError` - invalid request data (HTTP 400); `.errors` holds the server's
  per-field error dict when there is one, else `None`
- `ObsAppRateLimitedError` - HTTP 429. The API blocks the offending IP for **1 hour** once its
  rolling rate-limit window trips - do not retry in a loop on this error, it won't help
- `ObsAppError` - base class; also raised for network failures and unexpected status codes

## Notes

- This client is synchronous and makes one HTTP request per call - there is no background
  buffering/auto-flush thread. Use the batch methods (`log_batch`, `add_metrics`, `ingest`)
  to reduce request count for high-volume callers.
- `add_metrics` (batch) only supports metric names, not `metric_id` - use `add_metric`
  (singular) for id-based lookups.
