Ведение журнала
Python-программисты часто используют print() в своём коде в качестве быстрого и удобного инструмента отладки. Использование системы ведения журнала — это лишь немного больше усилий, но она гораздо элегантнее и гибче. Помимо полезности для отладки, ведение журнала также может предоставить вам более — и лучше структурированную — информацию о состоянии и работоспособности вашего приложения.
Обзор
Django использует и расширяет встроенный модуль Python logging для выполнения системного ведения журнала. Этот модуль подробно описан в документации Python; этот раздел предоставляет краткий обзор.
Состав участников
Конфигурация ведения журнала Python состоит из четырёх частей:
Журналисты
Журналист — это точка входа в систему ведения журнала. Каждый журналист — это именованный контейнер, в который можно записывать сообщения для обработки.
Журналист настроен с уровнем журнала. Этот уровень журнала описывает степень важности сообщений, которые будет обрабатывать журналист. Python определяет следующие уровни журнала:
-
DEBUG: Информация низкого уровня о системе для отладки -
INFO: Общая информация о системе -
WARNING: Информация, описывающая незначительную проблему, которая произошла. -
ERROR: Информация, описывающая серьёзную проблему, которая произошла. -
CRITICAL: Информация, описывающая критическую проблему, которая произошла.
Каждое сообщение, которое записывается в журналист, — это Запись журнала. Каждая запись журнала также имеет уровень журнала, указывающий степень важности этого конкретного сообщения. Запись журнала также может содержать полезные метаданные, описывающие событие, которое регистрируется. Это может включать такие детали, как стек вызовов или код ошибки.
Когда сообщению предоставляется журналист, уровень важности сообщения сравнивается с уровнем важности журналиста. Если уровень важности сообщения соответствует или превышает уровень важности самого журналиста, сообщение будет подвергнуто дальнейшей обработке. В противном случае сообщение будет проигнорировано.
После того, как журналист определил, что сообщение необходимо обработать, оно передаётся Обработчику.
Обработчики
Обработчик — это механизм, который определяет, что происходит с каждым сообщением в журналисте. Он описывает определённое поведение ведения журнала, например, запись сообщения на экран, в файл или в сетевой сокет.
Как и журналисты, обработчики также имеют уровень журнала. Если уровень важности записи журнала не соответствует или не превышает уровень обработчика, обработчик проигнорирует сообщение.
Журналист может иметь несколько обработчиков, и каждый обработчик может иметь разный уровень журнала. Таким образом, можно предоставить различные формы уведомлений в зависимости от важности сообщения. Например, можно установить один обработчик, который перенаправляет сообщения ERROR и CRITICAL в службу уведомлений, в то время как второй обработчик записывает все сообщения (включая сообщения ERROR и CRITICAL) в файл для последующего анализа.
Фильтры
Фильтр используется для дополнительного управления тем, какие записи журнала передаются из журналиста обработчику.
По умолчанию любое сообщение журнала, соответствующее требованиям уровня важности, будет обработано. Однако при установке фильтра можно установить дополнительные критерии для процесса ведения журнала. Например, можно установить фильтр, который пропускает только сообщения ERROR из определённого источника.
Фильтры также могут использоваться для модификации записи журнала перед выводом. Например, можно написать фильтр, который понижает сообщения ERROR до уровня WARNING если выполнены определённые условия.
Фильтры могут быть установлены на журналистах или на обработчиках; несколько фильтров могут использоваться в цепочке для выполнения нескольких действий фильтрации.
Форматировщики
В конечном счёте, запись журнала должна быть представлена в виде текста. Форматировщики описывают точный формат этого текста. Форматировщик обычно состоит из строки форматирования Python, содержащей атрибуты LogRecord; однако вы также можете написать собственные форматировщики для реализации специфического поведения форматирования.
Безопасность
Система ведения журнала обрабатывает потенциально конфиденциальную информацию. Например, запись журнала может содержать информацию о веб-запросе или стеке вызовов, а также некоторые данные, которые вы собираете в собственных журналистах, также могут иметь последствия для безопасности. Вам нужно убедиться, что вы знаете:
- какая информация собирается
- где она будет храниться
- как она будет передаваться
- кто может к ней получить доступ.
Чтобы контролировать сбор конфиденциальной информации, вы можете явно указать определённую конфиденциальную информацию, которая будет исключена из отчётов об ошибках — прочтите больше о том, как фильтровать отчёты об ошибках.
AdminEmailHandler
Встроенный AdminEmailHandler заслуживает упоминания в контексте безопасности. Если включён его параметр include_html, отправляемое им электронное сообщение будет содержать полный стек вызовов с именами и значениями локальных переменных на каждом уровне стека, а также значениями настроек Django (иными словами, такой же уровень детализации, который показан на веб-странице, когда DEBUG имеет значение True).
В общем случае не рекомендуется отправлять такую потенциально конфиденциальную информацию по электронной почте. Вместо этого используйте одну из многочисленных сторонних служб, в которые можно отправлять подробные журналы, чтобы получить лучшее из обоих миров — богатую информацию полных стеков вызовов, чёткий контроль над тем, кто уведомляется и имеет доступ к информации, и так далее.
Настройка ведения журнала
Библиотека ведения журнала Python предоставляет несколько методов настройки ведения журнала, начиная от программного интерфейса и заканчивая конфигурационными файлами. По умолчанию Django использует формат dictConfig.
Для настройки ведения журнала используйте LOGGING для определения словаря настроек ведения журнала. Эти настройки описывают журналистов, обработчики, фильтры и форматировщики, которые вы хотите в своей настройке ведения журнала, а также уровни важности и другие свойства, которые вы хотите для этих компонентов.
По умолчанию настройка LOGGING объединяется с стандартной конфигурацией ведения журнала Django с помощью следующего механизма.
Если ключ disable_existing_loggers в словаре LOGGING установлен в True (это значение dictConfig по умолчанию, если ключ отсутствует), то все журналисты из стандартной конфигурации будут отключены. Отключенные журналисты не являются удалёнными; журналист по-прежнему существует, но молча игнорирует всё, что записывается в него, не передавая даже записи родительскому журналисту. Поэтому следует очень осторожно использовать 'disable_existing_loggers': True; скорее всего, это не то, что вам нужно. Вместо этого вы можете установить disable_existing_loggers в False и переопределить некоторые или все стандартные журналисты; или вы можете установить LOGGING_CONFIG в None и сами обработать конфигурацию ведения журнала.
Ведение журнала настраивается как часть общей функции Django setup(). Поэтому вы можете быть уверены, что журналисты всегда готовы к использованию в вашем проекте.
Примеры
Полная документация для dictConfig format — лучший источник информации о словарях конфигурации ведения журнала. Однако, чтобы вы имели представление о возможностях, вот несколько примеров.
Начнём с небольшой конфигурации, которая позволит выводить все сообщения журнала в консоль:
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(...)
Обратите внимание, что процесс настройки по умолчанию вызывает LOGGING_CONFIG только один раз после полной загрузки настроек. В отличие от этого, ручная настройка ведения журнала в файле настроек загрузит вашу конфигурацию ведения журнала немедленно. Поэтому ваша конфигурация ведения журнала должна появляться после любых настроек, от которых она зависит.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.1/topics/logging/