Spec-Zone.ru › Python 3.12

logging.config — Настройка логгеров

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

Важно

Эта страница содержит только справочную информацию. Для учебных пособий, пожалуйста, см.

  • Базовый учебник
  • Расширенный учебник
  • Справочник по логгированию

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

Функции настройки

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

logging.config.dictConfig(config)

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

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

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

Разбор выполняется классом DictConfigurator, конструктор которого получает словарь, используемый для конфигурации, и имеет метод configure(). Модуль logging.config имеет вызываемый атрибут dictConfigClass, который изначально установлен в значение DictConfigurator. Вы можете заменить значение dictConfigClass на подходящую собственную реализацию.

dictConfig() вызывает dictConfigClass с указанным словарем, а затем вызывает метод configure() возвращённого объекта, чтобы применить конфигурацию:

def dictConfig(config):
    dictConfigClass(config).configure()

Например, подкласс DictConfigurator может вызвать DictConfigurator.__init__() в своём __init__(), затем настроить пользовательские префиксы, которые можно будет использовать в последующем вызове configure(). dictConfigClass будет привязано к этому новому подклассу, а затем dictConfig() можно будет вызвать точно так же, как в исходном, не настроенном состоянии.

Добавлена в версии 3.2.

logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=None)

Читает конфигурацию логгирования из файла в формате configparser. Формат файла должен соответствовать описанию в Формат файла конфигурации. Эту функцию можно вызывать несколько раз из приложения, что позволяет пользователю выбирать из различных предопределённых конфигураций (если разработчик предоставляет механизм для отображения выбора и загрузки выбранной конфигурации).

Будет выброшено исключение FileNotFoundError, если файл не существует, и RuntimeError, если файл некорректен или пуст.

Параметры:
  • fname – Имя файла или объект файла или экземпляр, полученный от RawConfigParser. Если передан экземпляр, производный от RawConfigParser, он используется как есть. В противном случае создаётся экземпляр ConfigParser, и конфигурация считывается из объекта, переданного в fname. Если у объекта есть метод readline(), предполагается, что это объект типа «файл», и он считывается с помощью read_file(); в противном случае предполагается, что это имя файла, и оно передаётся в read().
  • defaults – Значения по умолчанию, которые будут переданы в ConfigParser.
  • disable_existing_loggers – Если задано значение False, логгеры, которые существуют при этом вызове, остаются включёнными. По умолчанию установлено True ввиду обратной совместимости. Это поведение отключает любые существующие логгеры, не являющиеся корневым логгером, если они или их предки не указаны явно в конфигурации логгеров.
  • encoding – Кодировка, используемая для открытия файла, когда fname — имя файла.

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

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

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

Изменено в версии 3.12: Будет выброшено исключение, если предоставленный файл не существует или некорректен или пуст.

logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)

Запускает сервер сокетов на указанном порту и прослушивает новые конфигурации. Если порт не указан, используется значение по умолчанию модуля DEFAULT_LOGGING_CONFIG_PORT. Конфигурации логгирования будут отправлены в формате файла, подходящем для обработки dictConfig() или fileConfig(). Возвращает экземпляр Thread, на котором можно вызвать start() для запуска сервера и join() в случае необходимости. Для остановки сервера вызовите stopListening().

Аргумент verify, если указан, должен быть вызываемым объектом, который проверяет, являются ли принятые через сокет байты валидными и подлежат обработке. Это можно сделать, зашифровав и/или подписав передаваемые данные через сокет, так что вызываемый объект verify сможет выполнить проверку подписи и/или дешифрование. Вызываемый объект verify вызывается с одним аргументом — байтами, полученными через сокет, и должен вернуть байты для обработки или None, чтобы указать, что байты следует отбросить. Возвращаемые байты могут быть такими же, как и переданные (например, при выполнении только проверки), или они могут быть совершенно другими (например, при выполнении дешифрования).

Чтобы отправить конфигурацию в сокет, прочитайте конфигурационный файл и отправьте его в сокет в виде последовательности байтов, предваряемых четырёхбайтовой строкой длины, упакованной в двоичном формате с использованием struct.pack('>L', n).

Примечание

