Логгирование¶
См.также
Как вести журнал
Программисты Python часто используют print() в своем коде как быстрый и удобный инструмент отладки. Использование структуры ведения журналов требует лишь немного больше усилий, но гораздо более элегантно и гибко. Помимо того, что ведение журнала полезно для отладки, оно также может предоставить вам больше — и лучше структурированную — информацию о состоянии и работоспособности вашего приложения.
Обзор¶
Django использует и расширяет встроенный модуль Python logging для ведения журнала системы. Этот модуль подробно обсуждается в документации Python; в этом разделе представлен краткий обзор.
Действующие лица¶
Конфигурация логгирования в Python состоит из четырех частей:
Loggers(Логгеры)¶
регистратор — это точка входа в систему журналирования. Каждый регистратор представляет собой именованную корзину, в которую могут записываться сообщения для обработки.
У каждого логгера есть уровень логгирования (log level). Уровень логгирования указывает важность принимаемых сообщений. Python определяет следующие уровни логгирования:
DEBUG: Низкий уровень логгирования системной информации для последующего использования в отладкеINFO: Общая системная информацияWARNING: Информация о мелких проблемах возникших при работе приложенияERROR: Информация об ошибках возникших при работе приложенияCRITICAL: Информация о критических ошибках
Каждое сообщение записанное в логгер называется Log Record(Запись). Каждая запись содержит уровень логгирования, который указывает важность сообщения. Сообщение также может содержать метаданные, которые описывают произошедшее событие. Метаданные могут содержать код ошибки или отладочную информацию.
Когда сообщение передается в логгер, уровень логгирования сообщения сравнивается с уровнем логгирования логгера. Если уровень логгирования сообщения равен или выше уровню логгирования логгера, сообщение будет обработано, иначе - проигнорировано.
После того, как логгер принял сообщение на обработку, оно передается в Handler(Обработчик).
Handlers(Обработчики)¶
Обработчик — это механизм, который определяет, что происходит с каждым сообщением в журнале. Он описывает конкретное поведение при ведении журнала, например, запись сообщения на экран, в файл или в сетевой сокет.
Как и логгеры, обработчики имеют уровень логгирования. Если уровень логгирования сообщения ниже уровня логгирования обработчика, сообщение будет проигнорировано.
Логгер может содержать несколько обработчиков, которые могут иметь различный уровень логгирования. Это позволяет обрабатывать сообщения в соответствии с их уровнем важности. Например, вы можете установить обработчик для ERROR и CRITICAL сообщений, который будет отправлять через какой-то сервер сообщений, и в то же время обработчик записывающий все сообщения (включая ERROR и CRITICAL) в файл.
Фильтры¶
Фильтр используется для обеспечения дополнительного контроля над тем, какие записи журнала передаются от средства ведения журнала к обработчику.
По умолчанию все сообщения, прошедшие проверку уровня логгирования, будут переданы в обработчик. Добавив фильтры вы можете определить дополнительные правила проверки при обработке сообщений. Например, вы можете добавить фильтр, который позволяет обрабатывать ERROR сообщения отправленные определенным источником.
Фильтры также могу изменить сообщение. Например, вы можете создать фильтр, который изменяет уровень логгирования определенных сообщения с ERROR на WARNING.
Фильтр могут быть добавлены к логгеру или обработчику, можно использовать несколько фильтров.
Formatters(Форматер)¶
В конечном итоге запись журнала должна быть отображена в виде текста. Форматеры описывают точный формат этого текста. Средство форматирования обычно состоит из строки форматирования Python, содержащей атрибуты LogRecord <python:logrecord-attributes>`; однако вы также можете написать собственные средства форматирования для реализации определенного поведения форматирования.
Последствия для безопасности¶
Система журналирования обрабатывает потенциально конфиденциальную информацию. Например, запись журнала может содержать информацию о веб-запросе или трассировке стека, а некоторые данные, которые вы собираете в своих собственных средствах ведения журнала, также могут иметь последствия для безопасности. Вы должны быть уверены, что знаете:
какая информация собирается
где он будет впоследствии храниться
как это будет перенесено
кто может иметь к нему доступ.
Чтобы контролировать сбор конфиденциальной информации, вы можете явно указать, что определенная конфиденциальная информация должна быть отфильтрована из отчетов об ошибках. Узнайте больше о том, как фильтровать отчеты об ошибках.
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.py¶import os
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "WARNING",
},
}
Это настраивает родительский корневой регистратор для отправки сообщений с уровнем WARNING и выше обработчику консоли. Установив уровень «INFO» или «DEBUG», вы можете отображать больше сообщений. Это может быть полезно во время разработки.
Далее мы можем добавить более детальное ведение журнала. Вот пример того, как заставить систему журналирования печатать больше сообщений только из Джанго с именем logger:
settings.py¶import 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, которые очень подробны, поскольку включают в себя все запросы к базе данных.
Вам не нужно входить в консоль. Вот конфигурация, которая записывает все журналы из Джанго с именем logger в локальный файл:
settings.py¶LOGGING = {
"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,
},
},
}
При использовании этого примера убедитесь, что пользователь, от которого запускается Django приложение, имеет права на запись файла, указанного в 'filename'.
Наконец, здесь показан пример достаточно сложной конфигурации журналирования:
settings.py¶LOGGING = {
"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 версия 1“. На данный момент это единственная версия dictConfig формата.
Определяет два форматера:
simple, просто возвращает уровень логгирования сообщения (например,DEBUG) и содержимое сообщения.Строка format является обычной строкой форматирования Python, описывающая детали, которые будут присутствовать в каждой строке журнала. Полный список переменных для форматирования вы можете найти в документации.
verbose, выведет уровень логгирования, сообщение, время, название процесса, потока и модуля, который создал сообщение.
Определяет два фильтра:
project.logging.SpecialFilterс названиемspecial. Если конструктор фильтра требует наличия дополнительных аргументов, вы можете указать их в словаре настройки фильтра. В этом случае будет передан аргументfooсо значениемbarпри создании экземпляраSpecialFilter.django.utils.log.RequireDebugTrue– пропускает записи только в случае когда параметр конфигурацииDEBUGравен True.
Определяет два обработчика:
console, StreamHandler, который перенаправляет все сообщения уровняDEBUG(и выше) в stderr. Этот обработчик использует формат simple.mail_admins,AdminEmailHandler, который отправляет по электронной почте любое сообщениеERROR(или выше) на сайтADMINS. Этот обработчик использует специальный фильтр.
Настраивает три логгера:
django, который перенаправляет все сообщения в обработчикconsole.django.request, который передает все сообщения уровняERRORв обработчикmail_admins. Также указывается, что логгер не должен передавать сообщения родительским логгерам. Это означает что сообщения переданные вdjango.requestне будут обрабатываться логгеромdjango.myproject.custom, который передает все сообщения уровняINFOи выше прошедшие фильтрspecialв два обработчика –consoleиmail_admins. Это означает что все сообщения уровняINFO(или выше) будут отправлены в консоль, сообщенияERRORиCRITICALбудут отосланы через e-mail.
Собственная конфигурация логгирования¶
Если вы не хотите использовать формат dictConfig для настройки логгирования, вы можете определить собственный формат.
Параметр LOGGING_CONFIG определяет вызываемый объект, который будет использоваться для настройки регистраторов Django. По умолчанию он указывает на функцию Python logging.config.dictConfig(). Однако если вы хотите использовать другой процесс настройки, вы можете использовать любой другой вызываемый объект, который принимает один аргумент. Содержимое LOGGING будет предоставлено как значение этого аргумента при настройке ведения журнала.
Отключение настройки логгирования¶
Если вы вообще не хотите настраивать ведение журнала (или хотите настроить ведение журнала вручную, используя свой собственный подход), вы можете установить для LOGGING_CONFIG значение None. Это отключит процесс настройки Django ведения журнала по умолчанию.
Установка LOGGING_CONFIG в None только означает, что процесс автоматической настройки отключен, это не влияет на само журналирование. Если вы отключите процесс конфигурации, Django все равно будет вызывать методы журналирования, используя поведение логгеров, настроенное по умолчанию.
Вот пример, который отключает конфигурацию ведения журнала Django, а затем настраивает ведение журнала вручную:
settings.py¶LOGGING_CONFIG = None
import logging.config
logging.config.dictConfig(...)
Обратите внимание, что процесс настройки по умолчанию вызывает LOGGING_CONFIG только после полной загрузки настроек. Напротив, настройка ведения журнала вручную в файле настроек приведет к немедленной загрузке конфигурации ведения журнала. Таким образом, ваша конфигурация ведения журнала должна появиться после любых настроек, от которых она зависит.