logging.config — Настройка логгеров
Исходный код: Lib/logging/config.py
В этом разделе описывается API для настройки модуля логгирования.
Функции настройки
Следующие функции настраивают модуль логгирования. Они находятся в модуле logging.config. Их использование необязательно — вы можете настроить модуль логгирования, используя эти функции или вызывая функции основного API (определённого в logging) и определяя обработчики, объявленные в logging или logging.handlers.
-
logging.config.dictConfig(config) -
Получает конфигурацию логгирования из словаря. Содержимое этого словаря описано в Схеме словаря конфигурации ниже.
Если при настройке возникает ошибка, эта функция вызовет
ValueError,TypeError,AttributeErrorилиImportErrorс соответствующим сообщением. Ниже приведён (возможно, неполный) список условий, которые вызовут ошибку:- Значение
level, которое не является строкой или является строкой, не соответствующей фактическому уровню логгирования. - Значение
propagateкоторое не является булевым значением. - Идентификатор, которому не соответствует место назначения.
- Несуществующий идентификатор обработчика, обнаруженный во время инкрементального вызова.
- Некорректное имя логгера.
- Невозможность разрешения к внутреннему или внешнему объекту.
Разбор выполняется классом
DictConfigurator, конструктор которого получает словарь, используемый для конфигурации, и имеет методconfigure(). Модульlogging.configимеет вызываемый атрибутdictConfigClass, который изначально установлен в значениеDictConfigurator. Вы можете заменить значениеdictConfigClassна подходящую собственную реализацию.dictConfig()вызываетdictConfigClassс указанным словарем, а затем вызывает методconfigure()возвращённого объекта, чтобы применить конфигурацию:def dictConfig(config): dictConfigClass(config).configure()Например, подкласс
DictConfiguratorможет вызватьDictConfigurator.__init__()в своём__init__(), затем настроить пользовательские префиксы, которые можно будет использовать в последующем вызовеconfigure().dictConfigClassбудет привязано к этому новому подклассу, а затемdictConfig()можно будет вызвать точно так же, как в исходном, не настроенном состоянии.Добавлена в версии 3.2.
- Значение
-
logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=None) -
Читает конфигурацию логгирования из файла в формате
configparser. Формат файла должен соответствовать описанию в Формат файла конфигурации. Эту функцию можно вызывать несколько раз из приложения, что позволяет пользователю выбирать из различных предопределённых конфигураций (если разработчик предоставляет механизм для отображения выбора и загрузки выбранной конфигурации).Будет выброшено исключение
FileNotFoundError, если файл не существует, иRuntimeError, если файл некорректен или пуст.- Параметры:
-
-
fname – Имя файла или объект файла или экземпляр, полученный от
RawConfigParser. Если передан экземпляр, производный отRawConfigParser, он используется как есть. В противном случае создаётся экземплярConfigParser, и конфигурация считывается из объекта, переданного вfname. Если у объекта есть методreadline(), предполагается, что это объект типа «файл», и он считывается с помощьюread_file(); в противном случае предполагается, что это имя файла, и оно передаётся вread(). -
defaults – Значения по умолчанию, которые будут переданы в
ConfigParser. -
disable_existing_loggers – Если задано значение
False, логгеры, которые существуют при этом вызове, остаются включёнными. По умолчанию установленоTrueввиду обратной совместимости. Это поведение отключает любые существующие логгеры, не являющиеся корневым логгером, если они или их предки не указаны явно в конфигурации логгеров. - encoding – Кодировка, используемая для открытия файла, когда fname — имя файла.
-
fname – Имя файла или объект файла или экземпляр, полученный от
Изменено в версии 3.4: Теперь принимается экземпляр подкласса
RawConfigParserв качестве значения дляfname. Это позволяет:- Использование файла конфигурации, где конфигурация логгирования — лишь часть общей конфигурации приложения.
- Использование конфигурации, считанной из файла, и затем модифицированной приложением (например, на основе параметров командной строки или других аспектов среды выполнения) перед передачей в
fileConfig.
Изменено в версии 3.10: Добавлен параметр encoding.
Изменено в версии 3.12: Будет выброшено исключение, если предоставленный файл не существует или некорректен или пуст.
-
logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None) -
Запускает сервер сокетов на указанном порту и прослушивает новые конфигурации. Если порт не указан, используется значение по умолчанию модуля
DEFAULT_LOGGING_CONFIG_PORT. Конфигурации логгирования будут отправлены в формате файла, подходящем для обработкиdictConfig()илиfileConfig(). Возвращает экземплярThread, на котором можно вызватьstart()для запуска сервера иjoin()в случае необходимости. Для остановки сервера вызовитеstopListening().Аргумент
verify, если указан, должен быть вызываемым объектом, который проверяет, являются ли принятые через сокет байты валидными и подлежат обработке. Это можно сделать, зашифровав и/или подписав передаваемые данные через сокет, так что вызываемый объектverifyсможет выполнить проверку подписи и/или дешифрование. Вызываемый объектverifyвызывается с одним аргументом — байтами, полученными через сокет, и должен вернуть байты для обработки илиNone, чтобы указать, что байты следует отбросить. Возвращаемые байты могут быть такими же, как и переданные (например, при выполнении только проверки), или они могут быть совершенно другими (например, при выполнении дешифрования).Чтобы отправить конфигурацию в сокет, прочитайте конфигурационный файл и отправьте его в сокет в виде последовательности байтов, предваряемых четырёхбайтовой строкой длины, упакованной в двоичном формате с использованием
struct.pack('>L', n).Примечание
Поскольку части конфигурации передаются через
eval(), использование этой функции может создать риски безопасности. Хотя функция связывается только с сокетом наlocalhost, и поэтому не принимает подключения от удалённых машин, существуют сценарии, в которых ненадёжный код может выполняться от имени процесса, вызывающегоlisten(). В частности, если процесс, вызывающийlisten(), работает на многопользовательской машине, где пользователи не могут доверять друг другу, злонамеренный пользователь может организовать запуск практически произвольного кода в процессе жертвы, просто подключившись к сокету жертвыlisten()и отправив конфигурацию, которая выполнит любой код, который злоумышленник хочет выполнить в процессе жертвы. Это особенно легко сделать, если используется порт по умолчанию, но не сложно даже при использовании другого порта. Чтобы избежать риска, используйте аргументverifyдляlisten(), чтобы предотвратить применение нераспознанных конфигураций.Изменено в версии 3.4: Добавлен аргумент
verify.Примечание
Если вы хотите отправлять конфигурации слушателю, которые не отключают существующие логгеры, вам необходимо использовать JSON-формат для конфигурации, который будет использовать
dictConfig()для настройки. Этот метод позволяет указатьdisable_existing_loggersкакFalseв отправляемой конфигурации.
Безопасность
Функциональность конфигурации логгирования пытается предложить удобство, и отчасти это достигается возможностью конвертировать текст в конфигурационных файлах в объекты Python, используемые в конфигурации логгирования — например, как описано в Пользовательские объекты. Однако, эти же механизмы (импорт вызываемых объектов из пользовательских модулей и вызов их с параметрами из конфигурации) могут быть использованы для вызова любого кода, по этой причине вы должны относиться к конфигурационным файлам из недоверенных источников с крайней осторожностью и убедиться, что ничего плохого не может произойти при их загрузке, прежде чем действительно загружать их.
Схема словаря конфигурации
Для описания конфигурации ведения журнала требуется перечисление различных объектов для создания и соединений между ними; например, вы можете создать обработчик с именем «консоль», а затем указать, что логикатор с именем «запуск» будет отправлять свои сообщения в обработчик «консоль». Эти объекты не ограничиваются теми, которые предоставляет модуль logging, потому что вы можете написать свой собственный класс форматировщика или обработчика. Параметры этих классов также могут потребовать включения внешних объектов, таких как sys.stderr. Синтаксис для описания этих объектов и соединений определен в Соединения объектов ниже.
Подробности схемы словаря
Словарь, передаваемый в dictConfig(), должен содержать следующие ключи:
- version - должен быть установлен в целое числовое значение, представляющее версию схемы. В настоящее время единственное допустимое значение — 1, но наличие этого ключа позволяет схеме развиваться, сохраняя при этом обратную совместимость.
Все остальные ключи являются необязательными, но если они присутствуют, они будут интерпретироваться, как описано ниже. Во всех случаях ниже, где упоминается «словарь конфигурации», он будет проверен на наличие специального '()' ключа, чтобы увидеть, требуется ли пользовательская инициализация. В таком случае используется механизм, описанный в Пользовательские объекты ниже; в противном случае контекст используется для определения того, что нужно инициализировать.
-
formatters - соответствующее значение будет словарем, в котором каждый ключ — это идентификатор форматировщика, а каждое значение — это словарь, описывающий, как настроить соответствующий
Formatterэкземпляр.В словаре конфигурации ищутся следующие необязательные ключи, которые соответствуют аргументам, передаваемым для создания
Formatterобъекта:formatdatefmtstyle-
validate(с версии >=3.8) -
defaults(с версии >=3.12)
Необязательный ключ
classуказывает имя класса форматировщика (как имя модуля и класса с точкой). Аргументы инициализации такие же, как дляFormatter, поэтому этот ключ наиболее полезен для инициализации настроенного подклассаFormatter. Например, альтернативный класс может отображать трассировки исключений в расширенном или сжатом формате. Если ваш форматировщик требует других или дополнительных ключей конфигурации, вы должны использовать Пользовательские объекты. -
filters - соответствующее значение будет словарем, в котором каждый ключ — это идентификатор фильтра, а каждое значение — это словарь, описывающий, как настроить соответствующий экземпляр Filter.
В словаре конфигурации ищется ключ
name(по умолчанию пустая строка), и он используется для создания экземпляраlogging.Filter. -
handlers - соответствующее значение будет словарем, в котором каждый ключ — это идентификатор обработчика, а каждое значение — это словарь, описывающий, как настроить соответствующий экземпляр Handler.
В словаре конфигурации ищутся следующие ключи:
-
class(обязательно). Это полное квалифицированное имя класса обработчика. -
level(необязательно). Уровень обработчика. -
formatter(необязательно). Идентификатор форматировщика для этого обработчика. -
filters(необязательно). Список идентификаторов фильтров для этого обработчика.Изменено в версии 3.11:
filtersможет принимать экземпляры фильтров помимо идентификаторов.
Все другие ключи передаются как именованные аргументы конструктору обработчика. Например, в фрагменте:
handlers: console: class : logging.StreamHandler formatter: brief level : INFO filters: [allow_foo] stream : ext://sys.stdout file: class : logging.handlers.RotatingFileHandler formatter: precise filename: logconfig.log maxBytes: 1024 backupCount: 3обработчик с идентификатором
consoleинициализируется какlogging.StreamHandler, используяsys.stdoutв качестве базового потока. Обработчик с идентификаторомfileинициализируется какlogging.handlers.RotatingFileHandlerс именованными аргументамиfilename='logconfig.log', maxBytes=1024, backupCount=3. -
-
loggers - соответствующее значение будет словарем, в котором каждый ключ — это имя логикатора, а каждое значение — это словарь, описывающий, как настроить соответствующий экземпляр Logger.
В словаре конфигурации ищутся следующие ключи:
-
level(необязательно). Уровень логикатора. -
propagate(необязательно). Параметр распространения логикатора. -
filters(необязательно). Список идентификаторов фильтров для этого логикатора.Изменено в версии 3.11:
filtersможет принимать экземпляры фильтров помимо идентификаторов. -
handlers(необязательно). Список идентификаторов обработчиков для этого логикатора.
Указанные логикаторы будут настраиваться в соответствии с уровнем, распространением, фильтрами и обработчиками, указанными в них.
-
-
root - это будет конфигурация для корневого логикатора. Обработка конфигурации будет такой же, как для любого логикатора, за исключением того, что параметр
propagateне будет применяться. -
incremental - определяет, должна ли конфигурация интерпретироваться как инкрементальная по отношению к существующей конфигурации. Это значение по умолчанию
False, что означает, что указанная конфигурация заменяет существующую конфигурацию с теми же семантическими значениями, что и в существующем APIfileConfig().Если указанное значение
True, конфигурация обрабатывается, как описано в разделе Инкрементальная конфигурация. -
disable_existing_loggers - определяет, должны ли быть отключены любые существующие логикаторы, не являющиеся корневыми. Этот параметр соответствует параметру с тем же именем в
fileConfig(). Если отсутствует, этот параметр по умолчаниюTrue. Это значение игнорируется, если incrementalTrue.
Инкрементальная конфигурация
Трудно обеспечить полную гибкость инкрементальной конфигурации. Например, поскольку объекты, такие как фильтры и форматировщики, являются анонимными, после настройки конфигурации невозможно сослаться на такие анонимные объекты при дополнении конфигурации.
Кроме того, нет веских причин для произвольного изменения графа объектов логикаторов, обработчиков, фильтров, форматировщиков во время выполнения после настройки конфигурации; уровень подробности логикаторов и обработчиков можно контролировать только с помощью установления уровней (и, в случае с логикаторами, флагов распространения). Произвольное изменение графа объектов безопасным способом в многопоточной среде проблематично; хотя это не невозможно, выгоды не стоят сложности, которую это добавляет в реализацию.
Таким образом, когда ключ incremental словаря конфигурации присутствует и равен True, система полностью проигнорирует любые formatters и filters записи и обработает только level настройки в handlers записях и level и propagate настройки в loggers и root записях.
Использование значения в словаре конфигурации позволяет отправлять конфигурации по сети как закодированные словари в сокет-листенер. Таким образом, уровень подробности ведения журнала долгоживущего приложения можно изменять со временем без необходимости остановки и перезапуска приложения.
Соединения объектов
Схема описывает набор объектов ведения журнала — логикаторы, обработчики, форматировщики, фильтры — которые соединены друг с другом в графе объектов. Таким образом, схема должна представлять соединения между объектами. Например, предположим, что после настройки определённый логикатор прикреплён к определённому обработчику. Для целей этого обсуждения мы можем сказать, что логикатор представляет источник, а обработчик — пункт назначения соединения между ними. Конечно, в настроенных объектах это представлено тем, что логикатор хранит ссылку на обработчик. В словаре конфигурации это делается путём присвоения каждому объекту-получателю уникального идентификатора и последующего использования этого идентификатора в конфигурации объекта-источника для обозначения наличия соединения между объектом-источником и объектом-получателем с этим идентификатором.
Например, рассмотрим следующий фрагмент YAML:
formatters:
brief:
# configuration for formatter with id 'brief' goes here
precise:
# configuration for formatter with id 'precise' goes here
handlers:
h1: #This is an id
# configuration of handler with id 'h1' goes here
formatter: brief
h2: #This is another id
# configuration of handler with id 'h2' goes here
formatter: precise
loggers:
foo.bar.baz:
# other configuration for logger 'foo.bar.baz'
handlers: [h1, h2]
(Примечание: YAML используется здесь, потому что он немного более удобочитаем, чем эквивалентная форма словаря на Python.)
Идентификаторами логикаторов являются имена логикаторов, которые используются программно для получения ссылки на эти логикаторы, например foo.bar.baz. Идентификаторы форматировщиков и фильтров могут быть любыми строковыми значениями (такими как brief, precise выше), и они являются временными, поскольку они имеют смысл только для обработки словаря конфигурации и используются для определения соединений между объектами, и не сохраняются нигде после завершения вызова конфигурации.
Вышеупомянутый фрагмент указывает, что логикатор с именем foo.bar.baz должен иметь два присоединённых к нему обработчика, описанных идентификаторами обработчиков h1 и h2. Форматировщик для h1 — это форматировщик, описанный идентификатором brief, а форматировщик для h2 — это форматировщик, описанный идентификатором precise.
Пользовательские объекты
Схема поддерживает пользовательские объекты для обработчиков, фильтров и форматеров. (Логгерам не нужно иметь разные типы для разных экземпляров, поэтому в этой схеме конфигурации нет поддержки для пользовательских классов логгеров.)
Настраиваемые объекты описываются словарями, которые подробно описывают их конфигурацию. В некоторых местах система логирования сможет определить, как должен быть создан объект из контекста, но когда необходимо создать пользовательский объект, система не будет знать, как это сделать. Для обеспечения полной гибкости при создании пользовательских объектов пользователь должен предоставить «фабрику» — вызываемый объект, который вызывается со словарем конфигурации и возвращает созданный объект. Это обозначается абсолютным импортируемым путем к фабрике, размещенной под специальным ключом '()'. Вот конкретный пример:
formatters:
brief:
format: '%(message)s'
default:
format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
datefmt: '%Y-%m-%d %H:%M:%S'
custom:
(): my.package.customFormatterFactory
bar: baz
spam: 99.9
answer: 42
Вышеприведенный фрагмент YAML определяет три форматера. Первый, с идентификатором brief, является стандартным экземпляром logging.Formatter с указанной строкой формата. Второй, с идентификатором default, имеет более длинный формат и также явно определяет формат времени и приведет к созданию экземпляра logging.Formatter с этими двумя строками формата. В исходном коде Python форматеры brief и default имеют подсловарей конфигурации:
{
'format' : '%(message)s'
}
и:
{
'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
'datefmt' : '%Y-%m-%d %H:%M:%S'
}
соответственно, и так как эти словари не содержат специальный ключ '()', создание экземпляра определяется из контекста: в результате создаются стандартные экземпляры logging.Formatter. Подсловарь конфигурации для третьего форматера с идентификатором custom:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42
}
и в нем содержится специальный ключ '()', что означает, что требуется пользовательское создание экземпляра. В этом случае будет использоваться указанная фабричная вызываемая функция. Если это фактическая вызываемая функция, она будет использоваться непосредственно; в противном случае, если вы укажете строку (как в примере), фактическая вызываемая функция будет найдена с помощью обычных механизмов импорта. Вызываемая функция будет вызвана со всеми оставшимися элементами в подсловаре конфигурации в качестве ключевых аргументов. В приведенном выше примере предполагается, что форматер с идентификатором custom будет возвращен вызовом:
my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)
Предупреждение
Значения для ключей, таких как bar, spam и answer в приведенном выше примере не должны быть словарями конфигурации или ссылками, такими как cfg://foo или ext://bar, так как они не будут обрабатываться механизмом конфигурации, а будут переданы вызываемой функции как есть.
Ключ '()' используется как специальный ключ, потому что он не является допустимым именем ключевого параметра и поэтому не будет конфликтовать с именами ключевых аргументов, используемых в вызове. '()' также служит мнемоникой, что соответствующее значение — это вызываемая функция.
Изменено в версии 3.11: Член filters handlers и loggers может принимать экземпляры фильтров в дополнение к идентификаторам.
Также можно указать специальный ключ '.', значение которого — словарь, представляющий отображение имен атрибутов на значения. Если он найден, указанные атрибуты будут установлены на пользовательском объекте перед его возвращением. Таким образом, при следующей конфигурации:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42,
'.' {
'foo': 'bar',
'baz': 'bozz'
}
}
возвращаемый форматер будет иметь атрибут foo, установленный в 'bar', и атрибут baz установленный в 'bozz'.
Предупреждение
Значения для атрибутов, таких как foo и baz в приведенном выше примере не должны быть словарями конфигурации или ссылками, такими как cfg://foo или ext://bar, так как они не будут обрабатываться механизмом конфигурации, а будут установлены как значения атрибутов как есть.
Порядок конфигурации обработчиков
Обработчики настраиваются в алфавитном порядке их ключей, и настроенный обработчик заменяет словарь конфигурации в (рабочей копии) словаре handlers в схеме. Если вы используете конструкцию, такую как cfg://handlers.foo, то изначально handlers['foo'] указывает на словарь конфигурации для обработчика с именем foo, а позднее (после настройки обработчика) он указывает на экземпляр настроенного обработчика. Таким образом, cfg://handlers.foo может ссылаться либо на словарь, либо на экземпляр обработчика. В общем случае рекомендуется давать имена обработчикам таким образом, чтобы зависимые обработчики настраивались _после_ всех обработчиков, от которых они зависят; это позволяет использовать что-то вроде cfg://handlers.foo для настройки обработчика, который зависит от обработчика foo. Если бы этот зависимый обработчик назывался bar, возникли бы проблемы, потому что попытка настройки bar была бы предпринята до настройки foo, и foo еще не был бы настроен. Однако, если бы зависимый обработчик назывался foobar, он был бы настроен после foo, в результате cfg://handlers.foo сослался бы на настроенный обработчик foo, а не на его словарь конфигурации.
Доступ к внешним объектам
Иногда конфигурация должна ссылаться на объекты, внешние по отношению к конфигурации, например, sys.stderr. Если словарь конфигурации создается с помощью кода Python, это просто, но возникает проблема, когда конфигурация предоставляется через текстовый файл (например, JSON, YAML). В текстовом файле нет стандартного способа отличить sys.stderr от буквальной строки 'sys.stderr'. Для облегчения этого различия система конфигурации ищет определенные специальные префиксы в строковых значениях и обрабатывает их специальным образом. Например, если в качестве значения в конфигурации предоставляется буквальная строка 'ext://sys.stderr', то ext:// будет удалено, а остальная часть значения обработана с помощью обычных механизмов импорта.
Обработка таких префиксов выполняется аналогично обработке протоколов: существует общий механизм поиска префиксов, соответствующих регулярному выражению ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$, в котором, если prefix распознан, suffix обрабатывается в зависимости от префикса, и результат обработки заменяет строковое значение. Если префикс не распознан, то строковое значение останется неизменным.
Доступ к внутренним объектам
Помимо внешних объектов, иногда также необходимо ссылаться на объекты в конфигурации. Система конфигурации будет делать это неявно для объектов, о которых она знает. Например, строковое значение 'DEBUG' для level в логге или обработчике будет автоматически преобразовано в значение logging.DEBUG, а записи handlers, filters и formatter будут принимать идентификатор объекта и перенаправлять его к соответствующему целевому объекту.
Однако для пользовательских объектов, которые не известны модулю logging, нужен более общий механизм. Например, рассмотрим logging.handlers.MemoryHandler, который принимает аргумент target, который является другим обработчиком для делегирования. Поскольку система уже знает об этом классе, то в конфигурации указанный target должен быть просто идентификатором объекта соответствующего целевого обработчика, и система найдет обработчик по этому идентификатору. Однако, если пользователь определяет my.package.MyHandler с обработчиком alternate, система конфигурации не будет знать, что alternate относится к обработчику. Чтобы учесть это, система разрешения общего назначения позволяет пользователю указать:
handlers:
file:
# configuration of file handler goes here
custom:
(): my.package.MyHandler
alternate: cfg://handlers.file
Буквальная строка 'cfg://handlers.file' будет разрешаться аналогично строкам с префиксом ext://, но поиск будет проводиться в самой конфигурации, а не в пространстве импорта. Механизм позволяет получать доступ с помощью точки или по индексу, аналогично тому, что предоставляет str.format. Таким образом, учитывая следующий фрагмент:
handlers:
email:
class: logging.handlers.SMTPHandler
mailhost: localhost
fromaddr: my_app@domain.tld
toaddrs:
- support_team@domain.tld
- dev_team@domain.tld
subject: Houston, we have a problem.
в конфигурации строка 'cfg://handlers' будет перенаправлена на словарь с ключом handlers, строка 'cfg://handlers.email будет перенаправлена на словарь с ключом email в словаре handlers и так далее. Строка 'cfg://handlers.email.toaddrs[1] будет перенаправлена на 'dev_team@domain.tld', а строка 'cfg://handlers.email.toaddrs[0]' будет перенаправлена на значение 'support_team@domain.tld'. К значение subject можно получить, используя либо 'cfg://handlers.email.subject', либо, что эквивалентно, 'cfg://handlers.email[subject]'. Последняя форма требуется только в том случае, если ключ содержит пробелы или неалфавитно-цифровые символы. Если значение индекса состоит только из десятичных цифр, будет выполнена попытка доступа с использованием соответствующего целого значения, в противном случае используется строковое значение.
Учитывая строку cfg://handlers.myhandler.mykey.123, она будет перенаправлена на config_dict['handlers']['myhandler']['mykey']['123']. Если строка указана как cfg://handlers.myhandler.mykey[123], система попытается получить значение из config_dict['handlers']['myhandler']['mykey'][123], и если это не удастся, обратится к config_dict['handlers']['myhandler']['mykey']['123'].
Разрешение импорта и пользовательские импортеры
Разрешение импорта по умолчанию использует встроенную функцию __import__() для выполнения импорта. Вы можете заменить её собственным механизмом импорта: в этом случае вы можете заменить атрибут importer класса DictConfigurator или его суперкласса, класса BaseConfigurator. Однако будьте осторожны из-за того, как функции обращаются к классам через дескрипторы. Если вы используете вызываемый объект Python для выполнения импорта и хотите определить его на уровне класса, а не на уровне экземпляра, вам нужно обернуть его функцией staticmethod(). Например:
from importlib import import_module from logging.config import BaseConfigurator BaseConfigurator.importer = staticmethod(import_module)
Вам не нужно оборачивать функцией staticmethod(), если вы устанавливаете вызываемый объект импорта для экземпляра конфигуратора.
Настройка QueueHandler и QueueListener
Если вы хотите настроить QueueHandler, имея в виду, что это обычно используется совместно с QueueListener, вы можете настроить их вместе. После настройки экземпляр QueueListener будет доступен как атрибут listener созданного обработчика, а тот, в свою очередь, будет доступен вам с помощью getHandlerByName() и указанием имени, которое вы использовали для QueueHandler в вашей конфигурации. Схема словаря для настройки пары показана в примере YAML-фрагмента ниже.
handlers:
qhand:
class: logging.handlers.QueueHandler
queue: my.module.queue_factory
listener: my.package.CustomListener
handlers:
- hand_name_1
- hand_name_2
...
Ключи queue и listener необязательны.
Если ключ queue присутствует, соответствующее значение может быть одним из следующих:
-
Объект, реализующий общедоступный API
queue.Queue. Например, это может быть фактический экземплярqueue.Queueили его подкласс, или прокси, полученный с помощьюmultiprocessing.managers.SyncManager.Queue().Это, конечно, возможно только если вы создаёте или изменяете словарь конфигурации в коде.
- Строка, которая разрешается в вызываемый объект, который, при вызове без аргументов, возвращает экземпляр
queue.Queueдля использования. Этот вызываемый объект может быть подклассомqueue.Queueили функцией, возвращающей подходящий экземпляр очереди, например,my.module.queue_factory(). - Словарь с ключом
'()', который создаётся обычным образом, как описано в Пользовательские объекты. Результатом этого создания должен быть экземплярqueue.Queue.
Если ключ queue отсутствует, создаётся и используется стандартный неограниченный экземпляр queue.Queue.
Если ключ listener присутствует, соответствующее значение может быть одним из следующих:
- Подкласс
logging.handlers.QueueListener. Это, конечно, возможно только если вы создаёте или изменяете словарь конфигурации в коде. - Строка, которая разрешается в класс, являющийся подклассом
QueueListener, например,'my.package.CustomListener'. - Словарь с ключом
'()', который создаётся обычным способом, как описано в Пользовательские объекты. Результатом этого создания должен быть вызываемый объект с той же сигнатурой, что и инициализаторQueueListener.
Если ключ listener отсутствует, используется logging.handlers.QueueListener.
Значения под ключом handlers — это имена других обработчиков в конфигурации (не показанных в приведенном выше фрагменте), которые будут переданы слушателю очереди.
Любые пользовательские классы обработчиков и слушателей очереди должны быть определены с теми же сигнатурами инициализации, что и QueueHandler и QueueListener.
Добавлена в версии 3.12.
Формат файла конфигурации
Формат файла конфигурации, понимаемый fileConfig(), основан на функциональности configparser. Файл должен содержать секции, называемые [loggers], [handlers] и [formatters], которые по имени идентифицируют сущности каждого типа, определенные в файле. Для каждой такой сущности существует отдельная секция, которая определяет, как настраивается эта сущность. Таким образом, для логгера с именем log01 в секции [loggers], соответствующие данные конфигурации хранятся в секции [logger_log01]. Аналогично, обработчик с именем hand01 в секции [handlers] будет иметь свою конфигурацию, хранящуюся в секции [handler_hand01], а форматировщик с именем form01 в секции [formatters] будет иметь свою конфигурацию, заданную в секции [formatter_form01]. Конфигурация корневого логгера должна быть указана в секции [logger_root].
Примечание
API fileConfig() более стар, чем API dictConfig(), и не предоставляет функциональности для покрытия определённых аспектов ведения логов. Например, вы не можете настроить объекты Filter, которые обеспечивают фильтрацию сообщений за пределами простых целочисленных уровней, используя fileConfig(). Если вам нужны экземпляры Filter в вашей конфигурации ведения логов, вам нужно использовать dictConfig(). Обратите внимание, что будущие улучшения функциональности конфигурации будут добавлены в dictConfig(), поэтому стоит рассмотреть переход на этот новый API, когда это удобно.
Примеры этих секций в файле приведены ниже.
[loggers] keys=root,log02,log03,log04,log05,log06,log07 [handlers] keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09 [formatters] keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
Корневой логгер должен указывать уровень и список обработчиков. Пример секции корневого логгера приведен ниже.
[logger_root] level=NOTSET handlers=hand01
Запись level может быть одной из DEBUG, INFO, WARNING, ERROR, CRITICAL или NOTSET. Только для корневого логгера, NOTSET означает, что все сообщения будут записаны в журнал. Значения уровней оцениваются в контексте пространства имён пакета logging.
Запись handlers — это список имён обработчиков, разделённых запятыми, которые должны появиться в секции [handlers] Эти имена должны появляться в секции [handlers] и иметь соответствующие секции в файле конфигурации.
Для логгеров, отличных от корневого логгера, требуется дополнительная информация. Это проиллюстрировано следующим примером.
[logger_parser] level=DEBUG handlers=hand01 propagate=1 qualname=compiler.parser
Записи level и handlers интерпретируются так же, как для корневого логгера, за исключением того, что если уровень не корневого логгера задан как NOTSET, система обращается к логгерам выше по иерархии, чтобы определить эффективный уровень логгера. Запись propagate устанавливается в 1, чтобы указать, что сообщения должны распространяться к обработчикам выше по иерархии логгеров из этого логгера, или в 0, чтобы указать, что сообщения не распространяются к обработчикам выше по иерархии. Запись qualname — это иерархическое имя канала логгера, то есть имя, используемое приложением для получения логгера.
Секции, которые задают конфигурацию обработчика, проиллюстрированы ниже.
[handler_hand01] class=StreamHandler level=NOTSET formatter=form01 args=(sys.stdout,)
Запись class указывает класс обработчика (как определяется eval() в пространстве имён пакета logging). Запись level интерпретируется так же, как для логгеров, а NOTSET означает «записывать всё».
Запись formatter указывает имя ключа форматировщика для этого обработчика. Если пустая, используется форматировщик по умолчанию (logging._defaultFormatter). Если имя задано, оно должно появляться в секции [formatters] и иметь соответствующую секцию в файле конфигурации.
Запись args, при оценке в контексте пространства имён пакета logging, — это список аргументов конструктора для класса обработчика. Обратитесь к конструкторам соответствующих обработчиков или к приведённым ниже примерам, чтобы увидеть, как строятся типичные записи. Если не указано, значение по умолчанию — ().
Необязательная запись kwargs, при оценке в контексте пространства имён пакета logging, — это словарь ключевых аргументов конструктора для класса обработчика. Если не указано, значение по умолчанию — {}.
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')
[handler_hand03]
class=handlers.SocketHandler
level=INFO
formatter=form03
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
[handler_hand04]
class=handlers.DatagramHandler
level=WARN
formatter=form04
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
[handler_hand05]
class=handlers.SysLogHandler
level=ERROR
formatter=form05
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
[handler_hand06]
class=handlers.NTEventLogHandler
level=CRITICAL
formatter=form06
args=('Python Application', '', 'Application')
[handler_hand07]
class=handlers.SMTPHandler
level=WARN
formatter=form07
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
kwargs={'timeout': 10.0}
[handler_hand08]
class=handlers.MemoryHandler
level=NOTSET
formatter=form08
target=
args=(10, ERROR)
[handler_hand09]
class=handlers.HTTPHandler
level=NOTSET
formatter=form09
args=('localhost:9022', '/log', 'GET')
kwargs={'secure': True}
Секции, которые задают конфигурацию форматировщика, типизированы следующим образом.
[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s %(customfield)s
datefmt=
style=%
validate=True
defaults={'customfield': 'defaultvalue'}
class=logging.Formatter
Аргументы для конфигурации форматировщика такие же, как и ключи в схеме словаря секции форматировщиков.
Запись defaults при оценке в контексте пространства имён пакета logging является словарем значений по умолчанию для пользовательских полей форматирования. Если не указано, значение по умолчанию — None.
Примечание
Из-за использования eval(), как описано выше, существуют потенциальные риски безопасности, возникающие при использовании listen() для отправки и получения конфигураций через сокеты. Риски ограничены случаями, когда несколько пользователей без взаимного доверия выполняют код на одной машине; см. документацию listen() для получения дополнительной информации.
См. также
-
Modulelogging -
Справочник по API модуля ведения журнала.
-
Modulelogging.handlers -
Полезные обработчики, включенные в модуль ведения журнала.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/logging.config.html