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, если файл недействителен или пуст.

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

  • defaults – В этом аргументе могут быть указаны значения по умолчанию, которые будут переданы в ConfigParser.

  • disable_existing_loggers – Если указано значение False, то логгеры, которые существуют на момент выполнения этого вызова, остаются включенными. Значение по умолчанию равно True, поскольку это позволяет использовать старое поведение обратно совместимым способом. Это делается для того, чтобы отключить все существующие некорневые регистраторы, если только они или их предки явно не указаны в конфигурации ведения журнала.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • format

    • datefmt

    • style

    • validate (начиная с версии >=3.8)

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

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

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

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

    В конфигурирующем dict выполняется поиск следующих ключей:

    • 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.

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

    В конфигурирующем dict выполняется поиск следующих ключей:

    • level (необязательно). Уровень регистратора.

    • propagate (необязательно). Настройка распространения в регистраторе.

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

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

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

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

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

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

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

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

Постепенная настройка

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

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

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

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

Соединения с объектами

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

Так, например, рассмотрим следующий фрагмент кода 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. Если конфигурационный dict создан с использованием кода Python, это несложно, но возникает проблема, когда конфигурация предоставляется через текстовый файл (например, JSON, YAML). В текстовом файле нет стандартного способа отличить sys.stderr от строки-литерала 'sys.stderr'. Чтобы облегчить это различие, система конфигурации ищет определенные специальные префиксы в строковых значениях и обрабатывает их особым образом. Например, если строка-литерал 'ext://sys.stderr' указана в качестве значения в конфигурации, то строка-литерал ext:// будет удалена, а оставшаяся часть значения обработана с использованием обычных механизмов импорта.

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

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

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

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

handlers:
  file:
    # 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' преобразуется в dict с ключом handlers, строка 'cfg://handlers.email преобразуется в dict с ключом 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 означает, что все сообщения будут записываться в журнал. Значения уровня равны evaluated в контексте пространства имен пакета 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, когда evaluated в контексте пространства имен пакета logging, является списком аргументов конструктора для класса handler. Обратитесь к конструкторам соответствующих обработчиков или к приведенным ниже примерам, чтобы увидеть, как создаются типичные записи. Если не указано, по умолчанию используется значение ().

Необязательная запись kwargs, когда evaluated в контексте пространства имен пакета logging, является аргументом ключевого слова dict для конструктора класса handler. Если этот параметр не указан, то по умолчанию используется значение {}.

[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

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

Примечание

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

См.также

Модуль logging

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

Модуль logging.handlers

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

Вернуться на верх