Ведение журнала
Программисты 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 — лучший источник информации о словарях конфигурации ведения журнала. Тем не менее, чтобы дать вам представление о возможностях, здесь представлены несколько примеров.
Для начала вот небольшая конфигурация, которая позволит выводить все сообщения журнала в консоль:
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.0/topics/logging/