DispelEvilBot/docs/events.md

83 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# События аналитики (ClickHouse)
Бот пишет все значимые действия в ClickHouse — единую широкую таблицу
`analytics.events`. Дашборд (Superset) и ETL — отдельный финальный этап; здесь
описан **контракт** событий: какие бывают `event_type` и что лежит в `payload`.
> Источник правды в коде — `common/analytics/events.py` (`EventType`).
> Расхождение со списком ниже ловит `tests/test_analytics.py`.
> Добавляешь событие — добавь строку в таблицу.
## Поля события
| Поле | Тип | Описание |
| --- | --- | --- |
| **event_time** | `DateTime('UTC')` | Момент события (UTC, без таймзоны) |
| **event_type** | `LowCardinality(String)` | Тип события (см. каталог ниже) |
| **user_id** | `Int64` | Telegram-ID пользователя (0 — системное событие) |
| **username** | `String` | `@username` на момент события (может быть пустым) |
| **chat_id** | `Int64` | ID чата (обычно основной чат клана) |
| **payload** | `String` | Дополнительные данные события в виде JSON |
| **bot_version** | `String` | Версия бота из `common/version.py` |
| **prod** | `UInt8` | 1 — прод-контур, 0 — тестовый |
## Каталог событий
| Тип события | Когда пишется | `payload` |
| --- | --- | --- |
| `message` | Любое сообщение в основном чате | `message_id`, `chat_type`, `content_type`, `text_len`, `is_command` |
| `command` | Использование команды (`/инфо`, `/очищение`, …) | `command`, `args_count` |
| `purification` | Ежедневное очищение (`/очищение`) | `success`, `exp_add`, `money_add` |
| `exp_accrual` | Начисление опыта за очищение | `amount`, `streak` |
| `level_up` | Повышение уровня по итогам очищения | `level_from`, `level_to` |
| `money_accrual` | Начисление валюты (монетка за активность, награда за очищение) | `amount`, `reason`, `action_id` |
| `money_spend` | Трата валюты (покупка, обнуление баланса при удалении) | `amount`, `reason`, `product_id` |
| `eggs` | Получение яичек (`/яички`) | `amount` |
| `purchase_title` | Покупка звания | `title_id`, `price`, `success` |
| `purchase_donat` | Покупка доната | `donat_id`, `price`, `success` |
| `join` | Вход участника в основной чат | `chat_title` |
| `leave` | Выход участника из основного чата | `chat_title` |
| `nick_set` | Смена ника (`/ник`) | `nick` |
| `subscribe` | Подписка на рассылки (`/подписка`) | — |
| `unsubscribe` | Отписка от рассылок (`/отписка`) | — |
| `access_denied` | Отказ в доступе (не участник чата и не админ) | `reason` |
| `bot_start` | Старт бота | `app_env` |
| `bot_stop` | Остановка бота | `app_env`, `uptime_seconds` |
| `bot_alive` | Ежечасный пинг «бот живой» | `app_env`, `uptime_seconds` |
| `error` | Необработанная ошибка при обработке апдейта | `error_type`, `error`, `update_type` |
## Поведение при недоступности ClickHouse
Аналитика — **некритичная** подсистема: её сбой не должен влиять на бота.
- события копятся в буфере и отправляются батчами (по размеру и по таймеру);
- если ClickHouse недоступен, буфер не растёт бесконечно: при переполнении самые
старые записи отбрасываются со счётчиком в логе;
- если записать батч не удалось, события выводятся в stdout (`WARNING`, первые
несколько строк + общее количество) и отбрасываются — данные не пропадают молча;
- при остановке бота выполняется финальный сброс буфера;
- выключение целиком — `CLICKHOUSE_ENABLED=false` (тогда `record()` — no-op).
## Примеры запросов
```sql
-- активность по дням
SELECT toDate(event_time) AS day, count() FROM analytics.events GROUP BY day ORDER BY day;
-- топ команд за неделю
SELECT JSONExtractString(payload, 'command') AS cmd, count() AS uses
FROM analytics.events
WHERE event_type = 'command' AND event_time >= now() - INTERVAL 7 DAY
GROUP BY cmd ORDER BY uses DESC;
-- покупки за месяц
SELECT event_type, count(), sum(JSONExtractInt(payload, 'price'))
FROM analytics.events
WHERE event_type IN ('purchase_title', 'purchase_donat') AND event_time >= now() - INTERVAL 30 DAY
GROUP BY event_type;
-- ошибки
SELECT event_time, JSONExtractString(payload, 'error_type'), JSONExtractString(payload, 'error')
FROM analytics.events WHERE event_type = 'error' ORDER BY event_time DESC LIMIT 50;
```