Spec-Zone.ru › Python 3.10

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

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

    If specified as False, loggers which

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

    параметр encoding

    Кодировка, используемая для открытия файла, когда fname является именем файла.

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

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

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

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

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

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

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

Примечание

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

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

Примечание

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

logging.config.stopListening()

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

Соображения безопасности

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • disable_existing_loggers - указывает, должны ли быть отключены все существующие регистрирующие объекты, не являющиеся корневыми. Этот параметр аналогичен параметру с таким же именем в fileConfig(). Если он отсутствует, этот параметр по умолчанию равен True. Это значение игнорируется, если incremental равно True.

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

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

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

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

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

Соединения объектов

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

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

formatters:
  brief:
    # configuration for formatter with id 'brief' goes here
  precise:
    # configuration for formatter with id 'precise' goes here
handlers:
  h1: #This is an id
   # configuration of handler with id 'h1' goes here
   formatter: brief
  h2: #This is another id
   # configuration of handler with id 'h2' goes here
   formatter: precise
loggers:
  foo.bar.baz:
    # other configuration for logger 'foo.bar.baz'
    handlers: [h1, h2]

(Примечание: здесь используется YAML, поскольку он немного более удобочитаем, чем эквивалентный Python-формат для словаря.)

Идентификаторы регистрирующих объектов — это имена регистрирующих объектов, которые программно используются для получения ссылки на эти регистрирующие объекты, например, foo.bar.baz. Идентификаторы форматировщиков и фильтров могут быть любыми строковыми значениями (например, brief, precise выше), и они являются временными, в том смысле, что они имеют значение только для обработки словаря конфигурации и используются для определения связей между объектами, и не сохраняются нигде после завершения вызова конфигурации.

Приведенный выше фрагмент указывает, что регистрирующий объект с именем foo.bar.baz должен иметь два прикрепленных обработчика, которые описываются идентификаторами обработчиков h1 и h2. Форматировщик для h1 — это тот, который описывается идентификатором brief, а форматировщик для h2 — это тот, который описывается идентификатором precise.

Пользовательские объекты

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

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

formatters:
  brief:
    format: '%(message)s'
  default:
    format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
    datefmt: '%Y-%m-%d %H:%M:%S'
  custom:
      (): my.package.customFormatterFactory
      bar: baz
      spam: 99.9
      answer: 42

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

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

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

{
  '()' : '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() использовать не нужно.

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

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

[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

Ссылка на API модуля ведения логов.

Module logging.handlers

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

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

Spec-Zone.ru

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