logging.config — Настройка модуля регистрации событий
Исходный код: Lib/logging/config.py
Этот раздел описывает API для настройки модуля регистрации событий.
1. Функции конфигурации
Следующие функции настраивают модуль регистрации событий. Они расположены в модуле 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) -
Считывает конфигурацию регистрации событий из файла в формате
configparser. Формат файла должен быть таким, как описано в Формат файла конфигурации. Эту функцию можно вызывать несколько раз из приложения, позволяя конечному пользователю выбирать из различных предопределённых конфигураций (если разработчик предоставляет механизм для отображения вариантов и загрузки выбранной конфигурации).Параметры: -
fname – Имя файла или подобный файлу объект, или экземпляр, производный от
RawConfigParser. Если передается экземпляр, производный отRawConfigParser, он используется как есть. В противном случае создается экземплярConfigparser, и конфигурация считывается из объекта, переданного вfname. Если у объекта есть методreadline(), он предполагается файлоподобным объектом и читается с помощьюread_file(); в противном случае предполагается имя файла и передается вread(). - defaults – Параметры по умолчанию, которые будут переданы в ConfigParser, можно указать в этом аргументе.
-
disable_existing_loggers – Если задано значение
False, логгеры, которые существуют во время этого вызова, остаются активными. Значение по умолчаниюTrue, так как это позволяет сохранить старое поведение для обратной совместимости. Это поведение заключается в отключении всех существующих логгеров, если они или их предки не указаны явно в конфигурации регистрации событий.
Изменено в версии 3.4: Теперь в качестве значения для
fnameможно принять экземпляр подклассаRawConfigParser. Это позволяет:- Использовать файл конфигурации, где конфигурация регистрации событий — лишь часть общей конфигурации приложения.
- Использовать конфигурацию, прочитанную из файла, а затем измененную приложением (например, на основе параметров командной строки или других аспектов среды выполнения) перед передачей в
fileConfig.
-
fname – Имя файла или подобный файлу объект, или экземпляр, производный от
-
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().
2. Схема конфигурации словаря
Описание конфигурации логгирования требует перечисления различных объектов, которые нужно создать, и связей между ними; например, вы можете создать обработчик с именем «console» и затем сказать, что логгер с именем «startup» будет отправлять свои сообщения в обработчик «console». Эти объекты не ограничиваются объектами, предоставляемыми модулем logging, так как вы можете написать свой собственный класс форматера или обработчика. Параметры этих классов также могут потребовать включения внешних объектов, таких как sys.stderr. Синтаксис описания этих объектов и связей определён в Связи объектов ниже.
2.1. Подробности схемы словаря
Словарь, переданный dictConfig(), должен содержать следующие ключи:
- version - значение должно быть целым числом, представляющим версию схемы. В настоящее время единственное допустимое значение — 1, но наличие этого ключа позволяет схеме эволюционировать, сохраняя обратную совместимость.
Все остальные ключи необязательны, но если они присутствуют, они будут интерпретированы как описано ниже. Во всех случаях ниже, где упоминается «словарь конфигурации», будет проверено наличие специального ключа '()', чтобы определить, требуется ли пользовательская инициализация. Если это так, используется механизм, описанный в Пользовательские объекты ниже; в противном случае контекст используется для определения того, что нужно инициализировать.
-
formatters - соответствующее значение будет словарем, в котором каждый ключ — идентификатор форматера, а каждое значение — словарь, описывающий, как настроить соответствующий экземпляр
Formatter.В словаре конфигурации ищутся ключи
formatиdatefmt(с значениями по умолчаниюNone) и они используются для построения экземпляраFormatter. -
filters - соответствующее значение будет словарем, в котором каждый ключ — идентификатор фильтра, а каждое значение — словарь, описывающий, как настроить соответствующий экземпляр фильтра.
В словаре конфигурации ищется ключ
name(по умолчанию пустая строка), и он используется для создания экземпляраlogging.Filter. -
handlers - соответствующее значение будет словарем, в котором каждый ключ — идентификатор обработчика, а каждое значение — словарь, описывающий, как настроить соответствующий экземпляр обработчика.
В словаре конфигурации ищутся следующие ключи:
-
class(обязательно). Это полное квалифицированное имя класса обработчика. -
level(необязательно). Уровень обработчика. -
formatter(необязательно). Идентификатор форматера для этого обработчика. -
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(необязательно). Уровень логгера. -
propagate(необязательно). Настройка распространения логгера. -
filters(необязательно). Список идентификаторов фильтров для этого логгера. -
handlers(необязательно). Список идентификаторов обработчиков для этого логгера.
Указанные логгеры будут настраиваться в соответствии с уровнем, распространением, фильтрами и обработчиками, которые указаны.
-
-
root - это будет конфигурация для корневого логгера. Обработка конфигурации будет такой же, как для любого логгера, за исключением того, что настройка
propagateне будет применяться. -
incremental - устанавливает, интерпретируется ли конфигурация как добавление к существующей конфигурации. Значение по умолчанию -
False, что означает, что указанная конфигурация заменяет существующую конфигурацию с такими же семантическими значениями, как и в существующем APIfileConfig().Если указанное значение равно
True, конфигурация обрабатывается, как описано в разделе Инкрементная конфигурация. -
disable_existing_loggers - устанавливает, нужно ли отключать все существующие логгеры. Эта настройка аналогична параметру с таким же именем в
fileConfig(). Если отсутствует, по умолчанию равноTrue. Это значение игнорируется, если incremental равноTrue.
2.2. Инкрементная конфигурация
Сложно обеспечить полную гибкость при инкрементальной настройке. Например, поскольку такие объекты, как фильтры и форматеры, являются анонимными, после настройки конфигурации невозможно сослаться на такие анонимные объекты при дополнении конфигурации.
Кроме того, нет веских причин для произвольного изменения графа объектов логгеров, обработчиков, фильтров, форматеров во время выполнения после настройки конфигурации; уровень подробности логгеров и обработчиков можно контролировать просто установкой уровней (и, в случае с логгерами, флагов распространения). Произвольное изменение графа объектов безопасным способом в многопоточной среде проблематично; хотя это и не невозможно, преимущества не стоят сложности, которую это добавляет к реализации.
Таким образом, когда ключ incremental в словаре конфигурации присутствует и True, система полностью проигнорирует любые formatters и filters записи и обработает только level настройки в handlers записях и level и propagate настройки в loggers и root записях.
Использование значения в словаре конфигурации позволяет отправлять конфигурации по сети в виде сериализованных словарей на сокет-листенер. Таким образом, уровень подробности ведения журнала долго работающего приложения можно изменять со временем без необходимости останавливать и перезапускать приложение.
2.3. Подключения объектов
Схема описывает набор объектов ведения журнала — логгеров, обработчиков, форматеров, фильтров — которые соединены друг с другом в графе объектов. Таким образом, схема должна представлять подключения между объектами. Например, предположим, что после настройки определённый логгер подключен к определённому обработчику. Для целей этого обсуждения мы можем сказать, что логгер представляет источник, а обработчик — место назначения подключения между ними. Конечно, в настроенных объектах это представлено тем, что логгер содержит ссылку на обработчик. В словаре конфигурации это делается путём присвоения каждому целевому объекту уникального идентификатора и затем использования этого идентификатора в конфигурации исходного объекта для указания существования подключения между исходным и целевым объектом с этим идентификатором.
Например, рассмотрим следующий фрагмент 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.
2.4. Пользовательские объекты
Схема поддерживает пользовательские объекты для обработчиков, фильтров и форматеров. (Логгеры не должны иметь разные типы для разных экземпляров, поэтому в этой схеме конфигурации нет поддержки для пользовательских классов логгеров.)
Настраиваемые объекты описываются словарями, которые содержат их настройки. В некоторых местах система ведения журнала сможет определить из контекста, как должен быть создан объект, но когда должен быть создан пользовательский объект, система не будет знать, как это сделать. Для обеспечения полной гибкости при создании пользовательских объектов пользователю необходимо предоставить «фабрику» — вызываемый объект, который вызывается со словарем конфигурации и возвращает созданный объект. Это сигнализируется абсолютным импортным путём к фабрике, доступной по специальному ключу '()'. Вот конкретный пример:
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)
Ключ '()' используется в качестве специального ключа, так как он не является допустимым именем ключевого параметра и, следовательно, не будет конфликтовать с именами ключевых аргументов, используемых в вызове. '()' также служит мнемоникой, что соответствующее значение является вызываемым объектом.
2.5. Доступ к внешним объектам
Иногда конфигурации необходимо ссылаться на объекты, внешние по отношению к конфигурации, например sys.stderr. Если словарь конфигурации создаётся с помощью кода Python, это просто, но возникает проблема, когда конфигурация предоставляется через текстовый файл (например, JSON, YAML). В текстовом файле нет стандартного способа отличить sys.stderr от буквальной строки 'sys.stderr'. Для облегчения этого различия система конфигурации ищет определённые специальные префиксы в строковых значениях и обрабатывает их особым образом. Например, если в качестве значения в конфигурации предоставлена буквальная строка 'ext://sys.stderr', тогда ext:// будет удалён, а оставшаяся часть значения будет обработана с помощью обычных механизмов импорта.
Обработка таких префиксов выполняется аналогично обработке протоколов: существует общий механизм для поиска префиксов, соответствующих регулярному выражению ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$, посредством которого, если prefix распознаётся, suffix обрабатывается способом, зависящим от префикса, и результат обработки заменяет строковое значение. Если префикс не распознаётся, то строковое значение остаётся без изменений.
2.6. Доступ к внутренним объектам
Помимо внешних объектов, иногда также необходимо обратиться к объектам в конфигурации. Это будет неявно сделано системой конфигурации для объектов, о которых она знает. Например, строковое значение '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'], если это не удастся.
2.7. Разрешение импорта и пользовательские импортёры
Разрешение импорта по умолчанию использует встроенную функцию __import__() для выполнения импорта. Возможно, вам потребуется заменить этот механизм импорта собственным: в таком случае вы можете заменить атрибут importer класса DictConfigurator или его суперкласса, класса BaseConfigurator. Однако следует проявлять осторожность, поскольку функции обращаются к классам через дескрипторы. Если вы используете вызываемый объект Python для выполнения импорта и хотите определить его на уровне класса, а не экземпляра, вам необходимо обернуть его с помощью staticmethod(). Например:
from importlib import import_module from logging.config import BaseConfigurator BaseConfigurator.importer = staticmethod(import_module)
Вам не нужно обертывать с помощью staticmethod(), если вы устанавливаете вызываемый объект импорта для экземпляра конфигуратора.
3. Формат файла конфигурации
Формат файла конфигурации, понимаемый 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 , когда eval() оценивается в контексте пространства имен пакета 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')
[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')
Разделы, определяющие конфигурацию форматировщиков, типизируются следующим образом.
[formatter_form01] format=F1 %(asctime)s %(levelname)s %(message)s datefmt= class=logging.Formatter
Запись format — это строка формата в целом, а запись datefmt — строка формата даты/времени, совместимая с strftime(). Если пустая строка, пакет подставляет дату/время в формате ISO8601, что практически эквивалентно указанию строки формата даты '%Y-%m-%d %H:%M:%S'. Формат ISO8601 также указывает миллисекунды, которые добавляются к результату использования вышеуказанной строки формата с разделителем запятой. Пример времени в формате ISO8601 — 2003-01-23 00:29:50,411.
Запись class необязательна. Она указывает имя класса форматировщика (как имя модуля и класса с точками). Этот параметр полезен для создания экземпляра подкласса Formatter. Подклассы Formatter могут представлять отладочные данные исключений в расширенном или сокращённом формате.
Примечание
Из-за использования eval(), как описано выше, существуют потенциальные риски безопасности, которые возникают при использовании listen() для отправки и получения конфигураций через сокеты. Риски ограничены случаями, когда несколько пользователей без взаимного доверия запускают код на одной машине; см. документацию listen() для получения дополнительной информации.
См. также
-
Modulelogging - Ссылка на API модуля ведения журнала.
-
Modulelogging.handlers - Полезные обработчики, включенные в модуль ведения журнала.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.5/library/logging.config.html