Правильный выбор между print и logging для отладки
Основные подходы к выводу отладочной информации
Как организовать профессиональное логирование вместо хаотичного print?
Наиболее эффективное решение для отладки и мониторинга программ на Python - использование встроенного модуля logging. В отличие от print, он позволяет гибко управлять выводом, задавать уровни важности (DEBUG, INFO, WARNING, ERROR, CRITICAL), направлять сообщения в разные потоки (консоль, файл, сеть) и форматировать их. Ниже приведён минимальный рабочий пример.
import logging
logging.basicConfig(level=logging.INFO)
logging.info('Программа запущена')Python logging print (логирование и print в python)
После вызова basicConfig все последующие сообщения с уровнем INFO и выше будут выводиться в стандартный поток ошибок (stderr).
Типичная ошибка:
вызовbasicConfig несколько раз игнорирует последующие настройки. Если требуется переопределить конфигурацию, нужно использовать logging.getLogger().setLevel() или пересоздать логгер.Как сохранить простоту print, но получить больше контроля?
Можно использовать logging с минимальной настройкой, но при этом заменить все вызовы print на logging.debug или logging.info. Это не требует серьёзных изменений в коде, но даёт возможность позже отключить вывод, изменив уровень всего в одном месте.
import logging
logging.basicConfig(level=logging.DEBUG)
data = [1, 2, 3]
logging.debug(f'Данные: {data}')Python print traceback (печать traceback в python)
Проблема:
если не задать формат, сообщения не содержат временной метки и имени модуля. Для отладки рекомендуется добавитьformat в basicConfig.Как выводить сообщения только при отладке, а в продакшене пропускать?
Уровни позволяют легко фильтровать сообщения. В разработке можно установить level=logging.DEBUG, а в продакшене - level=logging.WARNING. Так отладочные сообщения не попадут в логи.
import logging
DEBUG_MODE = True
level = logging.DEBUG if DEBUG_MODE else logging.WARNING
logging.basicConfig(level=level)
logging.debug('Это отладочное сообщение')
logging.info('Информационное сообщение')
Traceback type python (тип traceback в python)
Как записывать логи в файл, а не в консоль?
Достаточно указать параметр filename в basicConfig.
import logging
logging.basicConfig(filename='app.log', level=logging.INFO)
logging.info('Сообщение записано в файл')Python не выводит ответ (почему python не выводит ответ?)
Важно:
по умолчанию файл открывается в режиме добавления. Если нужно перезаписывать файл при каждом запуске, следует указатьfilemode='w'.Как добавить информацию о времени и номере строки в каждое сообщение?
Используйте форматирование через format.
logging.basicConfig(
format='%(asctime)s - %(levelname)s - %(message)s - Line: %(lineno)d',
level=logging.DEBUG
)
logging.debug('Проверка переменной x')В результате вывод будет содержать временную метку, уровень, сообщение и номер строки в коде.
Как логировать исключения с полным traceback?
При перехвате исключения достаточно вызвать logging.exception или передать exc_info=True.
import logging
logging.basicConfig(level=logging.ERROR)
try:
1 / 0
except ZeroDivisionError:
logging.exception('Произошло деление на ноль')Этот метод автоматически добавляет стек вызовов в лог.
Как перенаправить сообщения из нескольких модулей в один логгер?
Создайте логгер в главном модуле и используйте его в подмодулях, передавая имя или используя __name__.
# main.py
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
# utils.py
import logging
logger = logging.getLogger(__name__)
logger.info('Сообщение из utils')Поскольку getLogger(__name__) использует иерархию, все логгеры наследуют настройки корневого.
Как временно отключить все логи, не удаляя вызовы?
Установите уровень корневого логгера на logging.CRITICAL или выше. Также можно временно добавить фильтр.
logging.getLogger().setLevel(logging.CRITICAL + 1)Все сообщения будут игнорироваться.
Расширенные примеры использования модуля logging
Следующие примеры демонстрируют более сложные конфигурации, полезные в реальных проектах.
Как настроить ротацию лог-файлов по размеру?
Модуль logging.handlers включает RotatingFileHandler, который автоматически создаёт новые файлы при достижении заданного размера.
import logging
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler('app.log', maxBytes=1024, backupCount=3)
logging.basicConfig(handlers=[handler], level=logging.INFO)
for i in range(100):
logging.info(f'Сообщение номер {i}')После заполнения файла на 1 КБ создаётся новый файл app.log.1, и так до трёх резервных копий.
Проблема:
если приложение работает долго, старые файлы будут перезаписаны. Можно увеличитьbackupCount или использовать TimedRotatingFileHandler для ротации по времени.Как логировать в несколько мест одновременно (консоль + файл)?
Добавьте несколько обработчиков к одному логгеру.
import logging
logger = logging.getLogger('multi')
logger.setLevel(logging.DEBUG)
# Обработчик для файла
file_handler = logging.FileHandler('multi.log')
file_handler.setLevel(logging.WARNING)
# Обработчик для консоли
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
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)
logger.debug('Отладка')
logger.warning('Предупреждение')В консоль попадёт и DEBUG, и WARNING, а в файл - только WARNING и выше.
2025-03-25 14:30:00,000 - multi - DEBUG - Отладка
2025-03-25 14:30:00,001 - multi - WARNING - Предупреждение
Как использовать конфигурацию через словарь (dictConfig)?
Для сложных проектов удобно задавать параметры в словаре и передавать logging.config.dictConfig.
import logging
from logging.config import dictConfig
config = {
'version': 1,
'formatters': {
'detailed': {
'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'detailed'
},
'file': {
'class': 'logging.FileHandler',
'filename': 'detailed.log',
'level': 'ERROR'
}
},
'root': {
'level': 'DEBUG',
'handlers': ['console', 'file']
}
}
dictConfig(config)
logging.debug('Отладочное сообщение')
logging.error('Ошибка')Такая конфигурация легко хранится в YAML или JSON и упрощает настройку.
Как добавить цветной вывод в консоль для разных уровней?
С помощью библиотеки colorlog (требует установки).
import logging
import colorlog
handler = colorlog.StreamHandler()
handler.setFormatter(colorlog.ColoredFormatter(
'%(log_color)s%(levelname)s: %(message)s'
))
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug('Синий')
logger.warning('Жёлтый')
logger.error('Красный')Результат - цветные сообщения, улучшающие восприятие.
Как фильтровать логи по определённому условию?
Создайте собственный фильтр, реализующий метод filter.
import logging
class ImportantFilter(logging.Filter):
def filter(self, record):
return 'important' in record.getMessage()
logger = logging.getLogger(__name__)
logger.addFilter(ImportantFilter())
logger.setLevel(logging.DEBUG)
logging.basicConfig(level=logging.DEBUG, force=True)
logging.warning('Обычное предупреждение')
logging.error('important: критическая ошибка')Выводится только второе сообщение, так как оно содержит слово 'important'.