Перейти к основному содержимому

Наблюдаемость бэкенда — метрики, логи и аудит

Разработчику Инженеру Архитектору

Наблюдаемость — способность понять внутреннее состояние системы по внешним сигналам. Для бэкенда критично не смешивать три разных потока данных.

Связанные материалы
Определения QPS, TPS, перцентилей, распределённой трассировки и примеры Prometheus — в статье Метрики производительности веб-приложений.

Развёрнутая инфраструктурная сторона: мониторинг и логирование. Поиск по каталогу и тексту в продукте: полнотекстовый поиск.


Три слоя

СлойВопросПримерыНе путать с
Метрики«Сколько и как быстро?»RPS, latency p99, error rate, CPUТекстом описывать каждый запрос
Логи«Что случилось в коде?»stack trace, timeout к БД, order_id=…Персональные данные без маскировки
Аудит«Кто изменил что?»user_id сменил роль, экспорт CSVDebug-логи уровня TRACE

Метрики (Prometheus-стиль)

Типы:

ТипСмыслПример
CounterТолько растётhttp_requests_total{status="500"}
GaugeТекущее значениеdb_connections_active
HistogramРаспределениедлительность запроса в корзинах
SummaryКвантили (реже)p95 latency на клиенте

Правила для разработчика:

  • метки (labels) — низкая кардинальность (route, method), не user_id;
  • считайте золотые сигналы: latency, traffic, errors, saturation;
  • алерт на симптом (рост 5xx), не на «CPU 80%» без контекста.

Запросы в духе rate(http_errors[5m]) — зона SRE; разработчику достаточно экспортировать метрики и знать, где дашборд.


Логи

Структурированные логи (JSON) упрощают поиск:

{
"level": "error",
"msg": "payment failed",
"request_id": "7f3a…",
"order_id": "ord_42",
"duration_ms": 1203
}

Уровни:

  • ERROR — требует внимания, влияет на пользователя;
  • WARN — деградация, retry;
  • INFO — бизнес-значимые вехи (старт, останов);
  • DEBUG — только на staging или кратковременно в проде.

Корреляция: один request_id / trace_id через API Gateway → сервисы → БД. Без этого микросервисы неотлаживаемы.

Middleware (идея на Python/FastAPI или Flask):

import uuid
from flask import Flask, g, request

app = Flask(__name__)

@app.before_request
def assign_request_id():
g.request_id = request.headers.get("X-Request-Id") or str(uuid.uuid4())

@app.after_request
def echo_request_id(response):
response.headers["X-Request-Id"] = g.request_id
return response

В логах всегда передавайте тот же request_id в поле JSON — тогда строки из разных сервисов склеиваются в одну цепочку.

Не логируйте: пароли, полные PAN карт, токены, тела запросов с PII по умолчанию.


Аудит

Аудит — юридически и организационно значимый журнал:

  • неизменяемость или WORM-хранение;
  • долгий retention;
  • поля: кто, когда, откуда (IP), что изменил (до/после).

Отдельная таблица или поток Kafka → холодное хранилище. Не смешивайте с console.log при отладке скидок.


Трассировка (четвёртый столп)

Distributed tracing (OpenTelemetry) связывает spans между сервисами. Дополняет логи: видно, на каком hop потерялись 800 ms.

Минимум для старта: propagate заголовок trace context из входящего HTTP в исходящие вызовы.


Health check и smoke

ПроверкаУровеньНазначение
LivenessПроцесс живПерезапуск пода
ReadinessГотов принимать трафикИсключение из LB при недоступной БД
Smoke testПосле деплоя«Логин + один критичный сценарий» проходит

Readiness не должен дергать тяжёлые отчёты — только зависимости, без которых сервис бессмысленен.


Антипаттерны

  • Логировать всё на INFO в проде → дорого и бесполезно.
  • Метрика с label url=/users/123 → взрыв кардинальности.
  • Искать причину только по среднему времени ответа — смотрите p95/p99.
  • Хранить аудит в той же БД без политики удаления → риск подмены.

Связанные темы


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).