Логирование A: почему print — это не логирование, и уровни лога
- Объяснить, что такое лог (Log) и почему print не подходит для записи того, что происходит в настоящей системе
- Знать пять уровней логирования и когда использовать каждый
- Настраивать базовое логирование с помощью
logging.basicConfigи выбирать минимальный уровень - Добавлять время и уровень в формат лога
Что мы изучим?
- Что такое лог (Log) и почему настоящие системы его пишут.
- Почему
print— это не логирование. - Модуль Python
logging. - Пять уровней лога:
debug,info,warning,error,critical.
Зачем это нужно?
Сервер, который вы напишете в темах бэкенда и баз данных, будет работать без присмотра, возможно, на компьютере в облаке, посреди ночи. Завтра утром клиент скажет: «мой заказ ночью пропал». Как узнать, что произошло?
printпечатал на экран, который никто не видел, и всё уже исчезло.- Отладчик не поможет, потому что баг произошёл вчера, а не сейчас.
Лог — это «чёрный ящик», как в самолёте: запись того, что произошло, когда и насколько серьёзно. Каждая профессиональная система пишет логи, и разработчики читают их каждый день.
Объяснение с основ
Что такое лог?
Лог (Log) — последовательность записей. Каждая запись описывает одно событие: когда оно произошло, насколько серьёзно и что произошло.
2026-10-06 09:14:02 INFO User dana logged in
2026-10-06 09:14:30 WARNING Login attempt with wrong password for avi
2026-10-06 09:15:11 ERROR Payment failed for order 1042: card declinedПочему print — это не логирование
print | logging | |
|---|---|---|
| Время | Нет. Неизвестно, когда это произошло. | Автоматически в каждой записи |
| Серьёзность | Все сообщения выглядят одинаково | 5 уровней. Можно фильтровать |
| Выключить/включить | Нужно удалять или добавлять строки кода | Изменить одну настройку, не трогая код |
| Назначение | Только экран | Экран, файл, сервер логов… |
| На сервере | Теряется | Сохраняется и проверяется потом |
Правило: print — для общения с пользователем (вывод программы). logging — для общения с разработчиками и эксплуатацией (что происходило внутри программы).
Пять уровней
| Уровень | Число | Когда использовать | Пример |
|---|---|---|---|
DEBUG | 10 | Технические детали для разработчика во время разработки и отладки | "cart contents: [...]" |
INFO | 20 | Обычные важные события — «всё в порядке» | "user dana logged in" |
WARNING | 30 | Что-то необычное, но система продолжает работу | "disk 90% full", "retrying request" |
ERROR | 40 | Действие не удалось | "payment failed for order 1042" |
CRITICAL | 50 | Вся система в опасности и, возможно, не сможет продолжать | "database unreachable - shutting down" |
Минимальный уровень — фильтрация
Вы задаёте минимальный уровень, и показываются только сообщения этого уровня и выше:
- Во время разработки:
DEBUG. Видно всё. - На настоящем сервере (Production):
INFOилиWARNING. Только важное, без «шума».
По умолчанию в Python — WARNING. Поэтому если ничего не настраивать, сообщения debug и info вообще не показываются.
DEBUG = полная запись каждого измерения (на неё смотрит только врач-исследователь). INFO = «пациент пообедал». WARNING = «температура немного повышена, продолжаем наблюдать». ERROR = «лекарство не дали вовремя». CRITICAL = «код синий!». Ночная медсестра выбирает видеть только WARNING и выше, иначе сообщения её захлестнут.
Синтаксис
import logging
# configure once, at the start of the program
logging.basicConfig(
level=logging.INFO, # minimum level to show
format="%(asctime)s %(levelname)s %(message)s", # how each record looks
)
# write log records
logging.debug("technical details")
logging.info("normal important event")
logging.warning("something unusual")
logging.error("an operation failed")
logging.critical("the whole system is in danger")Распространённые поля в format:
| Поле | Что показывается |
|---|---|
%(asctime)s | Дата и время |
%(levelname)s | Название уровня (INFO, ERROR…) |
%(message)s | Ваше сообщение |
%(funcName)s | Имя функции, которая сделала запись |
%(lineno)d | Номер строки |
Первый пример кода
week-2/log_levels.py:
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)
logging.debug("This is a debug message")
logging.info("Application started")
logging.warning("Config file not found, using defaults")
logging.error("Could not connect to the payment service")
logging.critical("Out of memory - shutting down")Вывод:
2026-10-06 09:30:12,481 INFO Application started
2026-10-06 09:30:12,481 WARNING Config file not found, using defaults
2026-10-06 09:30:12,482 ERROR Could not connect to the payment service
2026-10-06 09:30:12,482 CRITICAL Out of memory - shutting downРазбор кода построчно
| Строка | Объяснение |
|---|---|
import logging | Встроенный модуль Python для логов. Установка не нужна. |
logging.basicConfig(...) | Однократная настройка в начале программы: какой минимальный уровень и как выглядит каждая запись. |
level=logging.INFO | Показывать только начиная с INFO. |
format="..." | Шаблон записи: время, уровень, сообщение. |
logging.debug(...) | Не показывается! DEBUG (10) ниже INFO (20), поэтому отфильтрован. |
От logging.info(...) до logging.critical(...) | Показываются, потому что их уровень INFO и выше. |
,481 в выводе | Миллисекунды. Полезно, когда много событий происходит в одну секунду. |
Попробуйте: поменяйте на level=logging.DEBUG и запустите снова. Теперь появится 5 строк. С level=logging.ERROR появятся только 2. Вы изменили одну строку и не трогали сами сообщения. В этом сила уровней.
Ещё один пример
Логи внутри настоящей программы в сочетании с исключениями из предыдущих уроков. week-2/orders.py:
import logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s %(levelname)-8s %(funcName)s: %(message)s",
)
STOCK = {"bread": 5, "milk": 0, "eggs": 12}
def place_order(product, quantity):
logging.debug("place_order called with product=%s quantity=%s", product, quantity)
if product not in STOCK:
logging.error("Unknown product requested: %s", product)
return False
available = STOCK[product]
if available == 0:
logging.warning("Product out of stock: %s", product)
return False
if quantity > available:
logging.warning("Not enough %s: requested %s, available %s", product, quantity, available)
return False
STOCK[product] = available - quantity
logging.info("Order placed: %s x%s (left in stock: %s)", product, quantity, STOCK[product])
return True
place_order("bread", 2)
place_order("milk", 1)
place_order("cake", 1)
place_order("eggs", 20)Вывод:
2026-10-06 09:41:03,115 DEBUG place_order: place_order called with product=bread quantity=2
2026-10-06 09:41:03,115 INFO place_order: Order placed: bread x2 (left in stock: 3)
2026-10-06 09:41:03,116 DEBUG place_order: place_order called with product=milk quantity=1
2026-10-06 09:41:03,116 WARNING place_order: Product out of stock: milk
2026-10-06 09:41:03,116 DEBUG place_order: place_order called with product=cake quantity=1
2026-10-06 09:41:03,116 ERROR place_order: Unknown product requested: cake
2026-10-06 09:41:03,117 DEBUG place_order: place_order called with product=eggs quantity=20
2026-10-06 09:41:03,117 WARNING place_order: Not enough eggs: requested 20, available 12Разбор:
%(levelname)-8s—-8дополняет название уровня до 8 символов, чтобы сообщения выстраивались в столбец. Легко читать.%(funcName)s— видно, из какой функции пришла каждая запись.logging.info("... %s ...", product, quantity)—%s— заполнитель (placeholder) для значения, а значения передаются дополнительными аргументами. Это рекомендуемый способ в логировании: текст собирается, только если сообщение действительно будет показано, поэтому отфильтрованные сообщения DEBUG почти ничего не стоят.- Выбор уровней: «заказано» — INFO (обычное важное событие). «Нет в наличии» — WARNING (бизнес работает, но об этом стоит знать). «Товара не существует» — ERROR (что-то не так в запросе, возможно, баг на стороне клиента). Детали вызова — DEBUG.
if product not in STOCK—inдля словаря проверяет, существует ли ключ.
Теперь поменяйте на level=logging.WARNING: в логе останутся только 3 проблемы. Так это будет выглядеть на настоящем сервере, где интересны только сбои.
Типичная ошибка
Ошибка 1: вызывать basicConfig после того, как сообщение уже записано, или дважды.
import logging
logging.info("starting") # uses the default config!
logging.basicConfig(level=logging.INFO) # ignored - already configured
logging.info("now?") # still not shownПервый вызов logging.info автоматически устанавливает настройку по умолчанию (WARNING), а поздний basicConfig молча игнорируется. basicConfig — всегда первым и один раз, сразу после import.
Ошибка 2: «я не вижу свой info». Причина почти всегда в уровне по умолчанию WARNING. Исправление: level=logging.INFO (или DEBUG).
Ошибка 3: неправильный уровень.
logging.error("User dana logged in") # not an error!
logging.info("Payment failed!") # this IS an errorНеправильный уровень делает фильтрацию бесполезной: тот, кто смотрит только на ERROR, пропустит неудавшийся платёж и утонет в обычных входах в систему.
Ошибка 4: записывать в лог чувствительную информацию. logging.info("login: user=dana password=1234") — никогда не пишите пароли, номера кредитных карт или токены. Логи читают многие люди, и хранятся они долго.
Практика
Упражнения опираются только на то, что пройдено в этом уроке и в предыдущих. Сначала попробуйте сами, и только потом открывайте решение.
Упражнение 1: Какой уровень?
Для каждого события — на каком уровне лога вы бы его записали: DEBUG, INFO, WARNING, ERROR или CRITICAL?
- Пользователь успешно вошёл в систему.
- Значение переменной внутри цикла во время поиска бага.
- Пользователь ввёл неверный пароль.
- Платёж не прошёл.
- Нет соединения с базой данных, и сервер вообще не может работать.
Показать решение
- INFO — обычное событие, которое важно записать.
- DEBUG — технические детали, которые важны только во время разработки.
- WARNING — что-то необычное, но система продолжает работу.
- ERROR — действие не удалось.
- CRITICAL — вся система не может работать.
Упражнение 2: Минимальный уровень
import logging
logging.basicConfig(level=logging.WARNING)
logging.debug("checking item 3")
logging.info("order 17 created")
logging.warning("stock is low: 2 left")
logging.error("payment failed for order 17")Какие из сообщений появятся и почему? Что нужно изменить, чтобы увидеть все?
Показать решение
Появятся только WARNING и ERROR:
WARNING:root:stock is low: 2 left
ERROR:root:payment failed for order 17level=logging.WARNING — это минимальный уровень: показываются только сообщения этого уровня и выше. Чтобы увидеть все, поменяйте на level=logging.DEBUG. Без изменения остального кода — в этом всё преимущество.
Упражнение 3: От print к logging
Замените каждый print подходящим уровнем лога и задайте формат со временем, уровнем и сообщением:
def withdraw(balance, amount):
print("withdraw called with", amount)
if amount > balance:
print("not enough money, balance is", balance)
return balance
print("withdrew", amount)
return balance - amountПоказать решение
import logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s %(levelname)-8s %(message)s",
)
def withdraw(balance, amount):
logging.debug("withdraw called with %s", amount)
if amount > balance:
logging.error("not enough money, balance is %s", balance)
return balance
logging.info("withdrew %s", amount)
return balance - amount
withdraw(100, 30)
withdraw(100, 500)- Вход в функцию — DEBUG, успешное снятие — INFO, неудача — ERROR.
- Формат добавляет время и уровень к каждой строке, например:
2026-11-01 10:15:02 ERROR not enough money, balance is 100.
Упражнение 4: Читаем строку лога
2026-11-01 09:14:30 WARNING Wrong password for avi- Что представляет собой каждая часть строки и какая часть настройки
formatеё создаёт? - Почему важно, что в строке есть время?
Показать решение
- Части:
2026-11-01 09:14:30— время, его создаёт%(asctime)s.WARNING— уровень, его создаёт%(levelname)s.Wrong password for avi— сообщение, его создаёт%(message)s.
- Когда что-то происходит на сервере в три часа ночи, время позволяет восстановить, что произошло и в каком порядке, и сопоставить это с другими событиями.
Упражнение 5: print или logging?
Для каждого случая — print или logging? Объясните.
- Программа, которая спрашивает у пользователя имя и приветствует его.
- Сервер, который работает всю ночь, а утром вы хотите знать, какие заказы не прошли.
- Временная проверка значения переменной во время разработки, которую хочется выключить, не удаляя.
Показать решение
- print — это вывод, который программа показывает пользователю.
- logging (ERROR) — информация для разработчика, со временем и уровнем, которую можно сохранить и искать.
- logging (DEBUG) — все сообщения DEBUG можно выключить одной строкой (повысив минимальный уровень), не удаляя код.
Правило: print — для пользователя, logging — для разработчика.
Итоги
- Лог = запись событий: когда, насколько серьёзно и что произошло. «Чёрный ящик» программы.
print= вывод для пользователя.logging= запись для разработчиков: время, уровень, фильтрация и назначения.- 5 уровней: DEBUG < INFO < WARNING < ERROR < CRITICAL. Показываются только сообщения минимального уровня и выше.
- По умолчанию — WARNING.
basicConfigвызывается один раз, первым. logging.info("x=%s", x)— рекомендуемая форма. И никогда не логируйте пароли.