Metadata-Version: 2.1
Name: logforma-sdk
Version: 0.1
Summary: Logforma SDK package for observability event logging
Home-page: https://github.com/logforma/logforma
Author: Logforma
Author-email: team@logforma.ai
License: UNKNOWN
Platform: UNKNOWN
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: redis<6.0,>=5.0

# Logforma SDK (Python) — Простая Пошаговая Интеграция

- Pip package: `logforma-sdk`
- Python module: `logforma`

## 1. Быстрый Старт (минимум)

### Шаг 1. Инициализация (один раз при старте сервиса)
```python
from logforma import logforma_init

logforma_init(
    service_name="candidate_eval_service",
    service_instance_id="candidate_eval_service-1",
    queue_name="candidate_eval_service_inbound",
    log_db_queries=True,
    mask_fields={"token", "password", "email"},
    trace_level="standard",
)
```

### Шаг 2. Декорируйте бизнес-функции
```python
from logforma import logforma_trace

@logforma_trace()
async def validate_candidate(payload: dict) -> dict:
    return {"valid": True}
```

### Шаг 3. Для consume-сервиса используйте `logforma_consume(...)`
```python
import asyncio
from logforma import logforma_consume, logforma_trace

@logforma_trace()
async def handle_event(event: dict) -> bool:
    return True

def process_queue_event(event: dict) -> bool:
    return asyncio.run(logforma_consume(event, handle_event, seq_offset=2_000_000))
```

Что делает `logforma_consume(...)`:
- ставит consume-контекст (`transaction_id`, `seq_no`, `path`, `flow`);
- связывает вложенные вызовы SDK в одну трассу;
- убирает необходимость вручную писать `with logforma_with_consume_event(...)`.

## 2. Какие Функции Автоматические, А Какие Нет

## 2.1 Автоматические (рекомендуемый путь)

Этого достаточно для большинства сервисов:
- `logforma_init(...)`
- `@logforma_trace()`
- `logforma_consume(...)` для queue-consumer

Что SDK заполнит автоматически:
- `command.function.name` (из `<module>.<qualname>`);
- `call_id`, `seq_no`, тайминги;
- `service.name`, `service.instance.id`, `queue.name` (из init/config/context);
- `trace_id`, `span_id`, `parent_span_id` (если trace включен);
- `db_queries_preview` (если включено DB-логирование и DB-клиент инструментирован).

## 2.2 Неавтоматические (используются вручную по необходимости)

Используйте только если внутри функции есть отдельный шаг маршрута:
- `logforma_log_publish(...)` — шаг отправки в очередь;
- `logforma_log_db(...)` — ручной шаг SQL (fallback, если нет instrumentation);
- `logforma_log_http(...)` — шаг внешнего HTTP;
- `logforma_log_service_step(...)` — ручной сервисный шаг;
- `logforma_with_context(...)` — ручная установка runtime-контекста;
- `logforma_with_consume_event(...)` — низкоуровневый consume-контекст (edge-cases);
- `logforma_config_module(...)` — локальный override конфигурации;
- `logforma_current_context()` — чтение текущего контекста;
- `logforma_instrument(...)`, `logforma_instrument_db_cursor(...)`, `logforma_instrument_psycopg2_connection(...)`, `logforma_record_db_query(...)` — инструментация БД;
- legacy-совместимость: `logforma_log_call(...)`, `logforma_log_event(...)`.

Пример ручных внутренних шагов:
```python
from logforma import logforma_log_publish, logforma_log_db, logforma_log_http, logforma_trace

@logforma_trace()
async def process_candidate(payload: dict) -> dict:
    candidate_id = payload["candidate_id"]
    await logforma_log_publish("scoring_worker_service_inbound")
    await logforma_log_db(
        "SELECT id, score FROM candidates WHERE id = %s",
        params_preview=[candidate_id],
        db_alias="CandidateDB",
    )
    await logforma_log_http("POST", "https://risk-service.local/check", status_code=200)
    return {"ok": True}
```

Если отдельного шага маршрута внутри функции нет, достаточно одного `@logforma_trace()`.

## 3. Правила Интеграции (важно)

