logging.md
1> **Источник:** https://python-all.ru/3.3/howto/logging.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Руководство по логированию89| Автор: | Vinay Sajip \<vinay\_sajip at red-dove dot com\> |10| --- | --- |1112## Базовое руководство по логированию1314Логирование – это средство отслеживания событий, происходящих при выполнении программного обеспечения. Разработчик добавляет в код вызовы логирования, чтобы указать, что произошли определенные события. Событие описывается информационным сообщением, которое может содержать переменные данные (т. е. данные, которые потенциально различаются для каждого экземпляра события). События также имеют важность, которую разработчик присваивает событию; эту важность также называют *уровнем* или *серьезностью*.1516### Когда использовать логирование1718Модуль logging предоставляет набор удобных функций для простого использования логирования. Это [`debug()`](https://python-all.ru/3.3/library/logging.html#logging.debug), [`info()`](https://python-all.ru/3.3/library/logging.html#logging.info), [`warning()`](https://python-all.ru/3.3/library/logging.html#logging.warning), [`error()`](https://python-all.ru/3.3/library/logging.html#logging.error) и [`critical()`](https://python-all.ru/3.3/library/logging.html#logging.critical). Чтобы понять, когда использовать логирование, обратитесь к таблице ниже, где для каждой типовой задачи указан наилучший инструмент.1920| Задача, которую нужно выполнить | Лучший инструмент для решения задачи |21| --- | --- |22| Вывод на консоль при обычном использовании скрипта или программы командной строки | [`print()`](https://python-all.ru/3.3/library/functions.html#print) |23| Сообщать о событиях, происходящих при нормальной работе программы (например, для мониторинга состояния или анализа неисправностей) | [`logging.info()`](https://python-all.ru/3.3/library/logging.html#logging.info) (или [`logging.debug()`](https://python-all.ru/3.3/library/logging.html#logging.debug) для очень подробного вывода с диагностической целью) |24| Выдавать предупреждение о конкретном событии времени выполнения | [`warnings.warn()`](https://python-all.ru/3.3/library/warnings.html#warnings.warn) в коде библиотеки, если проблема устранима и клиентское приложение следует изменить, чтобы устранить предупреждение [`logging.warning()`](https://python-all.ru/3.3/library/logging.html#logging.warning), если клиентское приложение не может ничего сделать с ситуацией, но событие всё равно следует отметить |25| Сообщить об ошибке, связанной с конкретным событием времени выполнения | Вызвать исключение |26| Сообщить о подавлении ошибки без вызова исключения (например, обработчик ошибок в долго работающем серверном процессе) | [`logging.error()`](https://python-all.ru/3.3/library/logging.html#logging.error), [`logging.exception()`](https://python-all.ru/3.3/library/logging.html#logging.exception) или [`logging.critical()`](https://python-all.ru/3.3/library/logging.html#logging.critical) в зависимости от конкретной ошибки и предметной области |2728Функции логирования названы по уровню или серьёзности событий, для отслеживания которых они используются. Стандартные уровни и их применимость описаны ниже (в порядке возрастания серьёзности):2930| Уровень | Когда применяется |31| --- | --- |32| `DEBUG` | Подробная информация, обычно представляющая интерес только при диагностике проблем. |33| `INFO` | Подтверждение того, что всё работает как ожидается. |34| `WARNING` | Указание на то, что произошло что-то неожиданное, или признак возможной проблемы в ближайшем будущем (например, «мало места на диске»). Программа по-прежнему работает как ожидается. |35| `ERROR` | Из-за более серьезной проблемы программа не смогла выполнить некоторую функцию. |36| `CRITICAL` | Серьезная ошибка, указывающая на то, что программа, возможно, не сможет продолжить работу. |3738Уровень по умолчанию – `WARNING`, то есть отслеживаются только события этого уровня и выше, если только пакет logging не настроен иначе.3940Отслеживаемые события можно обрабатывать разными способами. Самый простой способ – выводить их на консоль. Другой распространенный способ – записывать их в файл на диске.4142### Простой пример4344Вот очень простой пример:4546```python47import logging48logging.warning('Watch out!') # выведет сообщение в консоль49logging.info('I told you so') # ничего не выведет50```5152Если ввести эти строки в скрипт и запустить его, на консоли появится:5354```python55WARNING:root:Watch out!56```5758выводится на консоль. Сообщение `INFO` не появляется, потому что уровень по умолчанию – `WARNING`. Выводимое сообщение включает указание уровня и описание события из вызова логирования, т.е. «Watch out!». Пока не беспокойтесь о части «root» – она будет объяснена позже. Фактический вывод можно довольно гибко форматировать, если это нужно; возможности форматирования также будут объяснены позже.5960### Запись логов в файл6162Очень часто возникает необходимость записывать события журналирования в файл, поэтому давайте рассмотрим это далее. Обязательно попробуйте выполнить следующий код в только что запущенном интерпретаторе Python, а не продолжайте сеанс, описанный выше:6364```python65import logging66logging.basicConfig(filename='example.log',level=logging.DEBUG)67logging.debug('This message should go to the log file')68logging.info('So should this')69logging.warning('And this, too')70```7172Теперь, если мы откроем файл и посмотрим, что получилось, мы должны увидеть сообщения журнала:7374```python75DEBUG:root:This message should go to the log file76INFO:root:So should this77WARNING:root:And this, too78```7980Этот пример также показывает, как можно установить уровень логирования, который служит порогом отслеживания. В данном случае, поскольку мы установили порог `DEBUG`, были выведены все сообщения.8182Чтобы задать уровень логирования из параметра командной строки, например:8384```python85--log=INFO86```8788и у вас есть значение параметра, переданного для `--log`, в некоторой переменной *loglevel*, вы можете использовать:8990```python91getattr(logging, loglevel.upper())92```9394чтобы получить значение, которое затем передаётся в [`basicConfig()`](https://python-all.ru/3.3/library/logging.html#logging.basicConfig) через аргумент *level*. Возможно, вы захотите проверить любое введённое пользователем значение на ошибки, как в следующем примере:9596```python97# предполагая, что loglevel привязан к строковому значению, полученному из98# аргумента командной строки. Преобразование в верхний регистр позволяет пользователю99# указать --log=DEBUG или --log=debug100numeric_level = getattr(logging, loglevel.upper(), None)101if not isinstance(numeric_level, int):102 raise ValueError('Invalid log level: %s' % loglevel)103logging.basicConfig(level=numeric_level, ...)104```105106Вызов [`basicConfig()`](https://python-all.ru/3.3/library/logging.html#logging.basicConfig) должен быть *до* любых вызовов [`debug()`](https://python-all.ru/3.3/library/logging.html#logging.debug), [`info()`](https://python-all.ru/3.3/library/logging.html#logging.info) и т.д. Поскольку это однократное простое средство настройки, только первый вызов что-то делает; последующие вызовы фактически ничего не делают.107108Если запускать этот скрипт несколько раз, сообщения от последовательных запусков добавляются в файл *example.log*. Чтобы каждый запуск начинался с чистого листа, без сохранения сообщений от предыдущих запусков, можно указать аргумент *filemode*, изменив вызов в предыдущем примере на:109110```python111logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)112```113114Вывод будет таким же, как и раньше, но лог-файл больше не дополняется, поэтому сообщения от предыдущих запусков теряются.115116### Логирование из нескольких модулей117118Если ваша программа состоит из нескольких модулей, вот пример того, как можно организовать в ней логирование:119120```python121# myapp.py122import logging123import mylib124125def main():126 logging.basicConfig(filename='myapp.log', level=logging.INFO)127 logging.info('Started')128 mylib.do_something()129 logging.info('Finished')130131if __name__ == '__main__':132 main()133```134135```python136# mylib.py137import logging138139def do_something():140 logging.info('Doing something')141```142143Если вы запустите *myapp.py*, вы должны увидеть это в *myapp.log*:144145```python146INFO:root:Started147INFO:root:Doing something148INFO:root:Finished149```150151что, надеюсь, вы и ожидали увидеть. Вы можете обобщить это на несколько модулей, используя шаблон из *mylib.py*. Обратите внимание, что при таком простом шаблоне использования вы не сможете узнать, *откуда* в вашем приложении пришли сообщения, просто глядя в файл журнала, кроме как по описанию события. Если вы хотите отслеживать расположение своих сообщений, вам нужно обратиться к документации за пределами учебного руководства – см. [*Расширенное руководство по логированию*](https://python-all.ru/3.3/howto/logging.html#logging-advanced-tutorial).152153### Логирование переменных данных154155Для логирования переменных данных используется строка формата сообщения описания события, а сами переменные данные передаются в качестве аргументов. Например:156157```python158import logging159logging.warning('%s before you %s', 'Look', 'leap!')160```161162выведет:163164```python165WARNING:root:Look before you leap!166```167168Как вы можете видеть, встраивание переменных данных в сообщение описания события использует старый формат %-стиля строк. Это сделано для обратной совместимости: пакет logging появился раньше более новых возможностей форматирования, таких как [`str.format()`](https://python-all.ru/3.3/library/stdtypes.html#str.format) и [`string.Template`](https://python-all.ru/3.3/library/string.html#string.Template). Эти более новые варианты форматирования *поддерживаются*, но их подробное рассмотрение выходит за рамки данного руководства: см. [*Использование определённых стилей форматирования в вашем приложении*](https://python-all.ru/3.3/howto/logging-cookbook.html#formatting-styles) для получения дополнительной информации.169170### Изменение формата отображаемых сообщений171172Для изменения формата отображения сообщений нужно указать нужный формат:173174```python175import logging176logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)177logging.debug('This message should appear on the console')178logging.info('So should this')179logging.warning('And this, too')180```181182что выведет:183184```python185DEBUG:This message should appear on the console186INFO:So should this187WARNING:And this, too188```189190Обратите внимание, что ‘root’, который появлялся в предыдущих примерах, исчез. Полный список того, что может присутствовать в строках формата, можно найти в документации [*атрибутов LogRecord*](https://python-all.ru/3.3/library/logging.html#logrecord-attributes), но для простого использования достаточно *levelname* (уровень серьёзности), *message* (описание события, включая переменные данные) и, возможно, отображения времени события. Это описано в следующем разделе.191192### Отображение даты/времени в сообщениях193194Для отображения даты и времени события в строку формата помещается ‘%(asctime)s’:195196```python197import logging198logging.basicConfig(format='%(asctime)s %(message)s')199logging.warning('is when this event was logged.')200```201202что выведет примерно следующее:203204```python2052010-12-12 11:41:42,612 is when this event was logged.206```207208Формат отображения даты/времени по умолчанию (показан выше) – ISO8601. Если требуется более гибкое управление форматированием даты/времени, передайте аргумент *datefmt* в `basicConfig`, как в этом примере:209210```python211import logging212logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')213logging.warning('is when this event was logged.')214```215216что отобразит примерно следующее:217218```python21912/12/2010 11:46:36 AM is when this event was logged.220```221222Формат аргумента *datefmt* такой же, как поддерживается [`time.strftime()`](https://python-all.ru/3.3/library/time.html#time.strftime).223224### Следующие шаги225226На этом базовое руководство заканчивается. Этого должно быть достаточно, чтобы начать работу с логированием. Пакет logging предлагает гораздо больше возможностей, но чтобы извлечь из него максимум, потребуется уделить немного времени чтению следующих разделов. Если готовы, возьмите любимый напиток и продолжайте.227228Если ваши потребности в логировании просты, используйте приведённые выше примеры для включения логирования в ваши скрипты. Если вы столкнётесь с проблемами или что-то будет непонятно, задайте вопрос в группе Usenet comp.lang.python (доступна по адресу [http://groups.google.com/group/comp.lang.python](https://python-all.ru/3.3/howto/logging.html)), и вы получите помощь в ближайшее время.229230Всё ещё здесь? Можно продолжить чтение следующих разделов, которые представляют собой немного более продвинутое/углублённое руководство по сравнению с базовым. После этого можно заглянуть в [*Logging Cookbook*](https://python-all.ru/3.3/howto/logging-cookbook.html#logging-cookbook).231232## Расширенное руководство по логированию233234Библиотека logging использует модульный подход и предлагает несколько категорий компонентов: регистраторы, обработчики, фильтры и форматировщики.235236- Регистраторы предоставляют интерфейс, который напрямую используется кодом приложения.237- Обработчики отправляют записи журнала (созданные регистраторами) в соответствующее назначение.238- Фильтры предоставляют более детальный механизм для определения того, какие записи журнала выводить.239- Форматировщики определяют расположение записей журнала в конечном выводе.240241Информация о событии логирования передаётся между логгерами, обработчиками, фильтрами и форматировщиками в экземпляре [`LogRecord`](https://python-all.ru/3.3/library/logging.html#logging.LogRecord).242243Логирование выполняется вызовом методов экземпляров класса [`Logger`](https://python-all.ru/3.3/library/logging.html#logging.Logger) (далее называемых *логгерами*). Каждый экземпляр имеет имя, и они концептуально организованы в иерархию пространств имён с использованием точек в качестве разделителей. Например, логгер с именем «scan» является родителем для логгеров «scan.text», «scan.html» и «scan.pdf». Имена логгеров могут быть любыми и указывают на область приложения, в которой возникает логируемое сообщение.244245Хороший подход при именовании логгеров – использовать модульный логгер в каждом модуле, где используется логирование, названный следующим образом:246247```python248logger = logging.getLogger(__name__)249```250251Это означает, что имена логгеров отслеживают иерархию пакетов/модулей, и из одного только имени логгера интуитивно понятно, где регистрируются события.252253Корень иерархии логгеров называется корневым логгером. Это логгер, используемый функциями [`debug()`](https://python-all.ru/3.3/library/logging.html#logging.debug), [`info()`](https://python-all.ru/3.3/library/logging.html#logging.info), [`warning()`](https://python-all.ru/3.3/library/logging.html#logging.warning), [`error()`](https://python-all.ru/3.3/library/logging.html#logging.error) и [`critical()`](https://python-all.ru/3.3/library/logging.html#logging.critical), которые просто вызывают одноимённый метод корневого логгера. Функции и методы имеют одинаковые сигнатуры. Имя корневого логгера выводится как «root» в залогированном выводе.254255It is, of course, possible to log messages to different destinations. Support is included in the package for writing log messages to files, HTTP GET/POST locations, email via SMTP, generic sockets, queues, or OS-specific logging mechanisms such as syslog or the Windows NT event log. Destinations are served by *handler* classes. You can create your own log destination class if you have special requirements not met by any of the built-in handler classes.256257По умолчанию ни для каких сообщений логирования не задан получатель. Можно указать получатель (например, консоль или файл) с помощью [`basicConfig()`](https://python-all.ru/3.3/library/logging.html#logging.basicConfig), как в примерах руководства. Если вызвать функции [`debug()`](https://python-all.ru/3.3/library/logging.html#logging.debug), [`info()`](https://python-all.ru/3.3/library/logging.html#logging.info), [`warning()`](https://python-all.ru/3.3/library/logging.html#logging.warning), [`error()`](https://python-all.ru/3.3/library/logging.html#logging.error) и [`critical()`](https://python-all.ru/3.3/library/logging.html#logging.critical), они проверят, не задан ли получатель; и если он не задан, они установят получатель – консоль (`sys.stderr`) и формат по умолчанию для отображаемого сообщения, а затем делегируют корневому логгеру фактический вывод сообщения.258259Формат по умолчанию, устанавливаемый [`basicConfig()`](https://python-all.ru/3.3/library/logging.html#logging.basicConfig) для сообщений:260261```python262severity:logger name:message263```264265Это можно изменить, передав строку формата в [`basicConfig()`](https://python-all.ru/3.3/library/logging.html#logging.basicConfig) с помощью именованного аргумента *format*. Все возможные варианты построения строки формата описаны в разделе [*Объекты Formatter*](https://python-all.ru/3.3/library/logging.html#formatter-objects).266267### Поток логирования268269Поток информации о событиях логирования в логгерах и обработчиках показан на следующей диаграмме.270271272273### Логгеры274275Объекты [`Logger`](https://python-all.ru/3.3/library/logging.html#logging.Logger) выполняют тройную задачу. Во-первых, они предоставляют несколько методов для кода приложения, чтобы приложения могли логировать сообщения во время выполнения. Во-вторых, объекты-логгеры определяют, какие сообщения логирования обрабатывать, на основе уровня серьёзности (стандартный механизм фильтрации) или объектов-фильтров. В-третьих, объекты-логгеры передают соответствующие сообщения всем заинтересованным обработчикам.276277Наиболее часто используемые методы объектов логгера делятся на две категории: настройка и отправка сообщений.278279Ниже приведены наиболее распространённые методы настройки:280281- [`Logger.setLevel()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.setLevel) задаёт самый низкий уровень серьёзности сообщений, которые будет обрабатывать логгер, где debug – это самый низкий встроенный уровень, а critical – самый высокий. Например, если уровень серьёзности – INFO, логгер будет обрабатывать только сообщения уровней INFO, WARNING, ERROR и CRITICAL, игнорируя сообщения DEBUG.282- [`Logger.addHandler()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.addHandler) и [`Logger.removeHandler()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.removeHandler) добавляют и удаляют объекты-обработчики из объекта-логгера. Обработчики подробно рассматриваются в разделе [*Обработчики*](https://python-all.ru/3.3/howto/logging.html#handler-basic).283- [`Logger.addFilter()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.addFilter) и [`Logger.removeFilter()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.removeFilter) добавляют и удаляют объекты фильтров из объекта логгера. Фильтры подробно описаны в [*Объекты фильтров*](https://python-all.ru/3.3/library/logging.html#filter).284285Необязательно всегда вызывать эти методы для каждого создаваемого регистратора. См. два последних абзаца в этом разделе.286287После настройки объекта регистратора следующие методы создают сообщения журнала:288289- [`Logger.debug()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.debug), [`Logger.info()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.info), [`Logger.warning()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.warning), [`Logger.error()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.error) и [`Logger.critical()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.critical) создают записи лога с сообщением и уровнем, соответствующими их именам методов. Сообщение – это строка формата, которая может содержать стандартный синтаксис подстановки строк `%s`, `%d`, `%f` и так далее. Остальные аргументы – список объектов, соответствующих полям подстановки в сообщении. Что касается `**kwargs`, методы логирования учитывают только ключевое слово `exc_info` и используют его для определения, нужно ли записывать информацию об исключении.290- [`Logger.exception()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.exception) создает сообщение лога, аналогичное [`Logger.error()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.error). Отличие в том, что [`Logger.exception()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.exception) выводит вместе с ним трассировку стека. Вызывайте этот метод только из обработчика исключений.291- [`Logger.log()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.log) принимает уровень лога в качестве явного аргумента. Это немного более многословно для записи сообщений, чем использование удобных методов уровня лога, перечисленных выше, но именно так производится логирование на пользовательских уровнях лога.292293[`getLogger()`](https://python-all.ru/3.3/library/logging.html#logging.getLogger) возвращает ссылку на экземпляр логгера с указанным именем, если оно задано, или на `корневой` логгер, если нет. Имена представляют собой иерархические структуры, разделенные точками. Многократные вызовы [`getLogger()`](https://python-all.ru/3.3/library/logging.html#logging.getLogger) с одним и тем же именем возвращают ссылку на один и тот же объект логгера. Логгеры, находящиеся ниже в иерархическом списке, являются дочерними по отношению к логгерам, находящимся выше в списке. Например, для логгера с именем `foo` логгеры с именами `foo.bar`, `foo.bar.baz` и `foo.bam` являются потомками `foo`.294295Loggers have a concept of *effective level*. If a level is not explicitly set on a logger, the level of its parent is used instead as its effective level. If the parent has no explicit level set, *its* parent is examined, and so on - all ancestors are searched until an explicitly set level is found. The root logger always has an explicit level set (`WARNING` by default). When deciding whether to process an event, the effective level of the logger is used to determine whether the event is passed to the logger’s handlers.296297Дочерние логгеры передают сообщения обработчикам, связанным с их родительскими логгерами. По этой причине нет необходимости определять и настраивать обработчики для всех логгеров, которые использует приложение. Достаточно настроить обработчики для логгера верхнего уровня и создавать дочерние логгеры по мере необходимости. (Однако можно отключить передачу, установив атрибут *propagate* логгера в *False*.)298299### Обработчики300301Объекты `Handler` отвечают за отправку соответствующих сообщений лога (на основе их уровня серьезности) в указанное место назначения. Объекты [`Logger`](https://python-all.ru/3.3/library/logging.html#logging.Logger) могут добавлять к себе ноль или более объектов обработчиков с помощью метода [`addHandler()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.addHandler). В качестве примера: приложение может захотеть отправлять все сообщения лога в файл, все сообщения уровня error и выше в stdout, а все сообщения уровня critical на адрес электронной почты. Для этого сценария требуется три отдельных обработчика, каждый из которых отвечает за отправку сообщений определенного уровня серьезности в определенное место.302303Стандартная библиотека включает довольно много типов обработчиков (см. [*Полезные обработчики*](https://python-all.ru/3.3/howto/logging.html#useful-handlers)); в примерах учебных пособий в основном используются [`StreamHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.StreamHandler) и [`FileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.FileHandler).304305В обработчике очень мало методов, которые должны беспокоить разработчиков приложений. Единственные методы обработчика, актуальные для разработчиков, использующих встроенные объекты-обработчики (то есть не создающих собственные обработчики), – это следующие методы настройки:306307- Метод [`setLevel()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.setLevel), как и в объектах логгера, задает минимальный уровень серьезности, который будет отправлен в соответствующее место назначения. Почему существует два метода `setLevel()`? Уровень, заданный в логгере, определяет, сообщения какой серьезности он будет передавать своим обработчикам. Уровень, заданный в каждом обработчике, определяет, какие сообщения этот обработчик будет отправлять дальше.308- [`setFormatter()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.setFormatter) выбирает объект Formatter для использования этим обработчиком.309- [`addFilter()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.addFilter) и [`removeFilter()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.removeFilter) соответственно настраивают и отключают объекты фильтров на обработчиках.310311Прикладной код не должен напрямую создавать и использовать экземпляры `Handler`. Вместо этого класс `Handler` является базовым классом, который определяет интерфейс, который должны иметь все обработчики, и устанавливает некоторое поведение по умолчанию, которое могут использовать (или переопределять) дочерние классы.312313### Форматировщики314315Объекты Formatter настраивают окончательный порядок, структуру и содержимое сообщения лога. В отличие от базового класса `logging.Handler`, прикладной код может создавать экземпляры классов форматтеров, хотя, вероятно, можно создать подкласс форматтера, если приложению требуется особое поведение. Конструктор принимает три необязательных аргумента: строку формата сообщения, строку формата даты и индикатор стиля.316317#### `logging.Formatter.__init__(fmt=None, datefmt=None, style='%')`318319Если строка формата сообщения не задана, по умолчанию используется исходное сообщение. Если строка формата даты не задана, формат даты по умолчанию:320321```python322%Y-%m-%d %H:%M:%S323```324325с добавленными в конце миллисекундами. Стиль `style` – один из *%*, '{' или '$'. Если ни один из них не указан, будет использоваться '%'.326327Если стиль `style` – '%', строка формата сообщения использует подстановку строк в стиле `%(<dictionary key>)s`; возможные ключи задокументированы в [*атрибутах LogRecord*](https://python-all.ru/3.3/library/logging.html#logrecord-attributes). Если стиль – '{', предполагается, что строка формата сообщения совместима с [`str.format()`](https://python-all.ru/3.3/library/stdtypes.html#str.format) (с использованием именованных аргументов), а если стиль – '$', то строка формата сообщения должна соответствовать тому, что ожидается в [`string.Template.substitute()`](https://python-all.ru/3.3/library/string.html#string.Template.substitute).328329Изменено в версии 3.2: Добавлен параметр `style`.330331Следующая строка формата сообщения будет записывать время в удобочитаемом формате, уровень серьёзности сообщения и содержимое сообщения в указанном порядке:332333```python334'%(asctime)s - %(levelname)s - %(message)s'335```336337Форматтеры используют настраиваемую пользователем функцию для преобразования времени создания записи в кортеж. По умолчанию используется [`time.localtime()`](https://python-all.ru/3.3/library/time.html#time.localtime); чтобы изменить это для конкретного экземпляра форматтера, установите атрибут `converter` экземпляра на функцию с той же сигнатурой, что и [`time.localtime()`](https://python-all.ru/3.3/library/time.html#time.localtime) или [`time.gmtime()`](https://python-all.ru/3.3/library/time.html#time.gmtime). Чтобы изменить это для всех форматтеров, например, если вы хотите, чтобы все время логирования отображалось в GMT, установите атрибут `converter` в классе Formatter (на `time.gmtime` для отображения в GMT).338339### Настройка журналирования340341Программисты могут настраивать журналирование тремя способами:3423431. Создание регистраторов, обработчиков и форматировщиков явно с помощью кода Python, вызывающего перечисленные выше методы настройки.3442. Создание файла конфигурации логирования и чтение его с помощью функции [`fileConfig()`](https://python-all.ru/3.3/library/logging.config.html#logging.config.fileConfig).3453. Создание словаря с конфигурационной информацией и передача его функции [`dictConfig()`](https://python-all.ru/3.3/library/logging.config.html#logging.config.dictConfig).346347Справочную документацию по двум последним вариантам см. в разделе [*Функции конфигурации*](https://python-all.ru/3.3/library/logging.config.html#logging-config-api). Следующий пример настраивает очень простой регистратор, обработчик для консоли и простой форматировщик с помощью кода Python:348349```python350import logging351352# создать логгер353logger = logging.getLogger('simple_example')354logger.setLevel(logging.DEBUG)355356# создать обработчик консоли и установить уровень DEBUG357ch = logging.StreamHandler()358ch.setLevel(logging.DEBUG)359360# создать форматтер361formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')362363# добавить форматтер в ch364ch.setFormatter(formatter)365366# добавить ch в логгер367logger.addHandler(ch)368369# код 'приложения'370logger.debug('debug message')371logger.info('info message')372logger.warn('warn message')373logger.error('error message')374logger.critical('critical message')375```376377Запуск этого модуля из командной строки выдает следующий результат:378379```python380$ python simple_logging_module.py3812005-03-19 15:10:26,618 - simple_example - DEBUG - debug message3822005-03-19 15:10:26,620 - simple_example - INFO - info message3832005-03-19 15:10:26,695 - simple_example - WARNING - warn message3842005-03-19 15:10:26,697 - simple_example - ERROR - error message3852005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message386```387388Следующий модуль Python создает логгер, обработчик и форматтер, почти идентичные приведенным в примере выше, с единственным отличием – имена объектов.389390```python391import logging392import logging.config393394logging.config.fileConfig('logging.conf')395396# создать логгер397logger = logging.getLogger('simpleExample')398399# код 'приложения'400logger.debug('debug message')401logger.info('info message')402logger.warn('warn message')403logger.error('error message')404logger.critical('critical message')405```406407Вот файл logging.conf:408409```python410[loggers]411keys=root,simpleExample412413[handlers]414keys=consoleHandler415416[formatters]417keys=simpleFormatter418419[logger_root]420level=DEBUG421handlers=consoleHandler422423[logger_simpleExample]424level=DEBUG425handlers=consoleHandler426qualname=simpleExample427propagate=0428429[handler_consoleHandler]430class=StreamHandler431level=DEBUG432formatter=simpleFormatter433args=(sys.stdout,)434435[formatter_simpleFormatter]436format=%(asctime)s - %(name)s - %(levelname)s - %(message)s437datefmt=438```439440Результат почти идентичен примеру без файла конфигурации:441442```python443$ python simple_logging_config.py4442005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message4452005-03-19 15:38:55,979 - simpleExample - INFO - info message4462005-03-19 15:38:56,054 - simpleExample - WARNING - warn message4472005-03-19 15:38:56,055 - simpleExample - ERROR - error message4482005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message449```450451Видно, что подход с файлом конфигурации имеет несколько преимуществ перед подходом с кодом Python: в первую очередь разделение конфигурации и кода, а также возможность для не-программистов легко изменять параметры журналирования.452453> **Предупреждение**454>455> Функция [`fileConfig()`](https://python-all.ru/3.3/library/logging.config.html#logging.config.fileConfig) принимает параметр по умолчанию `disable_existing_loggers`, который по умолчанию равен `True` по причинам обратной совместимости. Это может быть как то, что вам нужно, так и нет, поскольку это приведет к отключению всех логгеров, существовавших до вызова [`fileConfig()`](https://python-all.ru/3.3/library/logging.config.html#logging.config.fileConfig), если они (или их предок) не указаны явно в конфигурации. Пожалуйста, обратитесь к справочной документации для получения дополнительной информации и укажите `False` для этого параметра, если хотите.456>457> Словарь, передаваемый в [`dictConfig()`](https://python-all.ru/3.3/library/logging.config.html#logging.config.dictConfig), также может указывать логическое значение с ключом `disable_existing_loggers`, который, если не указан явно в словаре, по умолчанию интерпретируется как `True`. Это приводит к описанному выше поведению отключения логгеров, что может быть не тем, что вам нужно – в этом случае укажите ключ явно со значением `False`.458459Обратите внимание, что имена классов, на которые ссылаются в файлах конфигурации, должны быть либо относительными по отношению к модулю logging, либо абсолютными значениями, которые можно разрешить с помощью обычных механизмов импорта. Таким образом, можно использовать либо [`WatchedFileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.WatchedFileHandler) (относительно модуля logging), либо `mypackage.mymodule.MyHandler` (для класса, определенного в пакете `mypackage` и модуле `mymodule`, где `mypackage` доступен в пути импорта Python).460461В Python 3.2 был представлен новый способ настройки журналирования с использованием словарей для хранения информации о конфигурации. Он предоставляет расширенный функционал по сравнению с подходом на основе файлов конфигурации, описанным выше, и является рекомендуемым методом настройки для новых приложений и развертываний. Поскольку для хранения информации о конфигурации используется словарь Python, и вы можете заполнять этот словарь различными способами, у вас появляется больше возможностей для настройки. Например, вы можете использовать файл конфигурации в формате JSON или, если у вас есть доступ к функциям обработки YAML, файл в формате YAML для заполнения словаря конфигурации. Или, конечно, вы можете создать словарь в коде Python, получить его в сериализованном виде через сокет или использовать любой другой подход, подходящий для вашего приложения.462463Вот пример той же конфигурации, что и выше, в формате YAML для нового подхода на основе словарей:464465```python466version: 1467formatters:468 simple:469 format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'470handlers:471 console:472 class: logging.StreamHandler473 level: DEBUG474 formatter: simple475 stream: ext://sys.stdout476loggers:477 simpleExample:478 level: DEBUG479 handlers: [console]480 propagate: no481root:482 level: DEBUG483 handlers: [console]484```485486Для получения дополнительной информации о журналировании с использованием словаря см. [*функции конфигурации*](https://python-all.ru/3.3/library/logging.config.html#logging-config-api).487488### Что произойдет, если конфигурация не предоставлена489490Если конфигурация логирования не предоставлена, возможна ситуация, когда необходимо вывести событие логирования, но не найдено ни одного обработчика для его вывода. Поведение пакета logging в таких обстоятельствах зависит от версии Python.491492Для версий Python до 3.2 поведение следующее:493494- Если *logging.raiseExceptions* равно *False* (рабочий режим), событие молча отбрасывается.495- Если *logging.raiseExceptions* равно *True* (режим разработки), сообщение 'No handlers could be found for logger X.Y.Z' печатается один раз.496497В Python 3.2 и новее поведение следующее:498499- Событие выводится с помощью «обработчика последней надежды», хранящегося в `logging.lastResort`. Этот внутренний обработчик не связан ни с одним логгером и действует как [`StreamHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.StreamHandler), который записывает описание события в текущее значение `sys.stderr` (учитывая любые перенаправления, которые могут действовать). Никакого форматирования сообщения не производится – выводится только голое описание события. Уровень обработчика установлен на `WARNING`, поэтому все события этого и более высоких уровней серьезности будут выводиться.500501Чтобы получить поведение, существовавшее до версии 3.2, `logging.lastResort` можно установить в *None*.502503### Настройка журналирования для библиотеки504505При разработке библиотеки, которая использует логирование, следует позаботиться о документировании того, как библиотека использует логирование – например, имена используемых логгеров. Также необходимо уделить внимание конфигурации логирования. Если использующее приложение не использует логирование, а код библиотеки выполняет вызовы логирования, то (как описано в предыдущем разделе) события уровня `WARNING` и выше будут выводиться в `sys.stderr`. Это считается наилучшим поведением по умолчанию.506507Если по какой-то причине *не* нужно, чтобы эти сообщения выводились при отсутствии конфигурации логирования, можно прикрепить ничего не делающий обработчик к корневому регистратору библиотеки. Это предотвратит вывод сообщения, поскольку для событий библиотеки всегда будет найден обработчик – просто он не будет ничего выводить. Если пользователь библиотеки настраивает логирование для приложения, то, предположительно, эта конфигурация добавит обработчики, и при правильной настройке уровней вызовы логирования в коде библиотеки будут отправлять вывод на эти обработчики, как обычно.508509В пакет logging включен обработчик, который ничего не делает: [`NullHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.NullHandler) (начиная с Python 3.1). Экземпляр этого обработчика можно добавить к корневому логгеру пространства имен логирования, используемого библиотекой (*если* вы хотите предотвратить вывод событий логирования вашей библиотеки в `sys.stderr` при отсутствии конфигурации логирования). Если все логирование библиотеки *foo* выполняется с использованием логгеров с именами, соответствующими шаблону 'foo.x', 'foo.x.y' и т.д., то код:510511```python512import logging513logging.getLogger('foo').addHandler(logging.NullHandler())514```515516должен дать желаемый эффект. Если организация выпускает несколько библиотек, то имя логгера может быть 'orgname.foo', а не просто 'foo'.517518> **Примечание**519>520> Настоятельно рекомендуется *не добавлять никаких обработчиков, кроме* [`NullHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.NullHandler), *в логгеры вашей библиотеки*. Это связано с тем, что конфигурация обработчиков является прерогативой разработчика приложения, использующего вашу библиотеку. Разработчик приложения знает свою целевую аудиторию и то, какие обработчики наиболее подходят для его приложения: если добавлять обработчики «под капотом», это может помешать его возможности проводить модульные тесты и доставлять журналы, соответствующие его требованиям.521522## Уровни журналирования523524Числовые значения уровней журналирования приведены в следующей таблице. Они представляют интерес в первую очередь, если вы хотите определить собственные уровни и хотите, чтобы они имели определенные значения относительно предопределенных уровней. Если вы определяете уровень с тем же числовым значением, он перезаписывает предопределенное значение; предопределенное имя теряется.525526| Уровень | Числовое значение |527| --- | --- |528| `CRITICAL` | 50 |529| `ERROR` | 40 |530| `WARNING` | 30 |531| `INFO` | 20 |532| `DEBUG` | 10 |533| `NOTSET` | 0 |534535Уровни также могут быть связаны с логгерами: они устанавливаются разработчиком или загружаются из сохраненной конфигурации журналирования. Когда на логгере вызывается метод журналирования, логгер сравнивает свой собственный уровень с уровнем, связанным с вызовом метода. Если уровень логгера выше уровня вызова метода, сообщение журналирования фактически не создается. Это базовый механизм, управляющий подробностью вывода журналирования.536537Сообщения журнала кодируются как экземпляры класса [`LogRecord`](https://python-all.ru/3.3/library/logging.html#logging.LogRecord). Когда средство журналирования решает зарегистрировать событие, из сообщения создаётся экземпляр [`LogRecord`](https://python-all.ru/3.3/library/logging.html#logging.LogRecord).538539Сообщения журнала проходят через механизм диспетчеризации с помощью *обработчиков* – экземпляров подклассов класса `Handler`. Обработчики отвечают за то, чтобы зарегистрированное сообщение (в виде [`LogRecord`](https://python-all.ru/3.3/library/logging.html#logging.LogRecord)) попало в нужное место (или набор мест), полезное для целевой аудитории этого сообщения (например, конечные пользователи, сотрудники техподдержки, системные администраторы, разработчики). Обработчикам передаются экземпляры [`LogRecord`](https://python-all.ru/3.3/library/logging.html#logging.LogRecord), предназначенные для конкретных назначений. Каждое средство журналирования может иметь ноль, один или несколько обработчиков (через метод [`addHandler()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.addHandler) класса [`Logger`](https://python-all.ru/3.3/library/logging.html#logging.Logger)). Помимо обработчиков, напрямую связанных со средством журналирования, *для диспетчеризации сообщения вызываются все обработчики всех его предков* (если только флаг *propagate* не установлен в ложное значение – в этом случае передача предкам прекращается).540541Как и у средств журналирования, у обработчиков могут быть уровни. Уровень обработчика действует как фильтр так же, как уровень средства журналирования. Если обработчик решает передать событие, используется метод [`emit()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.emit) для отправки сообщения по назначению. Большинству определённых пользователем подклассов `Handler` потребуется переопределить этот [`emit()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.emit).542543### Пользовательские уровни544545Определение собственных уровней возможно, но обычно в этом нет необходимости, так как существующие уровни были выбраны на основе практического опыта. Однако если вы уверены, что вам нужны пользовательские уровни, делайте это с большой осторожностью, и это, возможно, *очень плохая идея определять пользовательские уровни, если вы разрабатываете библиотеку*. Это связано с тем, что если несколько авторов библиотек определят свои собственные пользовательские уровни, то вывод журнала от таких нескольких библиотек, используемых вместе, будет трудно контролировать и/или интерпретировать разработчику-пользователю, так как одно и то же числовое значение может означать разные вещи для разных библиотек.546547## Полезные обработчики548549Помимо базового класса `Handler`, предоставляется множество полезных подклассов:5505511. Экземпляры [`StreamHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.StreamHandler) отправляют сообщения в потоки (объекты, подобные файлам).5522. Экземпляры [`FileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.FileHandler) отправляют сообщения в файлы на диске.5533. [`BaseRotatingHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.BaseRotatingHandler) – базовый класс для обработчиков, выполняющих ротацию файлов журнала в определённый момент. Он не предназначен для прямого создания экземпляров. Вместо него используйте [`RotatingFileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.RotatingFileHandler) или [`TimedRotatingFileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler).5544. Экземпляры [`RotatingFileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.RotatingFileHandler) отправляют сообщения в файлы на диске с поддержкой максимального размера файла журнала и ротации.5555. Экземпляры [`TimedRotatingFileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler) отправляют сообщения в файлы на диске, выполняя ротацию через заданные временные интервалы.5566. [`SocketHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.SocketHandler) отправляют сообщения в TCP/IP сокеты.5577. [`DatagramHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.DatagramHandler) отправляют сообщения в UDP сокеты.5588. Экземпляры [`SMTPHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.SMTPHandler) отправляют сообщения на указанный адрес электронной почты.5599. Экземпляры [`SysLogHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.SysLogHandler) отправляют сообщения демону syslog Unix, возможно, на удалённой машине.56010. Экземпляры [`NTEventLogHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.NTEventLogHandler) отправляют сообщения в журнал событий Windows NT/2000/XP.56111. Экземпляры [`MemoryHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.MemoryHandler) отправляют сообщения в буфер в памяти, который сбрасывается при выполнении определённых условий.56212. Экземпляры [`HTTPHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.HTTPHandler) отправляют сообщения на HTTP-сервер, используя семантику `GET` или `POST`.56313. Экземпляры [`WatchedFileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.WatchedFileHandler) следят за файлом, в который ведут журнал. Если файл изменяется, он закрывается и открывается заново по тому же имени. Этот обработчик полезен только в Unix-подобных системах; Windows не поддерживает используемый механизм.56414. Экземпляры [`QueueHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.QueueHandler) отправляют сообщения в очередь, например реализованную в модулях [`queue`](https://python-all.ru/3.3/library/queue.html#module-queue) или [`multiprocessing`](https://python-all.ru/3.3/library/multiprocessing.html#module-multiprocessing).56515. Экземпляры [`NullHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.NullHandler) ничего не делают с сообщениями об ошибках. Они используются разработчиками библиотек, которые хотят применять журналирование, но избежать сообщения «No handlers could be found for logger XXX», которое может появляться, если пользователь библиотеки не настроил журналирование. Подробнее см. [*Настройка журналирования для библиотеки*](https://python-all.ru/3.3/howto/logging.html#library-config).566567Новое в версии 3.1: Класс [`NullHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.NullHandler).568569Новое в версии 3.2: Класс [`QueueHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.QueueHandler).570571Классы [`NullHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.NullHandler), [`StreamHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.StreamHandler) и [`FileHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.FileHandler) определены в основном пакете logging. Остальные обработчики определены в подмодуле [`logging.handlers`](https://python-all.ru/3.3/library/logging.handlers.html#module-logging.handlers). (Существует также ещё один подмодуль, [`logging.config`](https://python-all.ru/3.3/library/logging.config.html#module-logging.config), для функций настройки.)572573Зарегистрированные сообщения форматируются для отображения через экземпляры класса [`Formatter`](https://python-all.ru/3.3/library/logging.html#logging.Formatter). Они инициализируются форматной строкой, подходящей для использования с оператором % и словарём.574575Для форматирования нескольких сообщений в пакете можно использовать экземпляры `BufferingFormatter`. Помимо форматной строки (которая применяется к каждому сообщению в пакете), предусмотрены форматные строки для заголовка и окончания.576577Когда фильтрации по уровню средства журналирования и/или обработчика недостаточно, экземпляры [`Filter`](https://python-all.ru/3.3/library/logging.html#logging.Filter) можно добавить как к [`Logger`](https://python-all.ru/3.3/library/logging.html#logging.Logger), так и к `Handler` (через их метод [`addFilter()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.addFilter)). Прежде чем принять решение обрабатывать сообщение дальше, и средства журналирования, и обработчики запрашивают разрешение у всех своих фильтров. Если какой-либо фильтр возвращает ложное значение, сообщение дальше не обрабатывается.578579Базовая функциональность [`Filter`](https://python-all.ru/3.3/library/logging.html#logging.Filter) позволяет фильтровать по конкретному имени средства журналирования. Если эта возможность используется, через фильтр пропускаются сообщения, отправленные указанному средству журналирования и его дочерним элементам, а все остальные отбрасываются.580581## Исключения, возникшие во время журналирования582583Пакет logging спроектирован таким образом, чтобы проглатывать исключения, возникающие при журналировании в рабочей среде. Это делается для того, чтобы ошибки, возникающие при обработке событий журналирования – такие как неверная конфигурация журналирования, сетевые или другие подобные ошибки – не приводили к преждевременному завершению приложения, использующего журналирование.584585Исключения [`SystemExit`](https://python-all.ru/3.3/library/exceptions.html#SystemExit) и [`KeyboardInterrupt`](https://python-all.ru/3.3/library/exceptions.html#KeyboardInterrupt) никогда не поглощаются. Другие исключения, возникающие во время выполнения метода [`emit()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.emit) подкласса `Handler`, передаются его методу [`handleError()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.handleError).586587Реализация [`handleError()`](https://python-all.ru/3.3/library/logging.html#logging.Handler.handleError) по умолчанию в `Handler` проверяет, установлена ли переменная уровня модуля `raiseExceptions`. Если установлена, трассировка выводится в [`sys.stderr`](https://python-all.ru/3.3/library/sys.html#sys.stderr). Если не установлена, исключение подавляется.588589> **Примечание**590>591> Значение `raiseExceptions` по умолчанию – `True`. Это связано с тем, что в процессе разработки обычно требуется получать уведомления о любых возникших исключениях. Рекомендуется устанавливать `raiseExceptions` в `False` для использования в промышленной эксплуатации.592593## Использование произвольных объектов в качестве сообщений594595В предыдущих разделах и примерах предполагалось, что сообщение, передаваемое при регистрации события, является строкой. Однако это не единственная возможность. В качестве сообщения можно передать произвольный объект, и его метод [`__str__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__str__) будет вызван, когда системе логирования потребуется преобразовать его в строковое представление. Более того, при желании можно вообще избежать вычисления строкового представления – например, [`SocketHandler`](https://python-all.ru/3.3/library/logging.handlers.html#logging.handlers.SocketHandler) отправляет событие, сериализуя его модулем pickle и передавая по сети.596597## Оптимизация598599Форматирование аргументов сообщения откладывается до последней возможности. Однако вычисление аргументов, передаваемых методу логирования, также может быть дорогостоящим, и возможно, вы захотите избежать этого, если регистратор все равно отбросит ваше событие. Чтобы решить, что делать, можно вызвать метод [`isEnabledFor()`](https://python-all.ru/3.3/library/logging.html#logging.Logger.isEnabledFor), который принимает аргумент уровня и возвращает true, если Logger создаст событие для вызова этого уровня. Можно написать такой код:600601```python602if logger.isEnabledFor(logging.DEBUG):603 logger.debug('Message with %s, %s', expensive_func1(),604 expensive_func2())605```606607чтобы, если порог регистратора установлен выше `DEBUG`, вызовы `expensive_func1()` и `expensive_func2()` никогда не выполнялись.608609Существуют и другие оптимизации, которые можно выполнить для конкретных приложений, требующих более точного контроля над тем, какая информация логирования собирается. Вот список действий, которые можно предпринять, чтобы избежать ненужной обработки во время логирования:610611| Что не нужно собирать | Как избежать сбора |612| --- | --- |613| Информация о том, откуда были сделаны вызовы. | Установить `logging._srcfile` в `None`. |614| Информация о потоках. | Установите `logging.logThreads` в `0`. |615| Информация о процессе. | Установите `logging.logProcesses` в `0`. |616617Также обратите внимание, что основной модуль логирования включает только базовые обработчики. Если не импортировать [`logging.handlers`](https://python-all.ru/3.3/library/logging.handlers.html#module-logging.handlers) и [`logging.config`](https://python-all.ru/3.3/library/logging.config.html#module-logging.config), они не будут занимать память.618619> **См. также**620>621> **Модуль [`logging`](https://python-all.ru/3.3/library/logging.html#module-logging)**622>623> Справочник API для модуля logging.624>625> **Модуль [`logging.config`](https://python-all.ru/3.3/library/logging.config.html#module-logging.config)**626>627> API конфигурации для модуля logging.628>629> **Модуль [`logging.handlers`](https://python-all.ru/3.3/library/logging.handlers.html#module-logging.handlers)**630>631> Полезные обработчики, входящие в состав модуля logging.632>633> [*Кулинарная книга по логированию*](https://python-all.ru/3.3/howto/logging-cookbook.html#logging-cookbook)634