Spec-Zone.ru › Python 3.11

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, так как это позволяет сохранить старое поведение в обратной совместимости. Это поведение заключается в отключении всех существующих логгеров, кроме root, если они или их предки явно не указаны в конфигурации логгирования.
  • encoding – Кодировка, используемая при открытии файла, когда fname является именем файла.

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

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

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

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

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)

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

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

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

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

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

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

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

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

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

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

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

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

    • level (необязательно). Уровень логгера.
    • 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 определяет три форматера. Первый, с 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. Подсловарь конфигурации для третьего форматера с id custom имеет вид:

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

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

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

Формат файла конфигурации, понятный 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
datefmt=
style=%
validate=True
class=logging.Formatter

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

Примечание

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

См. также

Module logging

Справочная информация по модулю ведения журнала.

Module logging.handlers

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

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

Spec-Zone.ru

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