- `logforma_init(...)` вызывайте ровно один раз в entrypoint сервиса.
- Во внутренних модулях повторно `logforma_init(...)` не вызывайте.
- Сигнатуры бизнес-функций ради SDK не меняйте.
- Ручной `_logforma_context` и ручной `ctx["db_queries"]` не используйте.
- Для локальных override применяйте `logforma_config_module(...)`.

## 4. HTTP И Queue Сценарии

### HTTP entrypoint
- `logforma_consume(...)` не нужен.
- Обычно достаточно `@logforma_trace()`.
- Helper-функции (`logforma_log_publish/logforma_log_db/logforma_log_http`) добавляйте только если есть реальный отдельный шаг.

### Queue-consumer entrypoint
- Используйте `logforma_consume(...)` + `@logforma_trace()`.
- Низкоуровневый `logforma_with_consume_event(...)` оставлен для edge-cases.

## 5. Flow И Transaction ID

### `flow`
- Для consume-сессии приоритет: `command.action` -> `flow.name` -> `logforma_init(flow_name=...)`.
- В helper-вызовах можно передать `flow_name=...`, если нужно переопределение только для конкретного события.

### `transaction.id`
- Рекомендуется передавать внешний `transaction.id` для сквозной корреляции.
- Если не передан, SDK сгенерирует fallback `tx-<uuid>`.

## 6. DB Логирование (пошагово)

### Самое важное: как включить DB-логирование без ручных SQL-текстов

Чтобы SQL попадали в логи автоматически (без `logforma_log_db("SELECT ...")` вручную), нужны только 2 действия:

1. Включить флаг:
```python
logforma_init(..., log_db_queries=True)
```
2. Инструментировать DB-подключение/курсор через SDK:
```python
from logforma import logforma_instrument
conn = logforma_instrument(conn, db_alias="MainDB")
```

После этого SDK сам перехватывает `execute(...)`/`executemany(...)` и пишет SQL в `db_queries_preview`.

### Шаг 1. Включите логирование
- Через `logforma_init(log_db_queries=True)` или `logforma_config_module(log_db_queries=True)`.
- Приоритет: параметр декоратора -> `logforma_config_module(...)` -> `logforma_init(...)`.

### Шаг 2. Инструментируйте DB-клиент
Instrumentation = обёртка connection/cursor через SDK, чтобы перехватывать `execute(...)` и писать SQL в runtime-контекст.

Пример для `psycopg2`:
```python
import psycopg2
from psycopg2.extras import RealDictCursor
from logforma import logforma_instrument

def connect():
    conn = psycopg2.connect(dsn, cursor_factory=RealDictCursor)
    return logforma_instrument(conn, db_alias="LogformaDB")
```

Поведение `logforma_instrument(...)`:
- если коннектор распознан, применяется инструментатор;
- если не распознан, SDK вернёт исходный объект (passthrough, без падения).

### Шаг 3. Проверяйте `db_queries_preview`
В деталях function step в UI появится список:
- `statement`
- `params_preview`
- `db_alias`

Пример:
```json
[
  {
    "statement": "SELECT id, score FROM candidates WHERE id = %s",
    "params_preview": ["cand-1001"],
    "db_alias": "LogformaDB"
  }
]
```

Если instrumentation нет, используйте fallback:
```python
await logforma_log_db("SELECT ...", params_preview=[candidate_id], db_alias="CandidateDB")
```

## 7. Trace Level

`trace_level` задается в `logforma_init(...)`:
- `off` — trace-блок не добавляется;
- `basic`, `standard`, `verbose` — trace включен.

## 8. Legacy Совместимость

- `logforma_log_call(...)` и `logforma_log_event(...)` поддерживаются.
- Для нового кода целевой стиль: `logforma_init(...)` + `@logforma_trace()` + короткие helper-вызовы по необходимости.

## 9. Пилот На Тестовых Сервисах

- Контур `test-*` описан в `docs/project/12-sdk-pilot.md`.
- Быстрый прогон:
  - `python scripts/trigger_sdk_pilot.py`
- Скрипт запускает сценарии `happy/error/warning/missing tx/unsupported connector` и печатает `transaction_id`, `flow nodes/edges`.


