Расширяем Python logging: добавляем имя файла и номер строки
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ: логирование с подробностями о файле и строке
Если вам нужно понять, откуда было отправлено сообщение в журнале, прибегните к использованию модуля logging
в Python. Формат сообщений в журнале можно указать следующим образом:
import logging
logging.basicConfig(format='%(asctime)s – %(filename)s:%(lineno)d – %(levelname)s: %(message)s',
datefmt='%d/%m/%Y %H:%M:%S',
level=logging.DEBUG)
logging.debug('Это не та запись в журнале, которую вы ищете')
Такое форматирование позволит получить вывод с указанием имени файла и номера строки:
31/12/9999 23:59:59 – secret_script.py:8 – DEBUG – Это не та запись в журнале, которую вы ищете
Добавление контекста при помощи настройки формата
Для более точной ориентации в месте возникновения сообщения дополните формат логирования именем функции %(funcName)s
:
logging.basicConfig(format='%(asctime)s – %(filename)s:%(lineno)d – %(funcName)s: %(message)s')
Интеллектуальное логирование исключений
Применяйте блоки try-except
и метод logging.getLogger()
для логирования исключений, что упростит процесс отладки:
logger = logging.getLogger(__name__)
try:
risky_operation()
except Exception as e:
logger.error('О, вот и ошибка!', exc_info=True)
Лог будет содержать сведения об исходном файле и строке, где произошло исключение.
Декораторы – наше спасение!
Декораторы позволяют логировать моменты входа в функцию, её окончания и исключения, одновременно фиксируя информацию о файле и строке.
def log_decorator(func):
def wrapper(*args, **kwargs):
logger = logging.getLogger(func.__module__)
logger.debug(f'Входим в функцию: {func.__name__}')
try:
return func(*args, **kwargs)
except Exception as e:
logger.error(f'Произошла ошибка в {func.__name__}', exc_info=True)
raise
finally:
logger.debug(f'Выходим из функции: {func.__name__}')
return wrapper
Добавляем контекст в журнал
Качество журнала зависит от последовательности, ясности и контекста. Контекстные сведения придают записям в журнале большую ценность.
Различаем модули
Если вы логируете процессы в нескольких модулях с подобными именами файлов, используйте уникальные идентификаторы:
logger = logging.getLogger('unique.module.name')
Достоинства PyCharm и Eclipse Pydev
PyCharm и Eclipse Pydev связывают записи в журнале с кодом, упрощая навигацию по выводу.
Тонкая настройка логирования
Для гибкой конфигурации логирования примените дополнительные библиотеки:
import logging
import sys
import os
Повышаем качество отладки
Включаем всех возможных условий для отладки
Для получения максимума информации установите уровень логирования DEBUG
:
logging.basicConfig(level=logging.DEBUG)
Интеллектуальное отключение журналов отладки
Вы можете скрывать отладочные журналы в продакшене, используя следующий подход:
if not os.getenv('DEBUG'):
logging.disable(logging.DEBUG)
Используем logging вместо print
logging
лучше print
, так как он дает больше возможностей для управления и настройки, плюс его можно отключить при необходимости.
Визуализация
Журналирование файлов и строк можно сравнить с расстановкой маяков на железнодорожных путях вашего кода – это поможет легче следить за логическими связями сообщений:
**Файл 1** (train_red.py)
🚇 Функция A – def start_journey():
📍 log.info("Начинаем...") # [train_red.py:2 – Начинаем...]
**Файл 2** (train_blue.py)
🚇 Функция B – def continue_journey():
📍 log.info("Продолжаем...") # [train_blue.py:2 – Продолжаем...]
**Файл 3** (train_green.py)
🚇 Функция C – def end_journey():
📍 log.info("Завершаем...") # [train_green.py:2 – Завершаем...]
Эти "маяки" позволят точно определять местонахождение ваших сообщений в пространстве кода.
Настраиваем систему журналирования
Журналирование можно настраивать в зависимости от потребностей, оптимизируя процесс отладки:
Журналирование со StreamHandler
StreamHandler
перенаправляет события логирования в стандартный вывод, что улучшает доступность логов:
stream_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stream_handler)
Настраиваем формат времени
Вы можете настроить формат даты и времени в журнале, используя параметр datefmt
:
logging.basicConfig(datefmt='%H:%M:%S')
Добавляем контекст
Вы можете расширить контекст ваших сообщений, добавив дополнительные параметры форматирования, такие как %(module)s
, %(pathname)s
, %(threadName)s
.
Упрощаем журналирование с помощью Loguru
Если стандартное журналирование кажется сложным, воспользуйтесь библиотекой Loguru. Она значительно упрощает весь процесс.
Полезные материалы
- Как использовать журналирование — Python 3.12.2 документация – Подробное руководство по модулю журналирования Python.
- Рецепты журналирования — Python 3.12.2 документация – Осмотру рассматриваются продвинутые вопросы журналирования в Python.
- Как добавить пользовательский уровень журналирования в систему журналирования Python – Stack Overflow – Обсуждение по вопросу настройки пользовательских уровней логирования.
- PEP 282 – Система журналирования | peps.python.org – Предложение о введении системы журналирования в Python.
- logging — Система журналирования для Python — Python 3.12.2 документация – Документация по объектам Logger.
- GitHub – Delgan/loguru: Журналирование на Python сделано (невероятно) простым – Ознакомление с Loguru.
- Отслеживание ошибок и мониторинг производительности Python | Sentry – Инструменты Sentinel для отслеживания ошибок и мониторинга производительности в Python.