Управление выводом сообщений логгера в Python: ошибки

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для того чтобы пресечь вывод логов Python в stderr, используйте NullHandler:

Python
Скопировать код
import logging

logging.getLogger().addHandler(logging.NullHandler())

Либо, если хотите полностью отключить stderr, перенаправьте его в файл или в os.devnull:

Python
Скопировать код
import logging, os

logging.basicConfig(handlers=[logging.StreamHandler(open(os.devnull, 'w'))])

С NullHandler вы будете полностью игнорировать логи. А перенаправление в os.devnull позволит избавиться от лишних сообщений.

Кинга Идем в IT: пошаговый план для смены профессии

Останавливаем распространение: управляем распространением сообщений от логгера

Понимаем механизм распространения сообщений от логгера

Для настройки передачи сообщений от логгера к его "родителям", следует разобраться с атрибутом logger.propagate:

Python
Скопировать код
logger = logging.getLogger('my_logger')
logger.propagate = False

Отключение propagate предотвратит вывод логов на уровне корневого логгера и, соответственно, в stderr.

Берём под контроль отдельные обработчики

Для детальной настройки логирования стоит отключать обработчики по отдельности:

Python
Скопировать код
for handler in logger.handlers:
    if isinstance(handler, logging.StreamHandler):
        logger.removeHandler(handler)

Таким образом, вы сохраните работу других важных обработчиков, например тех, которые записывают данные в файл.

Единая команда для управления всем: продвинутое и временное управление логгером

Осваиваем способ работы с менеджерами контекста

Для временного контроля над процессом логирования можно использовать менеджер контекста:

Python
Скопировать код
import contextlib

@contextlib.contextmanager
def pause_logging(logger):
    original_handlers = logger.handlers
    logger.handlers = [logging.NullHandler()]
    try:
        yield
    finally:
        logger.handlers = original_handlers

with pause_logging(logging.getLogger()):
    # Логирование временно отключено

Как не допустить автоматическое восстановление стандартного обработчика

Следите за тем, чтобы логгер не возвращал стандартные обработчики, когда они у него отсутствуют.

Приводим уровень "шума" в порядок: настраиваем уровни логирования

Комфортная настройка уровней

Можно настроить уровни логирования, задавая их для каждого обработчика в отдельности:

Python
Скопировать код
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARN)
logger.addHandler(console_handler)

После этого будут проходить только предупреждения с уровнем WARNING и выше.

Отключаем логирование глобально

Чтобы полностью выключить логирование:

Python
Скопировать код
logging.disable(logging.CRITICAL)

Если в будущем потребуется вернуть логирование, его можно активировать, установив уровень на logging.NOTSET:

Python
Скопировать код
logging.disable(logging.NOTSET)

Визуализация

Приведем наглядное сравнение кода до и после отключения стандартного потока ошибок stderr:

Python
Скопировать код
import logging

logging.basicConfig(level=logging.DEBUG)

logging.debug("Это попадёт в stderr")

logging.getLogger().handlers[0].stream = None

logging.debug("Это НЕ попадёт в stderr")

Результат:

Markdown
Скопировать код
До: [📢, 📚(Ваш код)]
После: [🔕, 📚(Ваш код)]

Отключив логирование, вы, таким образом, замените "шум" на тишину.

Держим всё под контролем: надёжная защита настроек логирования

Безопасное взаимодействие со стандартными обработчиками

Перед тем как вносить изменения, всегда проверяйте существование стандартного обработчика:

Python
Скопировать код
if logger.handlers:
    logger.handlers[0].stream = None

Сначала файловые обработчики, затем stdout

Файловые обработчики следует добавлять перед тем, как настроить стандартный поток вывода:

Python
Скопировать код
file_handler = logging.FileHandler('logfile.log')
logger.addHandler(file_handler)

Обеспечиваем надёжность вашего менеджера контекста с помощью обработки исключений

Укрепите ваш менеджер контекста, обеспечив обработку возможных исключений:

Python
Скопировать код
@contextlib.contextmanager
def bulletproof_pause_logging(logger):
    original_handlers = logger.handlers
    logger.handlers = [logging.NullHandler()]
    try:
        yield
    finally:
        try:
            logger.handlers = original_handlers
        except Exception as e:
            logger.error("Возникла ошибка при попытке восстановить обработчики логгера.", exc_info=e)

Таким образом, ваш менеджер контекста продолжит работу даже при возникновении непредвиденных обстоятельств.

Полезные материалы

  1. Logging HOWTO — Документация Python 3.12.2 — Официальное руководство по работе с модулем логирования Python.
  2. Logging in Python – Real Python — Подробное руководство по модулю логирования в Python.
  3. logging — Ведение журнала событий для Python — Документация Python 3.12.2 — Глубокое изучение всех возможностей модуля logging.
  4. Logging Cookbook — Документация Python 3.12.2 — Практические рекомендации для работы с с модулем логирования.
  5. Logging HOWTO — Управление обработчиками – Документация Python — Руководство по управлению обработчиками потока stderr.