Ведение журнала
Программисты Python часто используют print() в своём коде как быстрый и удобный инструмент отладки. Использование системы ведения журнала требует лишь немного больше усилий, но оно намного элегантнее и гибче. Помимо отладки, ведение журнала также может предоставить вам более подробную и структурированную информацию о состоянии и работоспособности вашего приложения.
Обзор
Django использует и расширяет встроенный модуль Python logging для выполнения системного ведения журнала. Этот модуль подробно описан в документации Python; этот раздел предоставляет краткий обзор.
Участники процесса
Настройка ведения журнала Python состоит из четырёх частей:
Журнализаторы
Журнализатор — это точка входа в систему ведения журнала. Каждый журнализатор — это именованный контейнер, в который можно записывать сообщения для обработки.
Журнализатор настроен на уровень журнала. Этот уровень журнала описывает степень важности сообщений, которые будет обрабатывать журнализатор. Python определяет следующие уровни журнала:
-
DEBUG: Информация низкого уровня о системе для целей отладки -
INFO: Общая системная информация -
WARNING: Информация, описывающая незначительную проблему, которая произошла. -
ERROR: Информация, описывающая серьёзную проблему, которая произошла. -
CRITICAL: Информация, описывающая критическую проблему, которая произошла.
Каждое сообщение, записанное в журнализатор, — это Запись журнала. Каждая запись журнала также имеет уровень журнала, указывающий на степень важности этого конкретного сообщения. Запись журнала также может содержать полезные метаданные, описывающие событие, которое регистрируется. Это может включать такие данные, как трассировка стека или код ошибки.
При передаче сообщения в журнализатор уровень журнала сообщения сравнивается с уровнем журнала самого журнализатора. Если уровень журнала сообщения соответствует или превышает уровень журнала журнализатора, сообщение будет подвергнуто дальнейшей обработке. В противном случае сообщение будет проигнорировано.
После того, как журнализатор определил, что сообщение нуждается в обработке, оно передаётся обработчику.
Обработчики
Обработчик — это механизм, определяющий, что происходит с каждым сообщением в журнализаторе. Он описывает определённое поведение ведения журнала, например, запись сообщения на экран, в файл или в сетевой сокет.
Как и журнализаторы, обработчики также имеют уровень журнала. Если уровень журнала записи журнала не соответствует или не превышает уровень обработчика, обработчик проигнорирует сообщение.
Журнализатор может иметь несколько обработчиков, и каждый обработчик может иметь различный уровень журнала. Таким образом, можно предоставлять различные формы уведомлений в зависимости от важности сообщения. Например, вы можете установить один обработчик, который пересылает ERROR и CRITICAL сообщения в службу оповещения, а второй обработчик записывает все сообщения (включая ERROR и CRITICAL сообщения) в файл для последующего анализа.
Фильтры
Фильтр используется для дополнительного управления тем, какие записи журнала передаются от журнализатора к обработчику.
По умолчанию любое сообщение журнала, соответствующее требованиям уровня журнала, будет обработано. Однако, установив фильтр, можно наложить дополнительные критерии на процесс ведения журнала. Например, вы можете установить фильтр, который позволит передавать только ERROR сообщения из определённого источника.
Фильтры также могут использоваться для изменения записи журнала до её вывода. Например, вы можете написать фильтр, который понижает ERROR записи журнала до WARNING записей, если выполнены определённые критерии.
Фильтры могут устанавливаться на журнализаторы или на обработчики; несколько фильтров могут использоваться в цепочке для выполнения нескольких фильтрующих действий.
Форматизаторы
В конечном счёте, запись журнала должна быть представлена в виде текста. Форматизаторы описывают точный формат этого текста. Форматизатор обычно состоит из строки форматирования Python, содержащей Атрибуты записи журнала; однако вы также можете создавать пользовательские форматизаторы для реализации определённого поведения форматирования.
Безопасность
Система ведения журнала обрабатывает потенциально конфиденциальную информацию. Например, запись журнала может содержать информацию о веб-запросе или трассировке стека, а некоторые данные, которые вы собираете в собственных журнализаторах, также могут иметь последствия для безопасности. Вам необходимо убедиться, что вы знаете:
- какая информация собирается
- где она будет храниться
- как она будет передаваться
- кто может к ней получить доступ.
Для управления сбором конфиденциальной информации вы можете явно указать определённую конфиденциальную информацию, которую следует исключить из отчётов об ошибках. Подробнее о том, как фильтровать отчёты об ошибках.
AdminEmailHandler
В контексте безопасности стоит упомянуть встроенный AdminEmailHandler. Если его опция include_html включена, электронное сообщение, которое он отправляет, будет содержать полную трассировку стека, с именами и значениями локальных переменных на каждом уровне стека, а также значениями ваших настроек Django (другими словами, тот же уровень подробностей, что и на веб-странице, когда DEBUG установлен в True).
В целом, не рекомендуется отправлять такую потенциально конфиденциальную информацию по электронной почте. Вместо этого используйте одну из многочисленных сторонних служб, в которые можно отправлять подробные журналы, чтобы получить преимущества нескольких миров — богатую информацию полных трассировок, чёткое управление тем, кто уведомляется и имеет доступ к информации и т.д.
Настройка журналирования
Библиотека журналирования Python предоставляет несколько способов настройки журналирования, от программированного интерфейса до конфигурационных файлов. По умолчанию Django использует формат dictConfig.
Для настройки журналирования используйте LOGGING для определения словаря настроек журналирования. Эти настройки описывают логгеры, обработчики, фильтры и форматировщики, которые вы хотите использовать в вашей настройке журналирования, а также уровни журналов и другие свойства этих компонентов.
По умолчанию, настройка LOGGING объединяется с стандартной конфигурацией журналирования Django с использованием следующей схемы.
Если ключ disable_existing_loggers в словаре LOGGING установлен в значение True (что является значением по умолчанию, если ключ отсутствует), то все логгеры из стандартной конфигурации будут отключены. Отключенные логгеры отличаются от удаленных; логгер по-прежнему существует, но молча отбрасывает все записи, отправленные в него, даже не передавая записи родительскому логгеру. Поэтому следует очень осторожно использовать 'disable_existing_loggers': True; это, вероятно, не то, что вам нужно. Вместо этого можно установить disable_existing_loggers в значение False и переопределить некоторые или все стандартные логгеры; или можно установить LOGGING_CONFIG в значение None и ручно настроить журналирование.
Журналирование настраивается как часть общей функции Django setup(). Таким образом, вы можете быть уверены, что логгеры всегда готовы к использованию в вашем проекте.
Примеры
Полная документация по формату dictConfig — лучший источник информации о словарях конфигурации журналирования. Однако, чтобы дать вам представление о возможностях, вот несколько примеров.
Для начала, вот небольшая конфигурация, которая позволит вам выводить все сообщения журнала в консоль:
settings.pyimport os
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "WARNING",
},
}
Эта конфигурация настраивает родительский root логгер на отправку сообщений с уровнем WARNING и выше в обработчик консоли. Изменив уровень на INFO или DEBUG, вы можете отображать больше сообщений. Это может быть полезно во время разработки.
Далее мы можем добавить более точное журналирование. Вот пример того, как сделать систему журналирования для вывода больше сообщений только из логгера с именем django:
settings.pyimport os
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "WARNING",
},
"loggers": {
"django": {
"handlers": ["console"],
"level": os.getenv("DJANGO_LOG_LEVEL", "INFO"),
"propagate": False,
},
},
}
По умолчанию эта конфигурация отправляет сообщения из логгера django уровня INFO или выше в консоль. Это тот же уровень, что и в стандартной конфигурации Django, за исключением того, что стандартная конфигурация отображает записи журнала только при DEBUG=True. Django не регистрирует много сообщений уровня INFO. Однако с этой конфигурацией вы также можете установить переменную среды DJANGO_LOG_LEVEL=DEBUG, чтобы увидеть весь отладочный журнал Django, который очень подробный, поскольку включает все запросы к базе данных.
Вы не обязаны регистрировать в консоли. Вот конфигурация, которая записывает все журналы из логгера с именем django в локальный файл:
settings.pyLOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"file": {
"level": "DEBUG",
"class": "logging.FileHandler",
"filename": "/path/to/django/debug.log",
},
},
"loggers": {
"django": {
"handlers": ["file"],
"level": "DEBUG",
"propagate": True,
},
},
}
Если вы используете этот пример, убедитесь, что изменили путь 'filename' на расположение, доступное для записи пользователем, который запускает приложение Django.
Наконец, вот пример довольно сложной настройки журналирования:
settings.pyLOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
"filters": {
"special": {
"()": "project.logging.SpecialFilter",
"foo": "bar",
},
"require_debug_true": {
"()": "django.utils.log.RequireDebugTrue",
},
},
"handlers": {
"console": {
"level": "INFO",
"filters": ["require_debug_true"],
"class": "logging.StreamHandler",
"formatter": "simple",
},
"mail_admins": {
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler",
"filters": ["special"],
},
},
"loggers": {
"django": {
"handlers": ["console"],
"propagate": True,
},
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
"myproject.custom": {
"handlers": ["console", "mail_admins"],
"level": "INFO",
"filters": ["special"],
},
},
}
Эта конфигурация журналирования выполняет следующие действия:
- Определяет конфигурацию как в формате 'dictConfig version 1'. В настоящее время это единственный поддерживаемый формат dictConfig.
-
Определяет два форматировщика:
-
simple, который выводит имя уровня журнала (например,DEBUG) и сообщение журнала.Строка
format— это обычная строка форматирования Python, описывающая детали, которые должны выводиться в каждой строке журнала. Полный список деталей, которые можно вывести, можно найти в Объектах форматировщика. -
verbose, который выводит имя уровня журнала, сообщение журнала, а также время, процесс, поток и модуль, генерирующие сообщение журнала.
-
-
Определяет два фильтра:
-
project.logging.SpecialFilter, используя псевдонимspecial. Если этому фильтру требуются дополнительные аргументы, они могут быть предоставлены как дополнительные ключи в словаре конфигурации фильтра. В этом случае аргументуfooбудет присвоено значениеbarпри создании экземпляраSpecialFilter. -
django.utils.log.RequireDebugTrue, который пропускает записи, когдаDEBUGравенTrue.
-
-
Определяет два обработчика:
-
console,StreamHandler, который выводит любое сообщение уровняINFO(или выше) вsys.stderr. Этот обработчик использует формат выводаsimple. -
mail_admins,AdminEmailHandler, который отправляет электронное письмо с любым сообщением уровняERROR(или выше) на адрес сайтаADMINS. Этот обработчик использует фильтрspecial.
-
-
Настраивает три логгера:
-
django, который передает все сообщения в обработчикconsole. -
django.request, который передает все сообщения уровняERRORв обработчикmail_admins. Кроме того, этот логгер помечен как не передающий сообщения. Это означает, что сообщения журнала, записанные вdjango.request, не будут обрабатываться логгеромdjango. -
myproject.custom, который передает все сообщения уровняINFOили выше, которые также проходят фильтрspecial, в два обработчика —consoleиmail_admins. Это означает, что все сообщения уровняINFO(или выше) будут выведены в консоль; сообщения уровняERRORиCRITICALтакже будут выведены по электронной почте.
-
Настройка журналирования вручную
Если вы не хотите использовать формат dictConfig Python для настройки логгера, вы можете указать свою собственную схему конфигурации.
Настройка LOGGING_CONFIG определяет вызываемый объект, который будет использоваться для настройки логгеров Django. По умолчанию он указывает на функцию Python logging.config.dictConfig(). Однако, если вы хотите использовать другой процесс конфигурации, вы можете использовать любой другой вызываемый объект, который принимает один аргумент. Содержимое LOGGING будет передано в качестве значения этого аргумента при настройке журналирования.
Отключение конфигурации журналирования
Если вы не хотите настраивать журналирование вообще (или хотите настроить журналирование вручную), можно установить LOGGING_CONFIG в значение None. Это отключит процесс конфигурации для стандартной конфигурации журналирования Django.
Установка LOGGING_CONFIG в значение None означает только то, что процесс автоматической настройки отключен, а не само журналирование. Если вы отключите процесс конфигурации, Django по-прежнему будет делать вызовы журналирования, возвращаясь к поведению, заданному по умолчанию.
Вот пример, который отключает конфигурацию журналирования Django и затем вручную настраивает журналирование:
settings.pyLOGGING_CONFIG = None import logging.config logging.config.dictConfig(...)
Обратите внимание, что процесс стандартной конфигурации выполняется только один раз после полной загрузки настроек. В отличие от этого, ручная настройка журналирования в вашем файле настроек загрузит вашу конфигурацию журналирования немедленно. Поэтому ваша конфигурация журналирования должна находиться после любых настроек, от которых она зависит.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/topics/logging/