Поскольку части конфигурации передаются через eval(), использование этой функции может создать риски безопасности. Хотя функция связывается только с сокетом на localhost, и поэтому не принимает подключения от удалённых машин, существуют сценарии, в которых ненадёжный код может выполняться от имени процесса, вызывающего listen(). В частности, если процесс, вызывающий listen(), работает на многопользовательской машине, где пользователи не могут доверять друг другу, злонамеренный пользователь может организовать запуск практически произвольного кода в процессе жертвы, просто подключившись к сокету жертвы listen() и отправив конфигурацию, которая выполнит любой код, который злоумышленник хочет выполнить в процессе жертвы. Это особенно легко сделать, если используется порт по умолчанию, но не сложно даже при использовании другого порта. Чтобы избежать риска, используйте аргумент verify для listen(), чтобы предотвратить применение нераспознанных конфигураций.

Изменено в версии 3.4: Добавлен аргумент verify.

Примечание

Если вы хотите отправлять конфигурации слушателю, которые не отключают существующие логгеры, вам необходимо использовать JSON-формат для конфигурации, который будет использовать dictConfig() для настройки. Этот метод позволяет указать disable_existing_loggers как False в отправляемой конфигурации.

logging.config.stopListening()

Останавливает сервер прослушивания, созданный с помощью вызова listen(). Это обычно вызывается перед вызовом join() на возвращаемом значении из listen().

Безопасность

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

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

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

Подробности схемы словаря

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

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

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

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

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

    • format
    • datefmt
    • style
    • validate (с версии >=3.8)
    • defaults (с версии >=3.12)

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

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

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

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

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

    • class (обязательно). Это полное квалифицированное имя класса обработчика.
    • level (необязательно). Уровень обработчика.
    • formatter (необязательно). Идентификатор форматировщика для этого обработчика.
    • filters (необязательно). Список идентификаторов фильтров для этого обработчика.

      Изменено в версии 3.11: filters может принимать экземпляры фильтров помимо идентификаторов.

    Все другие ключи передаются как именованные аргументы конструктору обработчика. Например, в фрагменте:

    handlers:
      console:
        class : logging.StreamHandler
        formatter: brief
        level   : INFO
        filters: [allow_foo]
        stream  : ext://sys.stdout
      file:
        class : logging.handlers.RotatingFileHandler
        formatter: precise
        filename: logconfig.log
        maxBytes: 1024
        backupCount: 3
    

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

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

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

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

      Изменено в версии 3.11: filters может принимать экземпляры фильтров помимо идентификаторов.

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

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

  • root - это будет конфигурация для корневого логикатора. Обработка конфигурации будет такой же, как для любого логикатора, за исключением того, что параметр propagate не будет применяться.
  • incremental - определяет, должна ли конфигурация интерпретироваться как инкрементальная по отношению к существующей конфигурации. Это значение по умолчанию False, что означает, что указанная конфигурация заменяет существующую конфигурацию с теми же семантическими значениями, что и в существующем 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 определяет три форматера. Первый, с идентификатором brief, является стандартным экземпляром logging.Formatter с указанной строкой формата. Второй, с идентификатором default, имеет более длинный формат и также явно определяет формат времени и приведет к созданию экземпляра logging.Formatter с этими двумя строками формата. В исходном коде Python форматеры brief и default имеют подсловарей конфигурации:

{
  'format' : '%(message)s'
}

и:

{
  'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
  'datefmt' : '%Y-%m-%d %H:%M:%S'
}

соответственно, и так как эти словари не содержат специальный ключ '()', создание экземпляра определяется из контекста: в результате создаются стандартные экземпляры logging.Formatter. Подсловарь конфигурации для третьего форматера с идентификатором custom:

{
  '()' : 'my.package.customFormatterFactory',
  'bar' : 'baz',
  'spam' : 99.9,
  'answer' : 42
}

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

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

Предупреждение

Значения для ключей, таких как bar, spam и answer в приведенном выше примере не должны быть словарями конфигурации или ссылками, такими как cfg://foo или ext://bar, так как они не будут обрабатываться механизмом конфигурации, а будут переданы вызываемой функции как есть.

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

Изменено в версии 3.11: Член filters handlers и loggers может принимать экземпляры фильтров в дополнение к идентификаторам.

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

{
  '()' : 'my.package.customFormatterFactory',
  'bar' : 'baz',
  'spam' : 99.9,
  'answer' : 42,
  '.' {
    'foo': 'bar',
    'baz': 'bozz'
  }
}

возвращаемый форматер будет иметь атрибут foo, установленный в 'bar', и атрибут baz установленный в 'bozz'.

Предупреждение

Значения для атрибутов, таких как foo и baz в приведенном выше примере не должны быть словарями конфигурации или ссылками, такими как cfg://foo или ext://bar, так как они не будут обрабатываться механизмом конфигурации, а будут установлены как значения атрибутов как есть.

