Observability
Logs
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
log = logging.getLogger("mybot")
Что логировать
- event.id, event.type, delivery_id
- user_id, channel_id (только IDs, не sensitive)
- latency: ms на обработку
- HTTP status исходящих вызовов
- Exception trace
- Raw webhook body (может содержать
contentсообщений с sensitive) - Bot token / webhook secret (даже маскированные)
- Email / IP пользователей
- Полный
contentсообщений
Структурированные логи
JSON в production — для лёгкой агрегации в вашей системе сбора логов:
import structlog
log = structlog.get_logger()
log.info(
"handler_completed",
event_id=event.id,
event_type=event.type,
user_id=event.author_user_id,
latency_ms=int((time.time() - start) * 1000),
)
Метрики
Счётчики и гистограммы для стандартного /metrics endpoint:
# Counter / Histogram из вашей библиотеки сбора метрик
from metrics import Counter, Histogram
events_total = Counter(
"mybot_events_total",
"Webhook events received",
["type"],
)
event_duration = Histogram(
"mybot_event_duration_seconds",
"Webhook handler duration",
["type"],
)
@bot.on("message.created")
async def handler(event):
events_total.labels(type=event.type).inc()
with event_duration.labels(type=event.type).time():
await do_stuff(event)
Подключите экспортёр метрик вашего ASGI-приложения, чтобы отдавать
стандартный /metrics endpoint:
# Подключите ваш экспортёр метрик к ASGI-приложению бота
# и выставьте endpoint /metrics
setup_metrics(bot.app, endpoint="/metrics")
→ GET /metrics отдаёт метрики в стандартном текстовом формате.
Платформенные метрики
Отдельных метрик по ботам (вида reasonspace_bot_*) платформа
пока не экспозит. На стороне платформы есть только стандартный
/metrics endpoint с обычными HTTP-метриками
(latency, статус-коды, throughput) — без разбивки по конкретному боту, scope
или webhook-доставкам. Не стройте дашборды и алерты на сериях
reasonspace_bot_api_requests_total, ..._webhook_delivery_total,
..._oauth_token_issued_total и подобных — их в коде нет.
Что реально доступно для observability на стороне платформы — это лог-события доставки webhook'ов (структурированные записи в логах API). По ним команда платформы отслеживает здоровье доставки:
| Лог-событие | Когда |
|---|---|
bot_webhook_queue_full_drop | очередь доставки переполнена, событие отброшено |
bot_webhook_url_unsafe | URL webhook'а не прошёл SSRF-проверку, доставка пропущена |
bot_webhook_delivery_network_fail | сетевая ошибка при попытке доставки |
bot_webhook_gone | endpoint вернул 410 Gone (засчитывается как неуспешная доставка; авто-отвязка по 410 — в roadmap, пока не реализована) |
bot_webhook_auto_suspended | 5 неуспешных доставок подряд → suspend на 24 часа |
Собственные метрики на success rate доставки и автоматические уведомления владельцу (например, при success rate < 90%) — в roadmap, пока не реализованы. Для своего бота собирайте метрики сами (см. раздел Метрики выше).
Alerts
Базовый набор для production-бота:
| Alert | Threshold | Action |
|---|---|---|
| Bot API success rate | < 90% за 5 минут | Page on-call |
| Event handler latency | p99 > 5s | Slow, проверить queue |
| Webhook 4xx rate | > 5% | Возможно неверная подпись |
| Memory usage | > 80% | Memleak в handler? |
| Voice sessions stuck | > 30 минут | Зомби-процессы |
Tracing
OpenTelemetry для distributed tracing — если у вас бот → internal API → DB:
from opentelemetry import trace
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
HTTPXClientInstrumentor().instrument() # auto-trace всех HTTP requests
tracer = trace.get_tracer("mybot")
@bot.on("message.created")
async def handler(event):
with tracer.start_as_current_span("handle_message") as span:
span.set_attribute("event.id", str(event.id))
await do_stuff(event)
Dashboard-шаблоны
Grafana JSON-templates для bot-side мониторинга — планируется. Сейчас рекомендуется собирать свои.