# 📊 fast-telemetry

**Production-ready Prometheus integration for FastAPI, FastStream, and Python Workers.**

`fast-telemetry` — это "клей", который объединяет метрики вашего микросервиса в единый стандарт. Библиотека навязывает
правильные практики (единые метки `env`, `version`, `service`) и предоставляет удобные абстракции для HTTP-сервисов,
обработчиков очередей и периодических задач.

### 🌟 Особенности

* **Единый стандарт:** Автоматически добавляет метки `service`, `env`, `version` ко всем метрикам.
* **FastAPI:** Автоконфигурация через `Instrumentator`, исключение служебных ручек (`/metrics` и других переданных).
* **FastStream:** Поддержка RabbitMQ, Kafka, Redis, NATS "из коробки" (автоопределение драйвера).
* **Workers & Cron:**
    * Поддержка Long-running процессов (daemon thread server).
    * Поддержка Batch-jobs (Pushgateway) через **универсальный контекстный менеджер** (sync/async).
* **Декораторы:** Удобные `@measure_task` и `@track_exception`, которые сами понимают, синхронная функция или
  асинхронная.
* **Безопасность типов:** Полная типизация (mypy strict).

---

### 📦 Установка

```bash
pip install fast-telemetry
```

---

### 🚀 Quick Start

#### 1. Core Concepts

В основе всего лежит класс `PrometheusMetrics` (или его наследники). Вы инициализируете его один раз при старте
приложения.

```python
from fast_telemetry import PrometheusMetrics

metrics = PrometheusMetrics(
    service_name="payment_service",
    version="1.0.4",
    env="production"
)

# Использование в коде
metrics.inc_error("validation_error")

with metrics.timer("db_query", long_task=False):
    # ... logic ...
    pass
```

#### 2. FastAPI Integration

Автоматически добавляет эндпоинт `/metrics` и собирает RED-метрики (Requests, Errors, Duration).

```python
from fastapi import FastAPI
from fast_telemetry import PrometheusMetrics, setup_fastapi_metrics

app = FastAPI()
metrics = PrometheusMetrics(service_name="api_core", env="dev", version="1.2.3")

# Настройка (исключает /docs, /openapi.json + readiness)
setup_fastapi_metrics(app, metrics, excluded_routes=["/readiness"])


@app.get("/")
@metrics.measure_task("root_handler", long_task=False)
async def root():
    return {"status": "ok"}
```

#### 3. FastStream Integration

Поддерживает автоматическое определение брокера (Rabbit/Kafka/Redis/NATS) и инъекцию middleware.

```python
from faststream.asgi import AsgiFastStream, make_ping_asgi
from faststream.rabbit import RabbitBroker
from fast_telemetry import PrometheusMetrics, setup_faststream_metrics

broker = RabbitBroker("amqp://guest:guest@localhost:5672/")
app = AsgiFastStream(
    broker,
    asgi_routes=[
        ("/health", make_ping_asgi(broker))
    ],
    lifespan=None,
    asyncapi_path="/docs",
)

metrics = PrometheusMetrics(service_name="worker_core", env="dev")
setup_faststream_metrics(app, metrics)
```

#### 4. Workers & Cron Jobs

Для скриптов без веб-сервера. Поддерживает два режима:

1. **Daemon Server** (для бесконечных циклов).
2. **Push Gateway** (для скриптов, запускаемых по расписанию).

```python
import asyncio
from fast_telemetry import WorkerMetrics

metrics = WorkerMetrics(service_name="nightly_job", env="prod")


# --- Вариант А: Long-running worker ---
def run_worker():
    # Запускает HTTP сервер в фоновом потоке
    metrics.start_server(port=8000)
    while True:
        process_data()


# --- Вариант Б: Batch Job (Cron) ---
# Универсальный трекер (работает и с with, и с async with)
async def run_batch_job():
    # Автоматически отправит метрики в Pushgateway при выходе из блока
    # Группирует по instance_id, чтобы воркеры не перезатирали друг друга
    async with metrics.track_job(gateway_url="http://pushgateway:9091", timeout=5.0):
        await do_heavy_calculation()
        metrics.inc_error("calc_error")


if __name__ == "__main__":
    asyncio.run(run_batch_job())
```

---

### 🛠 Декораторы

Библиотека предоставляет "умные" декораторы, которые работают с sync и async функциями прозрачно.

**`@track_exception()`**
Считает количество исключений. Использует имя класса исключения как метку.

```python
@metrics.track_exception
async def dangerous_operation():
    raise ValueError("Oops")
    # Увеличит счетчик fasttelemetry_business_errors_total{error_type="ValueError", ...}
```

**`@measure_task("task_name")`**
Замеряет время выполнения функции (Histogram).

```python
@metrics.measure_task("image_processing")
def process_image(img):
    time.sleep(1)
```

---

### 📊 Grafana & Prometheus

Библиотека экспортирует следующие базовые метрики:

1. **`fasttelemetry_app_info`** (Gauge) — всегда `1`. Содержит метки `version`, `env`, `service`. Используйте для
   аннотаций деплоев на графиках.
2. **`fasttelemetry_business_errors_total`** (Counter) — счетчик ошибок бизнес-логики.
3. **`fasttelemetry_task_processing_seconds`** (Histogram) — время выполнения внутренних задач.
4. **`http_requests_...`** — [fastapi.json](grafana/fastapi.json) (если используется FastAPI).
5. **`faststream_...`** — [faststream.json](grafana/faststream.json) (если используется FastStream).

---

## 📈 Base Metrics & Grafana Dashboard

Библиотека предоставляет "Ready-to-use" набор метрик

### Metric Schema

| Metric Name                                  | Type      | Labels                      | Description                                                                      |
|----------------------------------------------|-----------|-----------------------------|----------------------------------------------------------------------------------|
| `fasttelemetry_app_info`                     | Gauge     | `env`, `service`, `version` | Информация о запущенном инстансе. Всегда `1`.                                    |
| `fasttelemetry_business_errors_total`        | Counter   | `error_type`                | Количество ошибок бизнес-логики (пойманных через `track_exception` или вручную). |
| `fasttelemetry_task_processing_seconds`      | Histogram | `task_type`                 | Время выполнения задач (обернутых в `@measure_task` или `timer`).                |
| `fasttelemetry_long_task_processing_seconds` | Histogram | `task_type`                 | Время выполнения долгих задач (обернутых в `@measure_task` или `timer`).         |

### ⚙️ Configuration

Вы можете передать параметры явно в `__init__` или использовать переменные окружения:

| Environment Variable | Description                | Default   |
|----------------------|----------------------------|-----------|
| `APP_ENV`            | Окружение (prod/dev/stage) | `dev`     |
| `APP_VERSION`        | Версия приложения          | `unknown` |

### 🖥️ Grafana Dashboard JSON

Дашборды можно импортировать из [папки](grafana)