Порядок конфигурации обработчиков

Обработчики настраиваются в алфавитном порядке их ключей, и настроенный обработчик заменяет словарь конфигурации в (рабочей копии) словаре handlers в схеме. Если вы используете конструкцию, такую как cfg://handlers.foo, то изначально handlers['foo'] указывает на словарь конфигурации для обработчика с именем foo, а позднее (после настройки обработчика) он указывает на экземпляр настроенного обработчика. Таким образом, cfg://handlers.foo может ссылаться либо на словарь, либо на экземпляр обработчика. В общем случае рекомендуется давать имена обработчикам таким образом, чтобы зависимые обработчики настраивались _после_ всех обработчиков, от которых они зависят; это позволяет использовать что-то вроде cfg://handlers.foo для настройки обработчика, который зависит от обработчика foo. Если бы этот зависимый обработчик назывался bar, возникли бы проблемы, потому что попытка настройки bar была бы предпринята до настройки foo, и foo еще не был бы настроен. Однако, если бы зависимый обработчик назывался foobar, он был бы настроен после foo, в результате cfg://handlers.foo сослался бы на настроенный обработчик foo, а не на его словарь конфигурации.

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

Иногда конфигурация должна ссылаться на объекты, внешние по отношению к конфигурации, например, sys.stderr. Если словарь конфигурации создается с помощью кода Python, это просто, но возникает проблема, когда конфигурация предоставляется через текстовый файл (например, JSON, YAML). В текстовом файле нет стандартного способа отличить sys.stderr от буквальной строки 'sys.stderr'. Для облегчения этого различия система конфигурации ищет определенные специальные префиксы в строковых значениях и обрабатывает их специальным образом. Например, если в качестве значения в конфигурации предоставляется буквальная строка 'ext://sys.stderr', то ext:// будет удалено, а остальная часть значения обработана с помощью обычных механизмов импорта.

Обработка таких префиксов выполняется аналогично обработке протоколов: существует общий механизм поиска префиксов, соответствующих регулярному выражению ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$, в котором, если prefix распознан, suffix обрабатывается в зависимости от префикса, и результат обработки заменяет строковое значение. Если префикс не распознан, то строковое значение останется неизменным.

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

Помимо внешних объектов, иногда также необходимо ссылаться на объекты в конфигурации. Система конфигурации будет делать это неявно для объектов, о которых она знает. Например, строковое значение 'DEBUG' для level в логге или обработчике будет автоматически преобразовано в значение logging.DEBUG, а записи handlers, filters и formatter будут принимать идентификатор объекта и перенаправлять его к соответствующему целевому объекту.

Однако для пользовательских объектов, которые не известны модулю logging, нужен более общий механизм. Например, рассмотрим logging.handlers.MemoryHandler, который принимает аргумент target, который является другим обработчиком для делегирования. Поскольку система уже знает об этом классе, то в конфигурации указанный target должен быть просто идентификатором объекта соответствующего целевого обработчика, и система найдет обработчик по этому идентификатору. Однако, если пользователь определяет my.package.MyHandler с обработчиком alternate, система конфигурации не будет знать, что alternate относится к обработчику. Чтобы учесть это, система разрешения общего назначения позволяет пользователю указать:

handlers:
  file:
    # configuration of file handler goes here

  custom:
    (): my.package.MyHandler
    alternate: cfg://handlers.file

Буквальная строка 'cfg://handlers.file' будет разрешаться аналогично строкам с префиксом ext://, но поиск будет проводиться в самой конфигурации, а не в пространстве импорта. Механизм позволяет получать доступ с помощью точки или по индексу, аналогично тому, что предоставляет str.format. Таким образом, учитывая следующий фрагмент:

handlers:
  email:
    class: logging.handlers.SMTPHandler
    mailhost: localhost
    fromaddr: my_app@domain.tld
    toaddrs:
      - support_team@domain.tld
      - dev_team@domain.tld
    subject: Houston, we have a problem.

в конфигурации строка 'cfg://handlers' будет перенаправлена на словарь с ключом handlers, строка 'cfg://handlers.email будет перенаправлена на словарь с ключом email в словаре handlers и так далее. Строка 'cfg://handlers.email.toaddrs[1] будет перенаправлена на 'dev_team@domain.tld', а строка 'cfg://handlers.email.toaddrs[0]' будет перенаправлена на значение 'support_team@domain.tld'. К значение subject можно получить, используя либо 'cfg://handlers.email.subject', либо, что эквивалентно, 'cfg://handlers.email[subject]'. Последняя форма требуется только в том случае, если ключ содержит пробелы или неалфавитно-цифровые символы. Если значение индекса состоит только из десятичных цифр, будет выполнена попытка доступа с использованием соответствующего целого значения, в противном случае используется строковое значение.

