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. Формат файла должен быть таким, как описано в Формат файла конфигурации. Эта функция может быть вызвана несколько раз из приложения, позволяя конечному пользователю выбирать из различных заранее подготовленных конфигураций (если разработчик предоставляет механизм для представления вариантов и загрузки выбранной конфигурации).

Parameters
  • fname – Имя файла, или файлоподобный объект, или экземпляр, производный от RawConfigParser. Если передан экземпляр, производный от RawConfigParser, то он используется как есть. В противном случае инстанцируется Configparser, и конфигурация считывается им из объекта, переданного в fname. Если у этого объекта есть метод readline(), то предполагается, что он является файлоподобным объектом и считывается с помощью read_file(); в противном случае предполагается, что он является именем файла и передается в read().

  • defaults – В этом аргументе можно указать значения по умолчанию, которые будут переданы в ConfigParser.

  • disable_existing_loggers – Если указано False, то регистраторы, существующие на момент выполнения этого вызова, остаются включенными. По умолчанию используется значение True, поскольку это позволяет использовать старое поведение, совместимое с обратным ходом. Это поведение заключается в отключении всех существующих не корневых регистраторов, если они или их предки явно не названы в конфигурации регистрации. :param encoding: Кодировка, используемая для открытия файла, когда fname - это имя файла.

Изменено в версии 3.4: Экземпляр подкласса RawConfigParser теперь принимается в качестве значения для fname. Это облегчает:

  • Использование конфигурационного файла, в котором конфигурация протоколирования является лишь частью общей конфигурации приложения.

  • Использование конфигурации, считанной из файла, а затем измененной использующим приложением (например, на основе параметров командной строки или других аспектов среды выполнения) перед передачей в fileConfig.

Добавлено в версии 3.10: Добавлен параметр encoding.

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, используемые в конфигурации логирования - например, как описано в Объекты, определяемые пользователем. Однако эти же механизмы (импорт callables из пользовательских модулей и вызов их с параметрами из конфигурации) могут быть использованы для вызова любого кода, и по этой причине вы должны относиться к конфигурационным файлам из ненадежных источников с экстремальной осторожностью и убедиться, что ничего плохого не произойдет, если вы загрузите их, прежде чем загружать их на самом деле.

Схема словаря конфигурации

Описание конфигурации протоколирования требует перечисления различных объектов для создания и связей между ними; например, вы можете создать обработчик с именем „console“ и затем сказать, что регистратор с именем „startup“ будет посылать свои сообщения обработчику „console“. Эти объекты не ограничиваются теми, которые предоставляются модулем logging, поскольку вы можете написать свой собственный класс форматера или обработчика. Параметры этих классов также могут включать внешние объекты, такие как sys.stderr. Синтаксис для описания этих объектов и соединений определен в Объектные соединения ниже.

Детали схемы словаря

Словарь, передаваемый в dictConfig(), должен содержать следующие ключи:

  • version - устанавливается в целочисленное значение, представляющее версию схемы. В настоящее время единственным допустимым значением является 1, но наличие этого ключа позволяет схеме развиваться, сохраняя при этом обратную совместимость.

