# ddog-monitoring

A lightweight, framework-agnostic Python library for sending metrics to **Datadog**, **SumoLogic**, or a local **Console** output. Designed for use in Django, FastAPI, or any Python app — including **AWS Lambda / Zappa** deployments.

## Installation

```bash
pip install ddog-monitoring
```

## Quick Start

```python
from monitoring.client import MonitoringFacade
from monitoring.config import MonitoringConfig

# Configure once at startup
MonitoringFacade.configure(MonitoringConfig(
    provider="datadog",
    datadog_api_key="your-api-key",
    datadog_app_key="your-app-key",
    datadog_hostname="your-host",
))

# Use anywhere
provider = MonitoringFacade.get_instance()
provider.send("api.request", value=1, metric_type="count", tags=["env:prod"])
```

## Providers

| Provider | Config keys required |
|---|---|
| `console` | _(none)_ — prints metrics to stdout |
| `datadog` | `datadog_api_key`, `datadog_app_key`, `datadog_hostname` |
| `sumologic` | `sumologic_url` |

## Django + AWS Lambda / Zappa Usage

For Django apps, call `configure()` once in `AppConfig.ready()`. Pass a **callable factory** (lambda) instead of a static config so that [django-constance](https://github.com/jazzband/django-constance) value changes are picked up automatically on warm Lambda starts — without a redeploy.

```python
# main_app/apps.py
from django.apps import AppConfig

class MainAppConfig(AppConfig):
    name = "main_app"

    def ready(self):
        from constance import config
        from monitoring.client import MonitoringFacade
        from monitoring.config import MonitoringConfig

        MonitoringFacade.configure(lambda: MonitoringConfig(
            provider=config.MONITORING_PROVIDER,
            datadog_api_key=config.DATADOG_API_KEY,
            datadog_app_key=config.DATADOG_APP_KEY,
            datadog_hostname=config.DATADOG_HOSTNAME,
            sumologic_url=config.SUMOLOGIC_URL,
        ))
```

Create a thin accessor module so views, management commands, and middleware never import `MonitoringFacade` directly:

```python
# main_app/monitor.py
from monitoring.client import MonitoringFacade

def get_monitor():
    return MonitoringFacade.get_instance()
```

```python
# views.py
from .monitor import get_monitor

def my_view(request):
    get_monitor().send("api.hit", value=1, metric_type="count", tags=["endpoint:my_view"])
```

### How warm-start caching works

On every `get_instance()` call the library fetches the current config (via your factory) and compares it using Pydantic field equality. The provider is only recreated when config actually changes — otherwise the cached instance is reused immediately, keeping warm starts fast.

## Decorators

Track function execution time and errors automatically:

```python
from monitoring.decorators import track_metric

@track_metric("my_function")
def my_function():
    ...
```

## License

MIT
