Введение: Боль и страдания от print() и стандартного logging

Если вы пишете на Python, скорее всего, ваша карьера разработчика начиналась с одной простой, но незаменимой команды — print(). Нужно проверить значение переменной? print(my_variable). Хотите убедиться, что функция вообще вызвалась? print("Я внутри функции!"). Этот метод прост, интуитивно понятен и кажется верным другом в мире отладки.

Но дружба эта длится ровно до первого серьезного проекта. Внезапно оказывается, что ваш терминал завален десятками отладочных сообщений, и вы уже не понимаете, какое из них к чему относится. Вы начинаете писать print("--- HERE ---"), чтобы хоть как-то ориентироваться в этом хаосе. А когда приходит время выкатывать код в продакшен, вы судорожно ищете и комментируете все свои print(), надеясь не пропустить ни одного.

В этот момент опытные коллеги (или статьи в интернете) говорят вам: "Для этого есть стандартный модуль logging!". И они правы. logging — это мощный, гибкий и правильный инструмент. Но давайте будем честны, его настройка часто напоминает бюрократическую процедуру. Чтобы просто начать писать логи в файл с указанием времени и уровня, нужно написать что-то вроде этого:

import logging

# Настройка... снова и снова
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler()
    ]
)

logging.info("Пользователь вошел в систему.")
logging.warning("Не удалось найти файл конфигурации.")

Это работает, но это громоздко. Пять-шесть строк кода только для того, чтобы начать. А если вам понадобится ротация файлов, кастомные форматы или что-то посложнее? Конфигурация становится еще запутаннее.

Именно в этот момент на сцену выходит Loguru. Эта библиотека была создана для того, чтобы избавить нас от страданий. Она берет лучшее из двух миров: феноменальную простоту print() и всю мощь взрослого логирования, но без лишнего "шума" и сложной настройки.

Что, если я скажу вам, что цветное логирование в консоль, запись в файл с автоматической ротацией и сжатием, а также невероятно удобная отладка исключений могут быть настроены всего одной строкой кода?

В этой статье мы раз и навсегда забудем про print() для отладки и посмотрим, как Loguru может сделать ваше логирование не только мощным, но и по-настоящему красивым и удобным.

Часть 1: Первое знакомство с Loguru — магия "из коробки"

Итак, мы оставили позади боль от print() и сложность logging. Давайте посмотрим, что предлагает Loguru и почему его называют "логированием для удовольствия".

Установка: один шаг до магии

Как и положено современному Python-пакету, установка предельно проста и выполняется одной командой в терминале:

pip install loguru

Всё, библиотека готова к работе. Никаких зависимостей, никаких сложных настроек окружения.

"Hello, Loguru!": начинаем за 5 секунд

Помните, сколько кода нужно было для базовой настройки logging? Забудьте. С Loguru вы просто импортируете готовый к использованию объект logger и начинаете его использовать.

from loguru import logger

logger.info("Hello, Loguru!")
logger.warning("Это предупреждение, будьте внимательны.")
logger.debug("Это сообщение не будет видно по умолчанию.")

Запустите этот код, и вы увидите в консоли что-то вроде этого:

2025-11-13 13:00:00.000 | INFO     | __main__:__main__:3 - Hello, Loguru!
2025-11-13 13:00:00.000 | WARNING  | __main__:__main__:4 - Это предупреждение, будьте внимательны.

Обратите внимание: debug-сообщение не появилось. По умолчанию Loguru, как и любая серьезная система логирования, показывает сообщения уровня INFO и выше. Это правильное поведение, которое избавляет от лишнего шума в консоли.

Разбираем стандартный вывод: всё, что нужно, и ничего лишнего

Давайте внимательно посмотрим на первую строку вывода:

2025-11-13 13:00:00.000 | INFO | __main__:__main__:3 - Hello, Loguru!