Все остальные ключи необязательны, но если они присутствуют, то интерпретируются так, как описано ниже. Во всех описанных ниже случаях, когда упоминается „configuring dict“, он будет проверяться на наличие специального ключа '()', чтобы узнать, требуется ли пользовательский инстанс. Если да, то для создания экземпляра используется механизм, описанный ниже в Объекты, определяемые пользователем; в противном случае контекст используется для определения того, что нужно инстанцировать.

  • formatters - соответствующее значение будет диктой, в которой каждый ключ - это идентификатор форматера, а каждое значение - диктат, описывающий, как настроить соответствующий экземпляр Formatter.

    В дикте конфигурации ищутся следующие необязательные ключи, которые соответствуют аргументам, переданным для создания объекта Formatter:

    • format

    • datefmt

    • style

    • validate (начиная с версии >=3.8)

    Необязательный ключ class указывает на имя класса форматера (в виде пунктирного имени модуля и класса). Аргументы инстанцирования такие же, как и для Formatter, поэтому этот ключ наиболее полезен для инстанцирования специализированного подкласса Formatter. Например, альтернативный класс может представлять отслеживание исключений в расширенном или сжатом формате. Если ваш форматтер требует других или дополнительных ключей конфигурации, вам следует использовать Объекты, определяемые пользователем.

  • filters - соответствующее значение будет диктой, в которой каждый ключ является идентификатором фильтра, а каждое значение - диктой, описывающей, как настроить соответствующий экземпляр фильтра.

    В конфигурационном дикте ищется ключ name (по умолчанию пустая строка), который используется для создания экземпляра logging.Filter.

  • handlers - соответствующее значение будет диктой, в которой каждый ключ - это id обработчика, а каждое значение - диктант, описывающий, как настроить соответствующий экземпляр обработчика.

    В дикте конфигурации выполняется поиск следующих ключей:

    • 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
    

    обработчик с id console инстанцируется как logging.StreamHandler, используя sys.stdout в качестве базового потока. Обработчик с id file инстанцируется как logging.handlers.RotatingFileHandler с аргументами ключевого слова filename='logconfig.log', maxBytes=1024, backupCount=3.

  • loggers - соответствующее значение будет dict, в котором каждый ключ - это имя логгера, а каждое значение - dict, описывающий, как настроить соответствующий экземпляр логгера.

    В дикте конфигурации выполняется поиск следующих ключей:

    • level (необязательно). Уровень регистратора.

    • propagate (необязательно). Настройка распространения регистратора.

    • filters (необязательно). Список идентификаторов фильтров для этого регистратора.

    • handlers (необязательно). Список идентификаторов обработчиков для этого регистратора.

    Указанные регистраторы будут настроены в соответствии с указанным уровнем, распространением, фильтрами и обработчиками.

  • root - это будет конфигурация для корневого регистратора. Обработка конфигурации будет такой же, как и для любого регистратора, за исключением того, что параметр propagate будет неприменим.

  • incremental - должна ли конфигурация интерпретироваться как инкрементная по отношению к существующей конфигурации. По умолчанию это значение равно False, что означает, что указанная конфигурация заменяет существующую конфигурацию с той же семантикой, которая используется существующим API fileConfig().

    Если указанное значение равно 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 определены три форматера. Первый, с id brief, является стандартным экземпляром logging.Formatter с указанной строкой формата. Второй, с id 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
}

и содержит специальный ключ '()', что означает, что требуется пользовательское инстанцирование. В этом случае будет использована указанная фабрика callable. Если это фактический вызываемый объект, то он будет использован напрямую - в противном случае, если вы укажете строку (как в примере), то фактический вызываемый объект будет найден с помощью обычных механизмов импорта. Вызываемая программа будет вызвана с оставшимися элементами в подсловаре конфигурации в качестве аргументов ключевых слов. В приведенном выше примере предполагается, что вызов вернет форматтер с id custom:

my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)

Ключ '()' был использован в качестве специального ключа, поскольку он не является действительным именем параметра ключевого слова и поэтому не будет конфликтовать с именами аргументов ключевых слов, используемых в вызове. Ключ '()' также служит мнемоникой того, что соответствующее значение является вызываемым.

Доступ к внешним объектам

Бывают случаи, когда конфигурация должна ссылаться на внешние по отношению к ней объекты, например 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 нужно просто указать id объекта соответствующего целевого обработчика, и система разрешит его по id. Однако, если пользователь определяет 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(), если вы устанавливаете вызываемый импорт на конфигуратор экземпляр.

Формат файла конфигурации

Формат конфигурационного файла, понимаемый 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 означает, что все сообщения будут записываться в журнал. Значения уровней eval()uated в контексте пространства имен пакета 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, представляет собой список аргументов конструктора класса обработчика. Обратитесь к конструкторам соответствующих обработчиков или к примерам ниже, чтобы увидеть, как строятся типичные записи. Если значение не указано, по умолчанию оно равно ().

Необязательный элемент kwargs, когда eval()используется в контексте пространства имен пакета logging, является аргументом ключевого слова dict в конструкторе класса обработчика. Если он не указан, то по умолчанию используется значение {}.

[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
datefmt=
style='%'
validate=True
class=logging.Formatter

Аргументы для конфигурации форматера совпадают с ключами в схеме словаря formatters section.

Примечание

Из-за использования eval(), как описано выше, существуют потенциальные риски безопасности, возникающие при использовании listen() для отправки и получения конфигураций через сокеты. Риски ограничены случаями, когда несколько пользователей без взаимного доверия выполняют код на одной машине; для получения дополнительной информации см. документацию listen().

См.также

Модуль logging

Ссылка на API для модуля протоколирования.

Модуль logging.handlers

Полезные обработчики, включенные в модуль протоколирования.

Вернуться на верх