# `logging.config` — Logging configuration

Вихідний код: 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()

  For example, a subclass of `DictConfigurator` could call `DictConfigurator.__init__()` in its own `__init__()`, then set up custom prefixes which would be usable in the subsequent `configure()` call. `dictConfigClass` would be bound to this new subclass, and then `dictConfig()` could be called exactly as in the default, uncustomized state.

  Нове в версії 3.2.

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

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

  It will raise `FileNotFoundError` if the file doesn’t exist and `RuntimeError` if the file is invalid or empty.

  Параметри:

    - fname – A filename, or a file-like object, or an instance derived from `RawConfigParser`. If a `RawConfigParser`-derived instance is passed, it is used as is. Otherwise, a `ConfigParser` is instantiated, and the configuration read by it from the object passed in `fname`. If that has a `readline()` method, it is assumed to be a file-like object and read using `read_file()`; otherwise, it is assumed to be a filename and passed to `read()`.

    - defaults – Defaults to be passed to the `ConfigParser` can be specified in this argument.

    - disable_existing_loggers – If specified as `False`, loggers which exist when this call is made are left enabled. The default is `True` because this enables old behaviour in a backward-compatible way. This behaviour is to disable any existing non-root loggers unless they or their ancestors are explicitly named in the logging configuration.

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

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

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

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

  Змінено в версії 3.10: Added the encoding parameter.

  Змінено в версії 3.11.4: An exception will be thrown if the provided file doesn’t exist or is invalid or empty.

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: Додано аргумент `перевірити`.

  Примітка

  Якщо ви хочете надіслати конфігурації прослухувачу, які не вимикають існуючі реєстратори, вам потрібно буде використовувати формат 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`:

  - `формат`

  - `datefmt`

  - `стиль`

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

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

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

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

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

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

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

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

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

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

    Змінено в версії 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` (необов’язковий). Налаштування розповсюдження реєстратора.

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

    Змінено в версії 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'
    }

і:

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

Попередження

The values for keys such as `bar`, `spam` and `answer` in the above example should not be configuration dictionaries or references such as `cfg://foo` or `ext://bar`, because they will not be processed by the configuration machinery, but passed to the callable as-is.

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

Змінено в версії 3.11: The `filters` member of `handlers` and `loggers` can take filter instances in addition to ids.

You can also specify a special key `'.'` whose value is a dictionary is a mapping of attribute names to values. If found, the specified attributes will be set on the user-defined object before it is returned. Thus, with the following configuration:

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

the returned formatter will have attribute `foo` set to `'bar'` and attribute `baz` set to `'bozz'`.

Попередження

The values for attributes such as `foo` and `baz` in the above example should not be configuration dictionaries or references such as `cfg://foo` or `ext://bar`, because they will not be processed by the configuration machinery, but set as attribute values as-is.

### Handler configuration order

Handlers are configured in alphabetical order of their keys, and a configured handler replaces the configuration dictionary in (a working copy of) the `handlers` dictionary in the schema. If you use a construct such as `cfg://handlers.foo`, then initially `handlers['foo']` points to the configuration dictionary for the handler named `foo`, and later (once that handler has been configured) it points to the configured handler instance. Thus, `cfg://handlers.foo` could resolve to either a dictionary or a handler instance. In general, it is wise to name handlers in a way such that dependent handlers are configured _after_ any handlers they depend on; that allows something like `cfg://handlers.foo` to be used in configuring a handler that depends on handler `foo`. If that dependent handler were named `bar`, problems would result, because the configuration of `bar` would be attempted before that of `foo`, and `foo` would not yet have been configured. However, if the dependent handler were named `foobar`, it would be configured after `foo`, with the result that `cfg://handlers.foo` would resolve to configured handler `foo`, and not its configuration dictionary.

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

Бувають випадки, коли конфігурація потребує посилання на об’єкти, зовнішні щодо конфігурації, наприклад `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.

in the configuration, the string `'cfg://handlers'` would resolve to the dict with key `handlers`, the string `'cfg://handlers.email` would resolve to the dict with key `email` in the `handlers` dict, and so on. The string `'cfg://handlers.email.toaddrs[1]` would resolve to `'dev_team@domain.tld'` and the string `'cfg://handlers.email.toaddrs[0]'` would resolve to the value `'support_team@domain.tld'`. The `subject` value could be accessed using either `'cfg://handlers.email.subject'` or, equivalently, `'cfg://handlers.email[subject]'`. The latter form only needs to be used if the key contains spaces or non-alphanumeric characters. If an index value consists only of decimal digits, access will be attempted using the corresponding integer value, falling back to the string value if needed.

Якщо вказати рядок `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`. Файл має містити розділи під назвою `[реєстратори]`, `[обробники]` і `[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

The `level` entry can be one of `DEBUG, INFO, WARNING, ERROR, CRITICAL` or `NOTSET`. For the root logger only, `NOTSET` means that all messages will be logged. Level values are evaluated in the context of the `logging` package’s namespace.

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

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

    [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]` і мати відповідний розділ у файлі конфігурації.

The `args` entry, when evaluated in the context of the `logging` package’s namespace, is the list of arguments to the constructor for the handler class. Refer to the constructors for the relevant handlers, or to the examples below, to see how typical entries are constructed. If not provided, it defaults to `()`.

The optional `kwargs` entry, when evaluated in the context of the `logging` package’s namespace, is the keyword argument dict to the constructor for the handler class. If not provided, it defaults to `{}`.

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

Примітка

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

Дивись також

Модуль `logging`

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

Модуль `logging.handlers`

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