logging.config — Настройка логирования

Исходный код: Lib/logging/config.py


В этом разделе описывается API для настройки модуля logging.

Функции конфигурации

Следующие функции настраивают модуль logging. Они расположены в модуле logging.config. Их использование не является обязательным — вы можете настроить модуль logging с помощью данных функций или путём вызова основного API (определенного в самом logging) и определения обработчиков, которые объявлены либо в logging, либо в logging.handlers.

logging.config.dictConfig(config)

Получает конфигурацию логирования из словаря. Содержание словаря описано в Схема словаря настройки ниже.

Если во время настройки обнаружена ошибка, функция вызовет ValueError, TypeError, AttributeError или ImportError с соответствующим описательным сообщением. Ниже приводится (возможно, неполный) список условий, при которых возникает ошибка:

  • level, который не является строкой или является строкой, не соответствующей фактическому уровню логирования.
  • Значение propagate, не являющееся логическим.
  • id, не имеющий соответствующего назначения.
  • Несуществующий id обработчика, обнаруженный во время инкрементного вызова.
  • Недопустимое имя логгера.
  • Неспособность разрешить внутренний или внешний объект.

Парсинг выполняется классом 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, потому что разрешает старое поведение обратно-совместимым способом. Это поведение отключит любые существующие не root логгеры, если они или их предки явно названы в конфигурации логирования.

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

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

Схема словаря настройки

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

Подробная информация о схеме словаря

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

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

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

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

    В конфигурационном dict ищутся ключи format и datefmt (со значениями по умолчанию None), и они используются для создания экземпляра Formatter.

    Изменено в версии 3.8: Ключ validate (по умолчанию True) можно добавить в раздел formatters конфигурационного dict, это необходимо для проверки формата.

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

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

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

    В конфигурационном dict ищутся следующие ключи:

    • 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 — соответствующее значение dict, в котором каждый ключ является именем логгера, а каждое значение dict описывает настройку соответствующего Logger экземпляра.

    В конфигурационном dict ищутся следующие ключи:

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

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

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

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

    Если заданное значение — True, конфигурация обрабатывается, как описано в разделе Инкрементальная конфигурация.

  • disable_existing_loggers — нужно ли отключить какие-либо существующие не корневые логгеры. Данный параметр отражает одноимённый параметр в fileConfig(). В случае отсутствия этот параметр по умолчанию равен True. Значение игнорируется, если incrementalTrue.

Инкрементальная конфигурация

Трудно обеспечить полную гибкость для инкрементной конфигурации. Например, поскольку такие объекты, как фильтры и форматтеры, являются анонимными, после настройки конфигурации невозможно ссылаться на такие анонимные объекты при расширении конфигурации.

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

Таким образом, когда присутствует ключ incremental в конфигурационном dict и он равен True, система полностью игнорирует любые записи formatters и filters и обрабатывает только level настройки в записях handlers и настройки level и propagate в настройках loggers и root записи.

Использование значения в конфигурационном dict позволяет отправлять конфигурации по сети в виде пикленных (pickled) dicts в прослушиватель сокета. Таким образом, подробность логирования долго работающего приложения может изменяться с течением времени без необходимости останавливать и перезапускать приложение.

Связи объектов

Схема описывает множество объектов логирования: логгеры, обработчики, форматтеры, фильтры — которые связаны друг с другом в графе объектов. Таким образом, схема должна представлять связи между объектами. Например, предположим, что после настройки конкретный логгер прикрепил к нему определённый обработчик. Для целей этого обсуждения мы можем сказать, что логгер представляет источник, а обработчик — назначение соединения между ними. Конечно, в настроенных объектах это представлено логгером, содержащим ссылку на обработчик. В dict конфигурации это делается путём присвоения каждому объекту назначения идентификатора, который однозначно его идентифицирует, а затем использования идентификатора в конфигурации исходного объекта, чтобы указать, что существует соединение между источником и объектом назначения с таким идентификатором.

Так, например, рассмотрим следующий фрагмент YAML:

formatters:
  brief:
    # здесь приведена конфигурация для форматтера с идентификатором "brief"
  precise:
    # здесь приведена конфигурация для форматтера с идентификатором "precise"
handlers:
  h1: # это другой идентификатор
   # здесь производится настройка обработчика с идентификатором "h1"
   formatter: brief
  h2: # это другой идентификатор
   # здесь производится настройка обработчика с идентификатором "h2"
   formatter: precise
loggers:
  foo.bar.baz:
    # другая конфигурация для логгера '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 инициализируется этими двумя строками формата. У форматеров brief и default, представленных в виде исходного кода Python, есть подкаталоги конфигурации:

{
  '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)

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

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

Бывают случаи, когда конфигурация должна ссылаться на объекты, внешние по отношению к конфигурации, например sys.stderr. Если конфигурационный dict создаётся с использованием кода 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:
    # здесь находится конфигурация обработчика файлов

  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' будет разрешена в dict с ключом handlers, строка 'cfg://handlers.email будет преобразована в dict с ключом email в dict 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()уируются в контексте пространства имён пакета 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=
class=logging.Formatter

Запись format — строка общего формата, а запись datefmt — строка strftime()-совместимого формата даты/времени. Если пусто, пакет заменяет чем-то, что почти эквивалентно указанию строки формата даты '%Y-%m-%d %H:%M:%S'. Формат также определяет миллисекунды, которые добавляются к результату использования указанной выше строки формата с разделителем запятой. Пример времени в этом формате — 2003-01-23 00:29:50,411.

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

Примечание

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

См.также

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