Даже без единой строчки конфигурации Loguru сразу предоставляет нам богатый контекст:

  • Дата и время: 2025-11-13 13:00:00.000 — точная временная метка, когда произошло событие. Больше не нужно гадать, к какому моменту времени относится print.

  • Уровень лога: INFO — показывает важность сообщения. WARNING говорит о потенциальной проблеме, ERROR — о серьезной ошибке.

  • Местоположение: __main__:__main__:3 — это самая полезная часть. Loguru автоматически указывает имя файла, функцию и номер строки, откуда был сделан вызов. Это невероятно ускоряет отладку!

  • Сообщение: Hello, Loguru! — непосредственно то, что мы хотели записать.

Магия цвета: прощай, монотонная консоль!

Если вы запустите приведенный выше код в терминале, который поддерживает цвета (а сегодня это делают почти все), вы увидите еще одну приятную особенность: вывод будет раскрашен!

  • INFO обычным белым.

  • WARNING — заметным желтым.

  • ERROR и CRITICAL — тревожно-красным.

Это не просто украшение. Цвета помогают мгновенно сканировать лог глазами и находить проблемы, не вчитываясь в каждое слово. Это та самая "красота" и "удобство", которых так не хватает стандартным инструментам.

Всего один import — и мы уже получили цветное, информативное и правильно структурированное логирование. Это и есть магия Loguru "из коробки". А ведь мы еще даже не начали знакомиться с его основными возможностями

Часть 2: Основные возможности на практических примерах

Мы убедились, что Loguru прекрасен "из коробки". Но его настоящая сила раскрывается, когда мы начинаем использовать его основные функции. И здесь Loguru остается верен своему принципу: максиму�� пользы при минимуме кода.

Уровни логирования: управляем потоком информации

Как мы уже видели, Loguru поддерживает стандартные уровни важности сообщений:

  • TRACE (самый подробный)

  • DEBUG

  • INFO

  • SUCCESS (приятное дополнение для успешных операций)

  • WARNING

  • ERROR

  • CRITICAL

По умолчанию в консоль выводятся сообщения от INFO и выше. Это легко изменить. Например, чтобы включить DEBUG-сообщения, нужно перенастроить стандартный обработчик (sink), указав новый уровень:

from loguru import logger

# Удаляем стандартный обработчик и добавляем новый с уровнем DEBUG
logger.remove()
logger.add(sys.stderr, level="DEBUG") # sys.stderr - это стандартный поток ошибок (консоль)

logger.debug("Теперь это сообщение будет видно!")
logger.info("И это, конечно, тоже.")

Запись логов в файл: одна строка, чтобы править всеми

Это одна из самых мощных и востребованных функций. Забудьте про FileHandler и его сложную настройку. С Loguru все делается одной командой — logger.add().

Просто записать в файл:

from loguru import logger

logger.add("my_app.log")

logger.info("Это сообщение попадет и в консоль, и в файл my_app.log")

Но настоящая магия начинается, когда мы добавляем параметры в эту команду.

Автоматическая ротация файлов (Rotation)

Ваш лог-файл не будет расти бесконечно, занимая все место на диске. Loguru может автоматически создавать новый файл, когда старый достигает определенного размера или проходит определенное время.

# Создавать новый файл, как только текущий достигнет 500 MB
logger.add("big_file.log", rotation="500 MB")

# Создавать новый файл каждую неделю
logger.add("weekly_log.log", rotation="1 week")

# Создавать новый файл каждый день в полночь
logger.add("daily_log.log", rotation="00:00")

Автоматическая очистка старых логов (Retention)

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

# Хранить логи за последние 10 дней
logger.add("cleaned_log.log", retention="10 days")

Автоматическое сжатие (Compression)

Loguru может даже самостоятельно архивировать старые лог-файлы, чтобы они занимали меньше места.

# При ротации сжимать старые файлы в zip-архив
logger.add("compressed_log.log", rotation="10 MB", compression="zip")

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

from loguru import logger

# Настраиваем логирование для продакшена:
# - Пишем в файл `prod.log`
# - Уровень - INFO и выше
# - Ротация при достижении 10 MB
# - Храним файлы 1 месяц
# - Сжимаем старые логи в .gz
logger.add("prod.log", level="INFO", rotation="10 MB", retention="1 month", compression="gz")

logger.info("Система запущена и готова к работе!")

