Ведение журнала
Программисты 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/4.2/topics/logging/