Приходилось ли работать со стеком логирования и мониторинга
Что проверяют
Настраивали ли вы наблюдаемость сами или пользовались готовым. Смотрят три вещи: знаете ли вы модуль logging глубже вызова basicConfig, отличаете ли логи от метрик и трассировки, и понимаете ли, что из этого читает дежурный во время инцидента.
Как отвечать
Разложите на три слоя и скажите, за что отвечает каждый.
- Логи. В коде только
logger = logging.getLogger(__name__), вся настройка одним местом черезdictConfigна старте приложения. В библиотеке настройки быть не должно, максимумNullHandler. Формат структурный, объект с полями, а не склеенная строка: искать по полю можно, по фразе нельзя. Сквозной идентификатор запроса кладётся вcontextvarsи подмешивается фильтром, иначе строки одного запроса не связать. Пишем в стандартный вывод, сбором занимается агент рядом. - Метрики. Счётчики и гистограммы через клиентскую библиотеку, набор минимальный: частота запросов, доля ошибок, задержка по верхним перцентилям, насыщение ресурсов. Ярлыки с неограниченным числом значений класть нельзя.
- Трассировка. Автоинструментирование по стандарту OpenTelemetry даёт отрезки по запросам и походам в базу, а идентификатор трассы попадает и в лог, и связывает слои между собой.
Про оповещения скажите отдельно: будим человека на симптомы, которые видит пользователь, остальное на панели.
Где спотыкаются
Логируют через print или прямо в корневой логгер, а потом в проде нет ни уровня, ни времени, ни имени модуля. Рядом живёт классика: logger.error(f"сбой: {e}") вместо logger.exception, из-за чего в логе остаётся текст исключения без стека вызовов.
Забывают про многопроцессность. Веб-сервер поднимает несколько рабочих процессов, и метрики по умолчанию видны только от того, который ответил на запрос. Нужен многопроцессный режим с общим каталогом. С файловым логом та же беда: процессы дерутся за файл и за его ротацию.
Кладут в лог то, чего там быть не должно: токены, пароли, тело запроса целиком, персональные данные. И держат синхронную отправку по сети прямо в обработчике, из-за чего тормоза приёмника становятся тормозами приложения. Лечится очередью: QueueHandler в рабочем потоке и QueueListener в фоне.