Всего одна строка кода заменяет десятки строк конфигурации стандартного logging. Это невероятно удобно.

Форматирование в стиле f-string

Еще одна мелочь, которая делает жизнь разработчика проще. Loguru использует для форматирования строк фигурные скобки, как в f-strings, что гораздо читабельнее и привычнее, чем старый %-стиль.

user_id = 123
status = "success"

# Привычный и читаемый синтаксис
logger.info("Аутентификация для пользователя {id} прошла со статусом: {status}", id=user_id, status=status)

Вывод будет таким:
... | INFO | ... - Аутентификация для пользователя 123 прошла со статусом: success

Мы рассмотрели базовые, но самые часто используемые возможности Loguru. Уже на этом этапе видно, насколько он упрощает и ускоряет разработку. Но это еще не все — в следующей части мы погрузимся в продвинутые техники, которые сделают вашу отладку по-настоящему волшебной.

Часть 3: Продвинутые техники для настоящих профи

Мы освоили основы, которые уже делают работу с логами приятнее. Но Loguru был создан не только для удобства — он предоставляет мощнейшие инструменты для отладки, которые могут сэкономить вам часы поиска ошибок. Давайте рассмотрим функции, которые отличают новичка от профессионала.

1. Идеальная отладка исключений

Это, пожалуй, главная "киллер-фича" Loguru. Стандартный трейсбэк в Python информативен, но часто хочется видеть значения переменных, которые привели к ошибке.

Логирование внутри try...except

Во-первых, вы можете использовать logger.exception(), который автоматически захватит и красиво отформатирует информацию о последнем исключении.

from loguru import logger

try:
    result = 10 / 0
except ZeroDivisionError:
    logger.exception("Произошла ошибка при вычислении.")

Вывод будет содержать не только ваше сообщение, но и полный, аккуратно отформатированный трейсбэк ошибки.

Декоратор @logger.catch — ваша секретная кнопка "Найти ошибку"

Но настоящий прорыв — это декоратор @logger.catch. Вы можете просто "обернуть" в него любую функцию, и Loguru автоматически поймает любое исключение, которое в ней произойдет, и выведет самый подробный отчет из возможных.

Посмотрите на этот пример:

from loguru import logger

@logger.catch
def calculate(a, b, c):
    return a / b + c

calculate(10, 0, 5) # Эта строка вызовет ошибку

Без @logger.catch вы бы получили стандартный трейсбэк. Но с декоратором Loguru выведет в консоль нечто гораздо более ценное:

> 2025-11-13 13:00:00.000 | ERROR    | __main__:calculate:5 - An error has been caught in function 'calculate', process 'MainProcess' (1234), thread 'MainThread' (5678):
Traceback (most recent call last):
...
  File "my_script.py", line 6, in <module>
    calculate(10, 0, 5)
    │         │  │  └ c = 5
    │         │  └ b = 0
    │         └ a = 10
  File "my_script.py", line 5, in calculate
    return a / b + c
           ──┘ └───
            │   └ 0
            └ 10

ZeroDivisionError: division by zero

Посмотрите внимательно: Loguru не просто показал, где произошла ошибка, он показал значения всех аргументов (a = 10, b = 0, c = 5) в момент падения! Это бесценная информация для отладки, которую вы получаете, добавив всего одну строку кода (@logger.catch).

2. Кастомизация формата логов

Стандартный формат хорош, но иногда его нужно адаптировать под требования проекта. Это легко сделать с помощью параметра format в logger.add().

Вы можете собрать свой формат из готовых "кирпичиков":

from loguru import logger
import sys

# Удаляем стандартный обработчик, чтобы не было дублирования
logger.remove()

# Создаем свой, очень подробный формат
custom_format = (
    "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
    "<level>{level: <8}</level> | "
    "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
)

logger.add(sys.stderr, format=custom_format)

logger.info("Лог в кастомном формате.")

Здесь мы добавили теги для цвета (<green>, <level>) и указали новые поля, например, {function} и {name}. Полный список доступных полей есть в официальной документации Loguru.

3. Структурированное логирование (JSON)