Учитывая строку cfg://handlers.myhandler.mykey.123, она будет перенаправлена на config_dict['handlers']['myhandler']['mykey']['123']. Если строка указана как cfg://handlers.myhandler.mykey[123], система попытается получить значение из config_dict['handlers']['myhandler']['mykey'][123], и если это не удастся, обратится к config_dict['handlers']['myhandler']['mykey']['123'].

Разрешение импорта и пользовательские импортеры

Разрешение импорта по умолчанию использует встроенную функцию __import__() для выполнения импорта. Вы можете заменить её собственным механизмом импорта: в этом случае вы можете заменить атрибут importer класса DictConfigurator или его суперкласса, класса BaseConfigurator. Однако будьте осторожны из-за того, как функции обращаются к классам через дескрипторы. Если вы используете вызываемый объект Python для выполнения импорта и хотите определить его на уровне класса, а не на уровне экземпляра, вам нужно обернуть его функцией staticmethod(). Например:

from importlib import import_module
from logging.config import BaseConfigurator

BaseConfigurator.importer = staticmethod(import_module)

Вам не нужно оборачивать функцией staticmethod(), если вы устанавливаете вызываемый объект импорта для экземпляра конфигуратора.

Настройка QueueHandler и QueueListener

Если вы хотите настроить QueueHandler, имея в виду, что это обычно используется совместно с QueueListener, вы можете настроить их вместе. После настройки экземпляр QueueListener будет доступен как атрибут listener созданного обработчика, а тот, в свою очередь, будет доступен вам с помощью getHandlerByName() и указанием имени, которое вы использовали для QueueHandler в вашей конфигурации. Схема словаря для настройки пары показана в примере YAML-фрагмента ниже.

handlers:
  qhand:
    class: logging.handlers.QueueHandler
    queue: my.module.queue_factory
    listener: my.package.CustomListener
    handlers:
      - hand_name_1
      - hand_name_2
      ...

Ключи queue и listener необязательны.

Если ключ queue присутствует, соответствующее значение может быть одним из следующих:

  • Объект, реализующий общедоступный API queue.Queue. Например, это может быть фактический экземпляр queue.Queue или его подкласс, или прокси, полученный с помощью multiprocessing.managers.SyncManager.Queue().

    Это, конечно, возможно только если вы создаёте или изменяете словарь конфигурации в коде.

  • Строка, которая разрешается в вызываемый объект, который, при вызове без аргументов, возвращает экземпляр queue.Queue для использования. Этот вызываемый объект может быть подклассом queue.Queue или функцией, возвращающей подходящий экземпляр очереди, например, my.module.queue_factory().
  • Словарь с ключом '()', который создаётся обычным образом, как описано в Пользовательские объекты. Результатом этого создания должен быть экземпляр queue.Queue.

Если ключ queue отсутствует, создаётся и используется стандартный неограниченный экземпляр queue.Queue.

Если ключ listener присутствует, соответствующее значение может быть одним из следующих:

  • Подкласс logging.handlers.QueueListener. Это, конечно, возможно только если вы создаёте или изменяете словарь конфигурации в коде.
  • Строка, которая разрешается в класс, являющийся подклассом QueueListener, например, 'my.package.CustomListener'.
  • Словарь с ключом '()', который создаётся обычным способом, как описано в Пользовательские объекты. Результатом этого создания должен быть вызываемый объект с той же сигнатурой, что и инициализатор QueueListener.

Если ключ listener отсутствует, используется logging.handlers.QueueListener.

Значения под ключом handlers — это имена других обработчиков в конфигурации (не показанных в приведенном выше фрагменте), которые будут переданы слушателю очереди.

Любые пользовательские классы обработчиков и слушателей очереди должны быть определены с теми же сигнатурами инициализации, что и QueueHandler и QueueListener.

Добавлена в версии 3.12.

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

