logging.config — Конфигурация журналирования

Kod źródłowy: Lib/logging/config.py


У цьому розділі описано API для налаштування модуля журналювання.

Функції конфігурації

Наступні функції налаштовують модуль журналювання. Вони знаходяться в модулі logging.config. Їхнє використання необов’язкове — ви можете налаштувати модуль журналювання за допомогою цих функцій або викликом основного API (визначеного в самому logging) і визначення обробників, які оголошуються або в logging, або logging.handlers.

logging.config.dictConfig(config)

Бере конфігурацію журналювання зі словника. Вміст цього словника описано в Схема словника конфігурації нижче.

Якщо під час налаштування буде виявлено помилку, ця функція викличе ValueError, TypeError, AttributeError або ImportError із відповідним описовим повідомленням. Нижче наведено (можливо, неповний) список умов, які викличуть помилку:

  • Рівень, який не є рядком або є рядком, що не відповідає фактичному рівню реєстрації.

  • Значення розповсюдження, яке не є логічним.

  • Ідентифікатор, який не має відповідного адресата.

  • Під час інкрементного виклику виявлено ідентифікатор неіснуючого обробника.

  • Недійсне ім’я реєстратора.

  • Нездатність вирішити внутрішній або зовнішній об’єкт.

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

dictConfig() викликає dictConfigClass, передаючи вказаний словник, а потім викликає метод configure() для повернутого об’єкта, щоб застосувати конфігурацію:

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

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

Dodane w wersji 3.2.

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

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

Он выдаст FileNotFoundError, если файл не существует, и RuntimeError, если файл недействителен или пуст.

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

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

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

  • encoding – Кодування, яке використовується для відкриття файлу, коли fname є назвою файлу.

Zmienione w wersji 3.4: Екземпляр підкласу RawConfigParser тепер приймається як значення для fname. Це полегшує:

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

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

Zmienione w wersji 3.10: Добавлен параметр encoding.

Zmienione w wersji 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).

Informacja

Оскільки частини конфігурації передаються через eval(), використання цієї функції може піддати користувачам ризик безпеки. Хоча функція прив’язується лише до сокета на localhost і тому не приймає з’єднання з віддалених машин, існують сценарії, коли ненадійний код може запускатися під обліковим записом процесу, який викликає listen(). Зокрема, якщо процес, який викликає listen(), виконується на багатокористувацькій машині, де користувачі не можуть довіряти один одному, тоді зловмисник може організувати запуск практично довільного коду в процесі користувача-жертви, просто підключившись до жертви listen() сокет і надсилання конфігурації, яка запускає будь-який код, який зловмисник хоче виконати в процесі жертви. Це особливо легко зробити, якщо використовується стандартний порт, але не важко, навіть якщо використовується інший порт. Щоб уникнути цього ризику, використовуйте аргумент verify для listen(), щоб запобігти застосуванню нерозпізнаних конфігурацій.

Zmienione w wersji 3.4: Додано аргумент перевірити.

Informacja

Якщо ви хочете надіслати конфігурації прослухувачу, які не вимикають існуючі реєстратори, вам потрібно буде використовувати формат JSON для конфігурації, яка використовуватиме dictConfig() для конфігурації. Цей метод дозволяє вказати disable_existing_loggers як False у конфігурації, яку ви надсилаєте.

logging.config.stopListening()

Зупиняє сервер прослуховування, створений за допомогою виклику listen(). Це зазвичай викликається перед викликом join() для значення, яке повертає listen().

Міркування безпеки

Функціональність конфігурації журналювання намагається запропонувати зручність, і частково це робиться, пропонуючи можливість перетворювати текст у конфігураційних файлах на об’єкти Python, які використовуються в конфігурації журналювання - наприклад, як описано в Визначені користувачем об’єкти. Однак ці самі механізми (імпорт викликів із визначених користувачем модулів і виклик їх із параметрами з конфігурації) можна використовувати для виклику будь-якого коду, який вам подобається, і з цієї причини ви повинні поводитися з конфігураційними файлами з ненадійних джерел з надзвичайною обережністю і переконайтеся, що нічого поганого не станеться, якщо ви їх завантажите, перш ніж завантажувати їх.

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