В современных системах логи часто собираются и анализируются машинами (например, в ELK Stack, Graylog или Datadog). Для этого они должны быть в структурированном формате, чаще всего — JSON.

С Loguru это делается элементарно — добавлением одного параметра: serialize=True.

from loguru import logger

logger.add("structured_data.log", serialize=True)

user_data = {"id": 123, "name": "John Doe"}
logger.info("Пользователь {user} обновил профиль", user=user_data)

В файле structured_data.log появится запись в формате JSON, идеально подходящая для парсинга:

{
    "text": "Пользователь {'id': 123, 'name': 'John Doe'} обновил профиль\n",
    "record": {
        "elapsed": {"repr": "0:00:00.001000", "seconds": 0.001},
        "exception": null,
        "extra": {},
        "file": {"name": "my_script.py", "path": "/path/to/my_script.py"},
        "function": "<module>",
        "level": {"icon": "ℹ️", "name": "INFO", "no": 20},
        "line": 6,
        "message": "Пользователь {'id': 123, 'name': 'John Doe'} обновил профиль",
        "name": "__main__",
        "process": {"id": 1234, "name": "MainProcess"},
        "thread": {"id": 5678, "name": "MainThread"},
        "time": {"repr": "2025-11-13T13:00:00.000000+03:00", "timestamp": 1762989600.0}
    }
}

4. Добавление контекста с помощью bind()

В сложных приложениях, например, в веб-сервисах, важно отслеживать цепочку событий, относящихся к одному запросу. Loguru позволяет "привязать" контекст к логгеру, и этот контекст будет добавляться во все последующие сообщения.

from loguru import logger
import uuid

# Создаем логгер с привязанным ID запроса
request_id = str(uuid.uuid4())
context_logger = logger.bind(request_id=request_id)

context_logger.info("Получен новый запрос.")
# ... какой-то код
context_logger.info("Данные из базы успешно получены.")
# ... еще код
context_logger.warning("Внешний API ответил с задержкой.")

В каждом из этих сообщений будет автоматически добавлено поле request_id, что позволит вам в системе сбора логов легко отфильтровать все события, связанные с одним конкретным запросом.

Эти продвинутые техники превращают Loguru из простого инструмента для записи сообщений в мощный фреймворк для отладки и мониторинга, который остается таким же простым в использовании.

Часть 4: Loguru в реальном проекте: Советы и лучшие практики

Мы изучили мощные функции Loguru, но как грамотно внедрить его в полноценное приложение? Просто импортировать logger в каждом файле — это начало, но для создания надежной и масштабируемой системы стоит учесть несколько моментов.

1. Создайте централизованную конфигурацию

Чтобы не настраивать логгер в разных частях вашего проекта, лучше всего создать один модуль, отвечающий за всю конфигурацию логирования. Это сделает ваши настройки последовательными и легко изменяемыми.

Создайте файл, например, app/logging_config.py:

# app/logging_config.py
import sys
from loguru import logger

def setup_logging():
    """
    Настраивает логгер для всего приложения.
    """
    # Удаляем стандартный обработчик, чтобы избежать дублирования
    logger.remove()

    # Добавляем обработчик для вывода в консоль (для разработки)
    # Уровень DEBUG, цветной вывод
    logger.add(
        sys.stderr,
        level="DEBUG",
        format="<white>{time:HH:mm:ss}</white> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan> - <level>{message}</level>",
        colorize=True
    )

    # Добавляем обработчик для записи в файл (для продакшена)
    # Уровень INFO, ротация, сжатие
    logger.add(
        "logs/app.log",
        level="INFO",
        rotation="10 MB",
        retention="1 month",
        compression="zip",
        serialize=False, # В данном примере используем текстовый формат
        format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
    )

    logger.info("Конфигурация логирования завершена.")

Теперь в главном файле вашего приложения (например, main.py) вам нужно просто импортировать и вызвать эту функцию один раз при старте:

# main.py
from app.logging_config import setup_logging
from loguru import logger

# Вызываем настройку в самом начале работы приложения
setup_logging()

@logger.catch
def main_logic():
    logger.info("Приложение начинает работу.")
    # ... ваш основной код ...
    a = 10
    b = 0
    result = a / b # Это вызовет ошибку, которую поймает @logger.catch

