logging.config — Настройка модуля логгирования
Исходный код: Lib/logging/config.py
В этом разделе описывается API для настройки модуля логгирования.
Функции настройки
Следующие функции настраивают модуль логгирования. Они находятся в модуле logging.config. Их использование необязательно — вы можете настроить модуль логгирования с помощью этих функций или вызовами основного API (определенного в logging) и определением обработчиков, объявленных в logging или logging.handlers.
-
logging.config.dictConfig(config) -
Принимает конфигурацию логгирования из словаря. Содержимое этого словаря описано в Схеме словаря конфигурации ниже.
Если при настройке возникает ошибка, эта функция вызовет
ValueError,TypeError,AttributeErrorилиImportErrorс соответствующим сообщением об ошибке. Ниже приведен (возможно, неполный) список условий, которые приведут к ошибке:- Значение уровня логгирования, которое не является строкой или строкой, не соответствующей фактическому уровню логгирования.
- Значение параметра, которое не является булевым.
- Идентификатор, которому не соответствует целевое место назначения.
- Несуществующий идентификатор обработчика, обнаруженный во время пошагового вызова.
- Неверно указанное имя логгера.
- Невозможность разрешения на внутренний или внешний объект.
Разбор выполняется классом
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 - соответствующее значение будет словарем, в котором каждый ключ — это идентификатор фильтра, а каждое значение — это словарь, описывающий, как настроить соответствующий экземпляр
logging.Filter.В словаре конфигурации ищется ключ
name(по умолчанию пустая строка), который используется для создания экземпляраlogging.Filter. -
handlers - соответствующее значение будет словарем, в котором каждый ключ — это идентификатор обработчика, а каждое значение — это словарь, описывающий, как настроить соответствующий экземпляр
classобъекта.В словаре конфигурации ищутся следующие ключи:
-
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 - соответствующее значение будет словарем, в котором каждый ключ — это имя логгера, а каждое значение — это словарь, описывающий, как настроить соответствующий экземпляр
levelобъекта.В словаре конфигурации ищутся следующие ключи:
-
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.
Использование значения в словаре конфигурации позволяет отправлять конфигурации по каналу связи в виде закодированных словарей в сокет-листенер. Таким образом, уровень подробности ведения журнала долгоживущего приложения можно изменять со временем без необходимости остановки и перезапуска приложения.
Связи объектов
Схема описывает набор объектов ведения журнала — логгеры, обработчики, форматировщики, фильтры — которые связаны друг с другом в графической структуре. Таким образом, схема должна представлять связи между объектами. Например, предположим, что после настройки определённый логгер присоединён к определённому обработчику. Для целей этого обсуждения мы можем сказать, что логгер представляет источник, а обработчик — место назначения связи между ними. Конечно, в настроенных объектах это представляется тем, что логгер хранит ссылку на обработчик. В словаре конфигурации это делается путём присвоения каждому объекту-получателю уникального идентификатора, а затем использования идентификатора в конфигурации объекта-источника, чтобы указать, что существует связь между объектом-источником и объектом-получателем с этим идентификатором.
Например, рассмотрите следующий фрагмент 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() и не предоставляет функциональности для покрытия определенных аспектов ведения логов. Например, вы не можете настроить объекты 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.13/library/logging.config.html