Опис конфігурації журналювання вимагає переліку різних об’єктів для створення та зв’язків між ними; наприклад, ви можете створити обробник під назвою „console”, а потім сказати, що реєстратор під назвою „startup” надсилатиме свої повідомлення до обробника „console”. Ці об’єкти не обмежуються об’єктами, наданими модулем logging, оскільки ви можете написати власний формататор або клас обробника. Параметри цих класів можуть також потребувати включення зовнішніх об’єктів, таких як sys.stderr. Синтаксис для опису цих об’єктів і з’єднань визначено в Об’єктні зв’язки нижче.

Подробиці схеми словника

Словник, переданий до dictConfig(), повинен містити такі ключі:

  • version - має бути встановлено ціле значення, що представляє версію схеми. Єдиним дійсним значенням наразі є 1, але наявність цього ключа дозволяє схемі розвиватися, зберігаючи зворотну сумісність.

Усі інші ключі необов’язкові, але якщо вони присутні, вони інтерпретуватимуться, як описано нижче. У всіх випадках, наведених нижче, де згадується „налаштування dict”, буде перевірено наявність спеціального ключа '()'', щоб побачити, чи потрібен власний екземпляр. Якщо так, механізм, описаний у Визначені користувачем об’єкти нижче, використовується для створення екземпляра; інакше контекст використовується для визначення того, що створити екземпляр.

  • formatters - відповідне значення буде dict, у якому кожен ключ є ідентифікатором formatter, а кожне значення є dict, що описує, як налаштувати відповідний екземпляр Formatter.

    У диктофоні налаштування шукаються наступні додаткові ключі, які відповідають аргументам, переданим для створення об’єкта Formatter:

    • format

    • datefmt

    • style

    • validate (починаючи з версії >=3.8)

    • defaults (since version >=3.12)

    Необов’язковий ключ class вказує на ім’я класу форматера (у вигляді модуля та імені класу з крапками). Аргументи створення екземпляра такі ж, як і для Formatter, тому цей ключ найбільш корисний для створення екземпляра налаштованого підкласу Formatter. Наприклад, альтернативний клас може представляти трасування винятків у розгорнутому або скороченому форматі. Якщо ваш форматувальник вимагає інших або додаткових ключів конфігурації, ви повинні використовувати Визначені користувачем об’єкти.

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

    Dict конфігурації шукається за ключем name (за замовчуванням порожній рядок), і це використовується для створення екземпляра logging.Filter.

  • обробники – відповідним значенням буде dict, у якому кожен ключ є ідентифікатором обробника, а кожне значення є dict, що описує, як налаштувати відповідний екземпляр Handler.

    У диктофоні налаштування виконується пошук таких ключів:

    • клас (обов’язковий). Це повна назва класу обробника.

    • рівень (необов’язково). Рівень обробника.

    • форматувальник (необов’язковий). Ідентифікатор форматера для цього обробника.

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

      Zmienione w wersji 3.11: filters can take filter instances in addition to ids.

    Усі інші ключі передаються як аргументи ключового слова до конструктора обробника. Наприклад, враховуючи фрагмент:

    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 - відповідне значення буде dict, у якому кожен ключ є іменем logger, а кожне значення є dict, що описує, як налаштувати відповідний екземпляр Logger.

    У диктофоні налаштування виконується пошук таких ключів:

    • рівень (необов’язково). Рівень лісоруба.

    • propagate (необов’язковий). Налаштування розповсюдження реєстратора.

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

      Zmienione w wersji 3.11: filters can take filter instances in addition to ids.

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

    Зазначені реєстратори буде налаштовано відповідно до вказаного рівня, розповсюдження, фільтрів і обробників.

  • root - це буде конфігурація для root logger. Обробка конфігурації відбуватиметься так само, як і для будь-якого реєстратора, за винятком того, що параметр propagate не застосовуватиметься.

  • incremental – чи конфігурація має інтерпретуватися як додаткова до існуючої конфігурації. За замовчуванням це значення має значення False, що означає, що вказана конфігурація замінює існуючу конфігурацію з тією самою семантикою, яку використовує існуючий API fileConfig().

    Якщо вказане значення True, конфігурація обробляється, як описано в розділі про Інкрементна конфігурація.

  • disable_existing_loggers - чи потрібно вимкнути існуючі некореневі реєстратори. Цей параметр відображає однойменний параметр у fileConfig(). Якщо цей параметр відсутній, цей параметр за замовчуванням має значення True. Це значення ігнорується, якщо incremental має значення True.