if __name__ == "__main__":
    main_logic()

Такой подход гарантирует, что логирование будет работать одинаково во всех частях вашего проекта.

2. Интеграция с библиотеками, использующими стандартный logging

Что делать, если вы используете библиотеки (например, requests, SQLAlchemy, uvicorn), которые пишут свои логи через стандартный модуль logging? Loguru может элегантно "перехватить" эти сообщения и направить их в свои обработчики.

Для этого нужно создать специальный класс-обработчик и настроить logging на его использование. Этот код может показаться сложным, но вы можете просто скопировать его в свой конфигурационный файл — он работает как готовый рецепт.

# Добавьте это в ваш app/logging_config.py

import logging

class InterceptHandler(logging.Handler):
    def emit(self, record):
        # Получаем соответствующий уровень loguru
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        # Находим вызывающий код
        frame, depth = logging.currentframe(), 2
        while frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())

# ... внутри функции setup_logging() добавьте эту строку:
def setup_logging():
    # ... предыдущие настройки ...

    # Настраиваем перехват логов из стандартного logging
    logging.basicConfig(handlers=[InterceptHandler()], level=0)
    logger.info("Стандартный logging перехвачен.")

Теперь все сообщения от сторонних библиотек будут проходить через Loguru и записываться в ваши файлы с нужным форматом и правилами ротации.

3. Безопасность прежде всего: осторожно с данными в продакшене!

Функция @logger.catch и logger.exception() с параметром diagnose=True (который включен по умолчанию) — это мощнейший инструмент отладки. Но в продакшене он может стать источником утечки конфиденциальных данных! Он выводит значения всех переменных, а среди них могут оказаться пароли, ключи API, персональные данные пользователей.

Правило для продакшена: всегда отключайте диагностику.

# НЕ ДЕЛАЙТЕ ТАК В ПРОДАКШЕНЕ
@logger.catch
def process_user_data(user, password):
    # ...

# ДЕЛАЙТЕ ТАК В ПРОДАКШЕНЕ
@logger.catch(diagnose=False)
def process_user_data(user, password):
    # ...

То же самое касается и обработки исключений:
logger.opt(exception=True, diagnose=False).error("Произошла ошибка").

4. Потокобезопасность и асинхронность

Хорошая новость: Loguru потокобезопасен "из коробки". Вам не нужно беспокоиться о блокировках при использовании логгера в многопоточных приложениях.

Для высоконагруженных или асинхронных приложений, где операции ввода-вывода (запись на диск) могут блокировать основной поток или event loop, Loguru предлагает параметр enqueue=True.

logger.add("high_load_app.log", enqueue=True)

С этой опцией сообщения сначала помещаются в очередь, а запись на диск происходит в отдельном процессе, не замедляя работу вашего основного приложения.

Следуя этим простым правилам, вы сможете построить надежную, информативную и безопасную систему логирования для проектов любого масштаба.

Домашнее задание: Закрепляем Loguru на практике

Прочитав статью, вы узнали, как сделать логирование в Python удобным и мощным. Теперь давайте применим эти знания на практике! Нажмите на каждую задачу, чтобы раскрыть её условие.

Задача 1: Первая настройка и знакомство

Цель: Убедиться, что Loguru установлен, и научиться выводить базовые сообщения.

  1. Создайте новый Python-файл (например, task_1.py).

  2. Импортируйте logger из библиотеки loguru.

  3. Напишите код, который последовательно выводит в консоль сообщения следующих уровней:

    • DEBUG: "Это сообщение для отладки."

    • INFO: "Приложение успешно запущено."

    • SUCCESS: "Операция выполнена успешно!"

    • WARNING: "Внимание: используется устаревшая версия API."

    • ERROR: "Не удалось подключиться к базе данных."

  4. Запустите скрипт и посмотрите на вывод в консоли. Обратите внимание, какие сообщения были выведены, а какие нет, и почему (вспомните про уровень по умолчанию).

Задача 2: Запись логов в файл с ротацией

