Правильный выбор между print и logging для отладки

Раздел: Основы Python -> Отладка и ошибки

Основные подходы к выводу отладочной информации

Как организовать профессиональное логирование вместо хаотичного 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'.

Логирование и print в Python - comments

En
Python logging print (python)