Metadata-Version: 2.4
Name: event-monitoring
Version: 0.1.0
Summary: Non-blocking business-event emitter that publishes to a Redis Stream for a monitoring dashboard
Project-URL: Homepage, https://github.com/oaboumrad/monitor
Project-URL: Repository, https://github.com/oaboumrad/monitor
Author-email: Omar Aboumrad <omar.aboumrad@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: django,events,monitoring,observability,redis,redis-streams
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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.10
Requires-Dist: redis>=4.0
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Description-Content-Type: text/markdown

# event-monitoring

A tiny, non-blocking emitter that publishes **business/contextual events** from any
Python app to a Redis Stream for a monitoring dashboard to consume.

- Sync (`emit`) and async (`aemit`) APIs.
- Transaction-safe under Django (`transaction.on_commit`); works fine without Django.
- **Opt-in** — a no-op unless `MONITORING_ENABLED` is truthy, so it's inert when
  installed into an app nobody has wired up to a dashboard.
- Only hard dependency is `redis`.

## Install

```bash
pip install event-monitoring
# or
uv add event-monitoring
```

Pre-release / unpublished, straight from Git:

```bash
pip install "git+https://github.com/<you>/event-monitoring.git@v0.1.0"
```

For local cross-repo dev, as a uv path source:

```toml
[tool.uv.sources]
event-monitoring = { path = "../event-monitoring", editable = true }
```

## Usage

```python
import event_monitoring

# Sync (Django views, scripts, workers)
event_monitoring.emit(
    event="offer_approved",
    entity_type="offer", entity_id=offer.id,
    actor_id=request.user.id,
    url=request.build_absolute_uri(offer.get_absolute_url()),
    payload={"amount": offer.amount},
)

# Async (asyncio apps — e.g. a Discord bot). Offloads the blocking publish.
await event_monitoring.aemit("music_played", entity_type="guild", entity_id=guild_id,
                             actor_id=user.id, payload={"song": title})
```

## Configuration (env vars)

| Var | Default | Meaning |
|-----|---------|---------|
| `MONITORING_ENABLED` | `0` (off) | Set `1`/`true`/`yes` to actually publish. |
| `MONITORING_APP` | `unknown` | Logical source-app name (`rms`, `dryorm`, …). |
| `MONITORING_REDIS_URL` | `redis://events-redis:6379/0` | Redis the dashboard consumes from. Keep separate from the app's own Redis. |
| `MONITORING_STREAM` | `events` | Stream name. |

Publish failures are swallowed (warned once) — monitoring never breaks the host app.

## Event shape

```json
{"app":"rms","event":"offer_approved","entity_type":"offer","entity_id":"123",
 "actor_id":"55","url":"https://rms.example/offers/123",
 "timestamp":"<naive-UTC-iso>","payload":{}}
```
