Spec-Zone.ru › Python 3.14

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: Теперь в качестве значения fname принимается экземпляр подкласса RawConfigParser. Это позволяет:

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

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

Описание конфигурации журналирования требует перечислить различные создаваемые объекты и связи между ними; например, можно создать обработчик с именем ‘console’, а затем указать, что регистратор с именем ‘startup’ будет отправлять свои сообщения обработчику ‘console’. Эти объекты не ограничиваются объектами, предоставляемыми модулем 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.

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

Связи между объектами

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

Например, рассмотрим следующий фрагмент 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.put_nowait и Queue.get. Например, это может быть экземпляр queue.Queue или его подкласса либо прокси, полученный с помощью multiprocessing.managers.SyncManager.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() и не предоставляет функциональность для настройки некоторых аспектов ведения журнала. Например, с помощью fileConfig() нельзя настроить объекты Filter, позволяющие фильтровать сообщения не только по простым целочисленным уровням. Если в конфигурации ведения журнала необходимо использовать экземпляры 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(), описанным выше, при использовании API listen() для отправки и получения конфигураций через сокеты существуют потенциальные риски безопасности. Эти риски актуальны в ситуациях, когда несколько не доверяющих друг другу пользователей запускают код на одном компьютере; дополнительные сведения см. в документации listen().

См. также

Module logging

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

Module logging.handlers

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

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

Spec-Zone.ru

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