Цель: Научиться настраивать запись логов в файл, используя logger.add(), и настроить автоматическую ротацию.

  1. Создайте файл task_2.py.

  2. Настройте логгер так, чтобы он записывал сообщения в файл app_actions.log.

  3. Добавьте в настройку logger.add() следующие параметры:

    • Уровень логирования для файла должен быть INFO и выше.

    • Ротация: новый файл должен создаваться, как только текущий достигнет размера 1 KB (килобайт).

    • Сжатие: старые файлы логов должны сжиматься в формат zip.

  4. Напишите цикл, который 100 раз выводит информационное сообщение (например, logger.info(f"Запись номер {i}")).

  5. Запустите скрипт и проверьте папку с вашим проектом. Вы должны увидеть несколько файлов: текущий app_actions.log и несколько архивов .zip со старыми логами.

Задача 3: Магия отладки с @logger.catch

Цель: Практически применить самую мощную отладочную функцию Loguru для перехвата исключений.

  1. Создайте файл task_3.py.

  2. Напишите функцию divide_numbers(a, b), которая принимает два числа и возвращает результат их деления.

  3. Оберните эту функцию декоратором @logger.catch.

  4. Вызовите вашу функцию с параметрами, которые приведут к ошибке ZeroDivisionError (например, divide_numbers(10, 0)).

  5. Запустите скрипт и изучите вывод в консоли. Обратите внимание, как Loguru показал не только ошибку, но и значения переменных a и b в момент её возникновения.

Задача 4: Создание собственного формата логов

Цель: Научиться кастомизировать формат вывода сообщений для лучшей читаемости.

  1. Создайте файл task_4.py.

  2. Удалите стандартный обработчик с помощью logger.remove().

  3. Добавьте новый обработчик для вывода в консоль (sys.stderr), который будет использовать следующий кастомный формат: {time:HH:mm:ss} | {level.icon} | {message}

    • {time:HH:mm:ss} — время в формате "часы:минуты:секунды".

    • {level.icon} — иконка, соответствующая уровню лога (например, ℹ️ для INFO).

    • {message} — само сообщение.

  4. Выведите несколько сообщений разных уровней (INFO, WARNING, ERROR) и убедитесь, что они отображаются в консоли в вашем новом, лаконичном формате.

Задача 5: Сборка всего вместе — конфигурация для проекта

Цель: Симулировать настройку логирования для реального проекта, вынеся конфигурацию в отдельную функцию.

  1. Создайте файл task_5_config.py. В нём определите функцию configure_logger().

  2. Внутри этой функции настройте два обработчика (sinks):

    • Первый (для консоли): должен выводить сообщения уровня DEBUG и выше, быть цветным и использовать простой формат (например, {level} | {message}).

    • Второй (для файла): должен записывать сообщения уровня WARNING и выше в файл project_warnings.log в формате JSON (serialize=True).

  3. Создайте главный файл task_5_main.py.

  4. В task_5_main.py импортируйте функцию configure_logger() и вызовите её в самом начале.

  5. После вызова конфигурации, напишите код, который генерирует несколько сообщений разных уровней (DEBUG, INFO, WARNING, ERROR).

  6. Запустите task_5_main.py. Убедитесь, что:

    • В консоли отображаются все сообщения, начиная с DEBUG.

    • В файле project_warnings.log появились только сообщения WARNING и ERROR, записанные в формате JSON.

Анонс новых статей, полезные материалы, а так же если в процессе решения возникнут сложности, обсудить их или задать вопрос по статье можно в моём Telegram-сообществе.

Уверен, у вас все получится. Вперед, к практике!

Комментарии (3)


  1. 1024rk
    13.11.2025 11:16

    (Примечание: в статье можно вставить реальный скриншот)

    После публикации вы получите $0.15 на ваш счёт от OpenAI. Не забудьте удалить последний абзац перед публикацией.


    1. enamored_poc Автор
      13.11.2025 11:16

      Я заранее пишу статью!) Расписываю сначала план, а потом начинаю ее заполнять. Я хотел туда поставить картинку но забыл)


      1. 1024rk
        13.11.2025 11:16

        Ага, верим.