Інкрементна конфігурація

Важко забезпечити повну гнучкість для поступової конфігурації. Наприклад, оскільки такі об’єкти, як фільтри та засоби форматування, є анонімними, після налаштування конфігурації неможливо посилатися на такі анонімні об’єкти під час розширення конфігурації.

Крім того, немає переконливих аргументів для довільної зміни графа об’єктів реєстраторів, обробників, фільтрів, форматувальників під час виконання, коли конфігурацію встановлено; докладністю реєстраторів і обробників можна керувати, просто встановлюючи рівні (і, у випадку реєстраторів, позначки поширення). Довільна зміна графа об’єктів у безпечний спосіб проблематична в багатопоточному середовищі; Хоча це не неможливо, переваги не варті складності, яку це додає до впровадження.

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

Використання значення в конфігураційному диктофоні дозволяє надсилати конфігурації по дроту як маріновані диктофони до слухача сокета. Таким чином, докладність журналу тривалої програми може бути змінена з часом без необхідності зупиняти та перезапускати програму.

Об’єктні зв’язки

Схема описує набір об’єктів журналювання – реєстратори, обробники, засоби форматування, фільтри – які з’єднані один з одним у графі об’єктів. Таким чином, схема повинна представляти зв’язки між об’єктами. Наприклад, скажіть, що після налаштування певний реєстратор приєднав до нього певний обробник. Для цілей цього обговорення ми можемо сказати, що реєстратор представляє джерело, а обробник — призначення з’єднання між ними. Звичайно, у налаштованих об’єктах це представлено реєстратором, що містить посилання на обробник. У 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. Ідентифікатори для Formatters і Filters можуть бути будь-якими рядковими значеннями (наприклад, 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'
}

dan:

{
  '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)

Ostrzeżenie

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

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

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

您还可以指定一个特殊的键 '.',它的值是属性名到值的映射。 如果找到,在返回用户定义对象之前,将在该对象上设置指定的属性。 因此,使用以下配置:

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

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

Ostrzeżenie

Значения таких атрибутов, как 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> .* )$, таким чином, якщо префікс розпізнається, суфікс обробляється залежно від префікса, і результат обробки замінює значення рядка. Якщо префікс не розпізнається, значення рядка залишиться без змін.

Доступ до внутрішніх об’єктів

Окрім зовнішніх об’єктів, інколи виникає потреба звертатися до об’єктів у конфігурації. Це буде зроблено неявно системою конфігурації для речей, про які вона знає. Наприклад, рядкове значення 'DEBUG для level у реєстраторі або обробнику буде автоматично перетворено на значення logging.DEBUG, а обробники, Записи filters і formatter прийматимуть ідентифікатор об’єкта та вирішуватимуть відповідний об’єкт призначення.

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

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 будет разрешаться в словарь с ключом handlers. ключ 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 являются необязательными.

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

  • Объект, реализующий общедоступный 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.

Dodane w wersji 3.12.

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

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

Informacja

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.

Запис обробники — це список імен обробників, розділених комами, які повинні з’являтися в розділі [обробники]. Ці назви мають відображатися в розділі [обробники] і мати відповідні розділи у файлі конфігурації.

Для реєстраторів, відмінних від кореневого реєстратора, потрібна додаткова інформація. Це ілюструється наступним прикладом.

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

Записи level і handlers інтерпретуються як для кореневого реєстратора, за винятком того, що якщо рівень некореневого реєстратора вказано як NOTSET, система консультується з реєстраторами вищого рівня в ієрархії, щоб визначити ефективний рівень логера. Запис пропагувати має значення 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, представляет собой список аргументов конструктора для класса-обработчика. Обратитесь к конструкторам соответствующих обработчиков или к примерам ниже, чтобы увидеть, как создаются типичные записи. Если не указано, по умолчанию используется ().

Запись args, когда оценивается в контексте пространства имен пакета 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

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

Запись defaults, когда оценивается в контексте пространства имен пакета logging, представляет собой словарь значений по умолчанию для пользовательских полей форматирования. Если он не указан, по умолчанию используется значение «Нет».

Informacja

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

Zobacz także

Модуль logging

Довідник API для модуля журналювання.

Модуль logging.handlers

Корисні обробники, включені в модуль журналювання.