![]() |
Как логировать ошибки в Python-скриптах — что думаете?
Как логировать ошибки в Python-скриптах — что думаете?
Логирование ошибок — это одна из тех тем, которая часто кажется простой, но на самом деле умеет подкинуть пару сюрпризов даже опытным разработчикам. Где-то в глубинах каждого проекта рано или поздно возникает вопрос: как правильно и эффективно записывать ошибки, чтобы потом не пришлось гадать «а что же тут произошло?». Особенно если проект растёт, работает в проде или когда нужно поддерживать несколько скриптов. Почему логирование — не просто запись в файл Многие считают, что достаточно словить исключение и просто записать стэк-трейс куда-нибудь в текстовый файл. Да, это работает, и для какого-то простого скрипта этого может хватить. Но если копнуть глубже, начинаешь понимать, что у логирования есть куча нюансов: - Форматы записи (человек должен быстро понять логи, а не смотреть на кучу непонятных символов). - Уровни логирования (INFO, WARNING, ERROR, DEBUG), чтобы отделять важное от второстепенного. - Возможность ротации логов (чтобы файл не рос до гигабайтов за неделю). - Мультиконсольный и файловый вывод — иногда полезно видеть ошибки сразу в консоли, а иногда — собирать их только в файл. - Логи в продакшене часто собирает внешняя система (например, ELK, Graylog), так что важно правильно их структурировать. - Удалённый сбор логов с разных машин или контейнеров. В общем, если не продумать заранее — потом можно сильно запариться, пытаясь разгребать кучки непонятных данных. Основы логирования в Python В Python есть встроенный модуль logging, который покрывает большинство задач. Он универсальный, гибкий и достаточно простой, если разобраться. Вот самый простой пример для записи ошибок в файл: import logging logging.basicConfig(filename='errors.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') try: 1 / 0 except Exception as e: logging.error("Exception occurred", exc_info=True) Важная часть тут — exc_info=True. Если его не указать, в лог запишется только строка сообщения, а стек вызовов не попадёт. Именно стек вызовов (traceback) часто даёт самое ценное понимание, где именно упёрлись. Почему стоит использовать уровни логирования Лучше сразу определить разный уровень важности сообщений: - DEBUG — очень подробные сведения, полезно при отладке. - INFO — обычные события, например, «скрипт запустился», «запрос отправлен». - WARNING — ситуация, которая не повод для сбоя, но стоит внимания. - ERROR — серьезные проблемы, которые приводят к ошибкам. - CRITICAL — критические сбои, после которых программа может аварийно завершиться. Если не разбивать логи по уровню, то в больших проектах быстро запутаешься, а при поиске важного события придётся шерстить гигабайты неактуальных сообщений. Настройка более продвинутых логеров logging.basicConfig — хороший старт, но у него есть ограничения. Например, нельзя легко настроить несколько обработчиков с разными форматами для разных целей. Здесь на помощь приходят логгеры, хэндлеры и форматтеры: import logging logger = logging.getLogger("myApp") logger.setLevel(logging.DEBUG) file_handler = logging.FileHandler('app.log') file_handler.setLevel(logging.ERROR) console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler) try: x = 5 / 0 except Exception: logger.error("Ошибка деления на ноль", exc_info=True) В этом примере ошибки записываются в файл, а INFO-сообщения — только в консоль. Это удобно, чтобы разработчики видели что происходит прямо в терминале, а в логе оставались только важные ошибки. Чек-лист для нормального логирования ошибок в Python - Всегда записывайте стек вызова (exc_info=True или traceback.format_exc()). - Используйте уровни логов для фильтрации и разных целей. - Настраивайте формат сообщения, чтобы лог был читаемым. - Не пишите секретные данные в логи (пароли, токены). - Применяйте ротацию логов (например, RotatingFileHandler), чтобы файл не раздувался. - Логируйте ошибки сразу в месте их обработки, а не где-то далеко. - В продакшен-окружении настройте централизованный сбор логов (например, с помощью syslog, fluentd). - Проверяйте, чтобы лог-файлы были доступны и не занимали всё пространство. Типичные ошибки при логировании ошибок - Не указывать exc_info=True — в результате логи почти бесполезны без контекста. - Логирование больших объектов целиком (например, дампов памяти), из-за чего логи становятся громоздкими. - Игнорирование уровней логирования — всё подряд пишется на минимальном уровне DEBUG или ERROR. - Забывать про ротацию логов и не контролировать размер файлов. - Писать логи в каталог без прав записи. - Заливать в лог слишком много информации и терять критическую. - Использовать print для отладки вместо нормального логирования — потом сложно масштабировать. FAQ по логированию ошибок в Python Вопрос: Можно ли логировать в json-формате? Ответ: Да, можно настроить форматтер, который будет писать в JSON, что удобно для парсинга логов внешними системами. Вопрос: Как логировать асинхронные ошибки в asyncio? Ответ: Там лучше использовать специальный обработчик событий loop.set_exception_handler, чтобы ловить необработанные исключения и передавать их в логгер. Вопрос: Нужно ли логировать все исключения? Ответ: Не обязательно. Часто стоит логировать самые серьезные и необработанные, иначе логи будут засорены. Вопрос: Что делать с логами в контейнерах Docker? Ответ: Обычно логи пишут в stdout/stderr, а системы оркестрации (например, Kubernetes) перенаправляют и собирают их централизованно. Вопрос: Как обрабатывать очень длинные стэк-трейсы? Ответ: Можно ограничить длину, либо использовать сжатие логов, но лучше всего — детально разбираться с причиной багов, чтобы не получать повторяющиеся огромные логи. В общем, если коротко — не надо просто ловить ошибки и вываливать их в файл. Надо продумать логи как инструмент, а не просто способ «чтобы было». Благодаря хорошему логированию потом можно смело быстро реагировать на проблемы, анализировать их и развивать проекты без лишней головной боли. Что используете вы? Какие есть классные приёмы по работе с логами? Может, кто-то пользуется какими-то библиотеками поверх стандартного logging? Расскажите, обсудим. |
| Время: 16:24 |