Формат файла конфигурации, понимаемый fileConfig(), основан на функциональности configparser. Файл должен содержать секции, называемые [loggers], [handlers] и [formatters], которые по имени идентифицируют сущности каждого типа, определенные в файле. Для каждой такой сущности существует отдельная секция, которая определяет, как настраивается эта сущность. Таким образом, для логгера с именем log01 в секции [loggers], соответствующие данные конфигурации хранятся в секции [logger_log01]. Аналогично, обработчик с именем hand01 в секции [handlers] будет иметь свою конфигурацию, хранящуюся в секции [handler_hand01], а форматировщик с именем form01 в секции [formatters] будет иметь свою конфигурацию, заданную в секции [formatter_form01]. Конфигурация корневого логгера должна быть указана в секции [logger_root].

Примечание

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

Примеры этих секций в файле приведены ниже.

[loggers]
keys=root,log02,log03,log04,log05,log06,log07

[handlers]
keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09

[formatters]
keys=form01,form02,form03,form04,form05,form06,form07,form08,form09

Корневой логгер должен указывать уровень и список обработчиков. Пример секции корневого логгера приведен ниже.

[logger_root]
level=NOTSET
handlers=hand01

Запись level может быть одной из DEBUG, INFO, WARNING, ERROR, CRITICAL или NOTSET. Только для корневого логгера, NOTSET означает, что все сообщения будут записаны в журнал. Значения уровней оцениваются в контексте пространства имён пакета logging.

Запись handlers — это список имён обработчиков, разделённых запятыми, которые должны появиться в секции [handlers] Эти имена должны появляться в секции [handlers] и иметь соответствующие секции в файле конфигурации.

Для логгеров, отличных от корневого логгера, требуется дополнительная информация. Это проиллюстрировано следующим примером.

[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser

Записи level и handlers интерпретируются так же, как для корневого логгера, за исключением того, что если уровень не корневого логгера задан как NOTSET, система обращается к логгерам выше по иерархии, чтобы определить эффективный уровень логгера. Запись propagate устанавливается в 1, чтобы указать, что сообщения должны распространяться к обработчикам выше по иерархии логгеров из этого логгера, или в 0, чтобы указать, что сообщения не распространяются к обработчикам выше по иерархии. Запись qualname — это иерархическое имя канала логгера, то есть имя, используемое приложением для получения логгера.

Секции, которые задают конфигурацию обработчика, проиллюстрированы ниже.

[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)

Запись class указывает класс обработчика (как определяется eval() в пространстве имён пакета logging). Запись level интерпретируется так же, как для логгеров, а NOTSET означает «записывать всё».

Запись formatter указывает имя ключа форматировщика для этого обработчика. Если пустая, используется форматировщик по умолчанию (logging._defaultFormatter). Если имя задано, оно должно появляться в секции [formatters] и иметь соответствующую секцию в файле конфигурации.

Запись args, при оценке в контексте пространства имён пакета logging, — это список аргументов конструктора для класса обработчика. Обратитесь к конструкторам соответствующих обработчиков или к приведённым ниже примерам, чтобы увидеть, как строятся типичные записи. Если не указано, значение по умолчанию — ().

Необязательная запись kwargs, при оценке в контексте пространства имён пакета logging, — это словарь ключевых аргументов конструктора для класса обработчика. Если не указано, значение по умолчанию — {}.

[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')

[handler_hand03]
class=handlers.SocketHandler
level=INFO
formatter=form03
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)

[handler_hand04]
class=handlers.DatagramHandler
level=WARN
formatter=form04
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)

[handler_hand05]
class=handlers.SysLogHandler
level=ERROR
formatter=form05
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)

[handler_hand06]
class=handlers.NTEventLogHandler
level=CRITICAL
formatter=form06
args=('Python Application', '', 'Application')

[handler_hand07]
class=handlers.SMTPHandler
level=WARN
formatter=form07
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
kwargs={'timeout': 10.0}

[handler_hand08]
class=handlers.MemoryHandler
level=NOTSET
formatter=form08
target=
args=(10, ERROR)

[handler_hand09]
class=handlers.HTTPHandler
level=NOTSET
formatter=form09
args=('localhost:9022', '/log', 'GET')
kwargs={'secure': True}

Секции, которые задают конфигурацию форматировщика, типизированы следующим образом.

[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s %(customfield)s
datefmt=
style=%
validate=True
defaults={'customfield': 'defaultvalue'}
class=logging.Formatter

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

Запись defaults при оценке в контексте пространства имён пакета logging является словарем значений по умолчанию для пользовательских полей форматирования. Если не указано, значение по умолчанию — None.

Примечание

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

См. также

Module logging

Справочник по API модуля ведения журнала.

Module logging.handlers

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

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/logging.config.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API