Как реализовать логирование и мониторинг микросервисов
Что проверяют
Есть ли у вас рабочая схема наблюдаемости, а не список модных названий. Интервьюеру важно, сможете ли вы по одной жалобе пользователя найти, в каком сервисе и почему упал запрос. Следом обычно спрашивают, как связать логи разных сервисов между собой.
Как отвечать
Стройте ответ вокруг трёх сигналов: логи, метрики, трассировки.
- структурные логи: JSON в stdout, собирает их агент (Fluent Bit, Vector, Grafana Alloy) и отправляет в Loki или OpenSearch. В Python это
structlogилиloggingс JSON-форматтером; сервис сам в файлы не пишет и ротацией не занимается; - корреляция:
trace_idилиX-Request-IDпринимается на входе, кладётся вcontextvarsи попадает в каждую строку лога и в заголовки исходящих запросов.contextvarsработает и в asyncio, в отличие отthreading.local; - метрики:
prometheus_clientотдаёт/metrics, Prometheus забирает их по pull-модели. Считайте по методу RED: частота запросов, доля ошибок, длительность в виде гистограммы, чтобы строить p95 и p99; - трассировки: OpenTelemetry SDK с автоинструментацией для FastAPI, Django,
httpx, SQLAlchemy, экспорт по OTLP в Jaeger или Tempo. Инструментацию Celery подключают и в воркере, иначе цепочка обрывается на очереди; - алерты: Alertmanager или Grafana по симптомам для пользователя (рост 5xx, латентность выше SLO), а не по загрузке CPU.
Где спотыкаются
Логируют f-строками: logger.info(f"user {user_id} paid"). Вместо полей получается текст, который не отфильтровать, а форматирование выполняется даже при выключенном уровне.
Пишут в лог персональные данные и токены: тело запроса целиком, заголовок Authorization, номер карты. Маскировать нужно фильтром или процессором на уровне логгера, а не надеяться на аккуратность каждого разработчика.
Добавляют в метки Prometheus user_id или полный URL. Кардинальность взрывается, и сервер метрик ложится первым. Метки должны иметь ограниченный набор значений: шаблон маршрута, метод, код ответа.