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: Теперь в качестве значения
fnameпринимается экземпляр подклассаRawConfigParser. Это позволяет:- Использовать файл конфигурации, в котором конфигурация ведения журнала является лишь частью общей конфигурации приложения.
- Использовать конфигурацию, считанную из файла, а затем изменённую приложением (например, с учётом параметров командной строки или других аспектов среды выполнения) перед передачей в
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в отправляемой конфигурации.
-
logging.config.stopListening() -
Останавливает сервер, созданный вызовом
listen(). Обычно эту функцию вызывают перед вызовомjoin()для значения, возвращённогоlisten().
Вопросы безопасности
Функциональность конфигурации ведения журнала призвана обеспечить удобство; отчасти это достигается возможностью преобразовывать текст в файлах конфигурации в объекты Python, используемые при настройке ведения журнала, — например, как описано в разделе Объекты, определённые пользователем. Однако эти же механизмы (импорт вызываемых объектов из определённых пользователем модулей и вызов их с параметрами из конфигурации) можно использовать для выполнения любого кода. Поэтому к файлам конфигурации из ненадёжных источников следует относиться с крайней осторожностью и перед их загрузкой убедиться, что это не приведёт к нежелательным последствиям.
Схема словаря конфигурации
Описание конфигурации журналирования требует перечислить различные создаваемые объекты и связи между ними; например, можно создать обработчик с именем ‘console’, а затем указать, что регистратор с именем ‘startup’ будет отправлять свои сообщения обработчику ‘console’. Эти объекты не ограничиваются объектами, предоставляемыми модулем 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. Это значение игнорируется, если incremental равноTrue.
Инкрементальная конфигурация
Предоставить полную гибкость для инкрементальной конфигурации сложно. Например, поскольку такие объекты, как фильтры и форматировщики, являются анонимными, после настройки конфигурации на них нельзя ссылаться при её дополнении.
Кроме того, после настройки конфигурации нет веских причин произвольно изменять граф объектов регистраторов, обработчиков, фильтров и форматировщиков во время выполнения; управлять подробностью вывода регистраторов и обработчиков можно простым изменением уровней (а для регистраторов — также флагов распространения). Произвольное изменение графа объектов безопасным способом проблематично в многопоточной среде; хотя это и возможно, преимущества не оправдывают усложнения реализации.
Поэтому, если в словаре конфигурации присутствует ключ incremental со значением True, система полностью игнорирует любые записи formatters и filters и обрабатывает только настройки level в записях handlers, а также настройки level и propagate в записях loggers и root.
Значение в словаре конфигурации позволяет передавать конфигурации через сеть в виде сериализованных с помощью pickle словарей обработчику сокета. Таким образом, подробность журналирования долго работающего приложения можно менять со временем без необходимости останавливать и перезапускать приложение.
Связи между объектами
Схема описывает набор объектов журналирования — регистраторов, обработчиков, форматировщиков и фильтров, — связанных друг с другом в граф объектов. Поэтому схема должна представлять связи между объектами. Например, предположим, что после настройки к определённому регистратору подключён определённый обработчик. В рамках этого обсуждения можно считать регистратор источником, а обработчик — получателем связи между ними. Разумеется, в настроенных объектах это представлено ссылкой на обработчик, хранящейся в регистраторе. В словаре конфигурации каждому объекту-получателю присваивается однозначно идентифицирующий его идентификатор, а затем этот идентификатор используется в конфигурации объекта-источника, чтобы указать на наличие связи с объектом-получателем, имеющим такой идентификатор.
Например, рассмотрим следующий фрагмент 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.put_nowaitиQueue.get. Например, это может быть экземплярqueue.Queueили его подкласса либо прокси, полученный с помощьюmultiprocessing.managers.SyncManager.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() и не предоставляет функциональность для настройки некоторых аспектов ведения журнала. Например, с помощью fileConfig() нельзя настроить объекты Filter, позволяющие фильтровать сообщения не только по простым целочисленным уровням. Если в конфигурации ведения журнала необходимо использовать экземпляры 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(), описанным выше, при использовании API listen() для отправки и получения конфигураций через сокеты существуют потенциальные риски безопасности. Эти риски актуальны в ситуациях, когда несколько не доверяющих друг другу пользователей запускают код на одном компьютере; дополнительные сведения см. в документации listen().
См. также
-
Modulelogging -
Справочник API модуля ведения журнала.
-
Modulelogging.handlers -
Полезные обработчики, входящие в модуль ведения журнала.
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/logging.config.html