- Определение
- Использование – когда нужно логирование
- Уровни журналирования
-
Модуль logging
-
Logger-объекты
- Propagate
- setLevel(level)
- IsEnablefFor(level)
- getEffectiveLevel()
- getChild(suffix)
- Debug(msg), *args, **kwargs)
- Info/warning/error/critical(msg, *args, **kwargs)
- Log(level, msg, *args, **kwargs)
- Exception(msg, *args, **kwargs)
- addFilter(filter)
- removeFilter(filter)
- Filter(record)
- addHandler(hdlr)
- removeHandler(hdlr)
- findCaller(stack_info=False, stacklevel=1)
- Handle(record)
- makeRecord(name. Level, fn, ino, msg, args, exc_info, func-None, extra=None, sinfo=None)
- hasHandlers()
- Форматирование журнала
- Обработчик журналов
- Диспетчер журналирования
-
Способы записи
- Советы по журналированию
Python – язык программирования, который поддерживает множество разнообразных и полезных инструментов для разработки программного обеспечения. Он часто используется для бизнес-приложений, а также для небольших игр. В крупных проектах может служить в качестве вспомогательного инструмента.
Зная возможности Python, программист сможет понять, что именно он способен реализовать в своих приложениях. Сегодня предстоит познакомиться с таким процессом, как логирование (Python logging). Также необходимо разобраться с тем, что собой представляют логи. Дополнительно будут внимательно изучены методы и атрибуты, позволяющие осуществлять логирование.
Предложенная информация рассчитана на широкий круг лиц. Она в большей степени подойдет опытным разработчикам, планирующим начать работу с логированием. Новичкам соответствующие сведения тоже пригодятся, но усвоение материала может быть для них на первых порах трудноватым.
Определение
Python logging – это логирование или журналирование. Так называется средства отслеживания событий, происходящих в процессе запуска того или иного программного обеспечения.
Разработчик при использовании logging добавляет свой код вызова журналирования, чтобы указать, что произошли те или иные события. Событие определяется в качестве сообщения-описания, опционально содержащее изменяющиеся данные – те, которые потенциально могут меняться (различаться) для каждого наступившего события. Каждое событие имеет так называемую важность. Разработчик придает ее каждому «происшествию». Важность – это еще и уровень/серьезность.
Использование – когда нужно логирование
Журналирование (или логирование) – процедура, которая может оказаться очень полезной. Ее необходимо грамотно использовать в своих проектах. Logging предлагает множество полезных функций, которые могут быть задействованы в рассматриваемой операции.
Вот таблица, которая поможет понять, когда целесообразно использовать print() для выполнения тех или иных задач, а когда – пользоваться logging:
Выполняемая процедураОптимальный инструмент для решения поставленной задачиВывод информации в консоли для обычного использования сценария командной строки или программного обеспеченияprint()Вывод сообщений о событиях, которые происходят в процессе нормального функционирования программного обеспечения. Примером может служить мониторинг состояний или отслеживание неисправностейLogging.info(). Если необходимо добиться очень подробного вывода в целях дальнейшей диагностики, требуется использовать функцию logging.debug()Вывод предупреждений о событиях в процессе выполненияWarnings.warn() – в коде библиотеки используется, если проблема может быть устранена, а клиентское приложение – должно быть изменено, чтобы исключить предупреждениеLogging.warning() – используется, если клиентская программа никак не реагирует на ситуацию, но событие все равно требует фиксации Отображение сообщения об ошибке, которая связана с событием во время исполненияПрограммист должен воспользоваться вызовом исключенияВывод сообщения о подавлении ошибки без обращения к вызову исключений. В качестве примера можно привести ситуацию с нахождением обработчика ошибок в длительном серверном процессеВ зависимости от ошибки и области применения программного обеспечения могут использоваться функции logging.error(), logging.exception(), logging.critical()
Предложенная информация поможет понять, в каких случаях print() использовать не рекомендуется.
Уровни журналирования
Уровни журналирования соотносятся с важностью (или серьезностью) имеющегося лога: информация об ошибке должна быть важнее предупреждения. Отладочный журнал должен быть полезен только в процессе отладки используемого программного обеспечения.
В Python существуют шесть уровней логирования. Каждый из них получил собственное целое число, указывающее на важность лога.
Уровень логаОписаниеЧисло, указывающее на важностьNOTSETИспользуется при создании средства ведения журнала. Приводит к обработке всех сообщений, если логгер является корневым, или к делегации родительскому объекту – если логгер не является корневым. Корневой логгер создается с уровнем WARNING.0DEBUGВывод подробной информации. Обычно соответствующие данные представляют интерес только для диагностики ошибок и неполадок.10INFOПодтверждение нормальной (ожидаемой) работы программного продукта20WARNINGСсылка на то, что в процессе работы произошло что-то неожиданное. Данный уровень также указывает на вероятность появления проблем в программном обеспечении в будущем. Примером может служить сообщение о недостаточном количестве пространства на жестком диске. Исходное приложение в соответствующем случае все еще работает нормально.30ERRORВозникновение более серьезных сбоев, при которых программное обеспечение не смогло выполнить ту или иную функцию.40CRITICALУровень, ссылающийся на очень серьезную (критическую) ошибку. Он указывает на то, что программное обеспечение больше не может продолжать дальнейшее функционирование.50
По умолчанию журналирование получает уровень WARNING. Это значит, что отслеживаться будут только события этого уровня или выше при условии, что пакет the logging Python не настроен на другие операции.
Все представленные уровни являются последовательно упорядоченными. Это значит, что актуально следующее выражение:
DEBUG < INFO < WARNING < ERROR < CRITICAL
Отдельного внимания требует NOTSET. Этот уровень будет рассмотрен более подробно, но чуть позже. Для начала необходимо запомнить, что отслеживаемые события могут быть обработаны различными способами. Наиболее простым вариантом является их вывод на консоль. Второй подход к реализации поставленной задачи – это запись логов в отдельный файл на жестком диске устройства. Эти операции тоже будут рассмотрены более подробно, но сначала предстоит получше познакомиться с главным модулем логирования Python.
Модуль logging
The logging Python – это модуль, который определяет функции и классы, отвечающие за гибкую систему журналирования. Он активно используется как программистами-новичками, так и опытными специалистами. В основном применяется большинством сторонних библиотек Python. За счет этого the logging может интегрировать логи с сообщениями разнообразных библиотек рассматриваемого языка для формирования единого журнала логов в итоговом программном обеспечении.
Основным преимуществом API-журналирования является то, что в логировании могут участвовать любые Python-модули. Это дает возможность включать собственные сообщения в программу, которые будут интегрированы с сообщениями от сторонних модулей.
The logging – модуль, оснащенный большой функциональностью. Он является достаточно быстрым. Распространяется в составе стандартной Python-библиотеки.
Для добавления упомянутого модуля необходимо написать следующую строчку в исходном коде программного обеспечения:
Import logging
Перед активным использованием журналирования необходимо ознакомиться с его классами и методами. Эта информация представлена ниже.
Logger-объекты
Логгеры имеют разнообразные атрибуты и методы. Для них не допускается создание экземпляров напрямую. Вместо этого разработчику необходимо вызвать функцию logger.getLogger(name) на уровне модуля. Несколько вызовов getLogger() с одним и тем же именем будут всегда производить возврат ссылки на один и тот же logger-объект.
Name – это потенциально иерархическое значение, которое разделяется точками. Точки могут отсутствовать, если имя состоит из одного слова. Представленные ниже логгеры размещаются в порядке иерархии. Они – потомки логгеров, размещенных в списке позициями выше.
Пример – логгер с именем foo. Его потомками будут foo.bar, foo.bam, foo.bar.baz. Иерархия имен логгеров будет точно такой же, как и иерархия Python-пакетов.
Далее будут представлены методы класса logging.loder. У этого класса есть разнообразные методы и атрибуты. Он является основным в рассматриваемом модуле.
Propagate
Если у атрибута устанавливается истинное значение, события, которые были зарегистрированы в соответствующем логгере, передаются обработчикам более высокого уровня (предкам) дополнительно к любым обработчикам, подключенным к данному логгеру. Сообщения будут передаваться непосредственно обработчикам логгеров предков – ни фильтры, ни их уровни не принимаются во внимание.
Если атрибут propagate принимает значение false, сообщения журнала передаваться обработчикам логирования не будут. По умолчанию для соответствующего атрибута устанавливается значение True.
setLevel(level)
Используется для установки уровня лога. Сообщения журнала, которые менее важные, чем установленный параметр level, будут проигнорированы системой. Если уровень серьезности у сообщения равен или больше level, они будут выводиться обработчиком (или обработчиками), если для его (их) уровней не задан более высокий уровень серьезности, чем level.
В процессе создания журналирования устанавливается уровень NOTSET. Это приводит к тому, что все сообщения будут обрабатываться согласно указанным в таблице выше инструкциям.
«Делегирование родителю» – это термин, который означает, что, если у логгера установлен уровень NOTSET, цепочка его логгеров-предков будет просматриваться до тех пор, пока не будет обнаружен предок с отличным от NOTSET уровнем. Также просмотр заканчивается при достижении корня.
Если система обнаружит предка с отличным от NOTSET-уровнем, его уровень будет рассматриваться как эффективный для журнала, с которого начался поиск предка. Соответствующее значение используется для определения дальнейших принципов обработки событий.
Если достигнут корень, но у него установлен уровень NOTSET, все сообщения будут обрабатываться системой. Иначе корневой уровень рассматривается в качестве эффективного.
IsEnablefFor(level)
Используется для указания факта обработки имеющимся логгером сообщения с серьезностью level. Здесь происходит следующее:
- Метод осуществляет проверку уровня модуля, установленного logging.disable(level).
- После соответствующей проверки определяется эффективный уровень. Делается это при помощи getEffectiveLevel().
Существуют и другие интересные и полезные методы рассматриваемого класса. Каждый из них должен быть изучен перед непосредственным журналированием.
getEffectiveLevel()
Помогает указать эффективный уровень для имеющегося журнала (логгера). Если значение соответствующего параметра отличается от NOTSET, а также оно было установлено через setLevel(), оно будет возвращено. В противном случае иерархия будет возвращаться к корню до обнаружения значения, отличного от NOTSET. В конечном итоге соответствующий параметр тоже будет возвращен.
Возвращаемое значение – это целое число. Обычно оно представлено logging.DEBUG, logging.INFO и так далее.
getChild(suffix)
Отвечает за возврат логгера-потомка заданного журнала, как определено суффиксом. Это значит, что logging.getLogger(‘abc’).getChild(‘def.ghi’) будет возвращать тот же логгер, что и logging.getLogger(‘abc.def.ghi’).
Соответствующий метод удобен, когда родительский логгер именуется с использованием отличной от литеральной строки элементом. Примером может служить __name__.
Debug(msg), *args, **kwargs)
Метод регистрации сообщений с DEBUG-уровнем. Здесь:
- msg – это строка формата сообщения;
- args – аргументы, которые будут объединены в msg с использованием оператора форматирования строки;
- kwargs – проверка четырех аргументов. К ним относят exc_info, stack_info, extra, stacklevel.
Если exc_info не имеет значения False, информация об исключении будет добавлена в сообщение журнала. При предоставлении кортежа исключения или экземпляра исключения соответствующие элементы будут успешно использованы. Иначе для получения данных об исключении нужно вызвать sys.exc_info().
Stack_info – это еще один необязательный ключевой аргумент. По умолчанию у него установлено значение False. Если оно меняется на True, данные о стеке будут добавлены к logging-сообщению, включая фактический вызов логирования.
Stacklevel имеет значение по умолчанию 1. Если оно больше, при вычислении номера строки и имени функции, заданных в LogRecord, будет пропускаться соответствующее количество фреймов стека.
Extra – аргумент, который может быть использован для передачи словаря, используемого для заполнения __dict__ LogRecord, сформированного для the logging Python.
Info/warning/error/critical(msg, *args, **kwargs)
Info отвечает за регистрацию сообщения с INFO-уровнем в журнале. Все аргументы здесь будут интерпретироваться в качестве debug().
При помощи методов error и critical будут регистрироваться сообщения с соответствующими уровнями. Аргументы, как и в предыдущем случае, интерпретируются в виде debug().
Отдельного внимания требует warning. Отвечает за регистрацию сообщений WARNING-уровня с аргументами debug(). Но в the Python есть устаревший метод для аналогичной операции. Он носит название warn. Задействовать его в программном коде не рекомендуется, хоть и принцип работы у него точно такой же, как и у метода warning.
Log(level, msg, *args, **kwargs)
Метод, который осуществляет запись в установленный логгер сообщения с целочисленным level-уровнем. В нем все остальные параметры (аргументы) будут интерпретированы как debug().
Exception(msg, *args, **kwargs)
Метод, который используется для регистрации сообщений с ERROR-уровнем в logging. Аргументы тут будут интерпретированы как debug().
При использовании соответствующего метода информация об исключении добавляется в сообщение журнала. Вызывается он только из обработчика исключений.
addFilter(filter)
Используется для добавления указанного фильтра (filter) к логгеру.
removeFilter(filter)
Удаляет заданный фильтр из логгера.
Filter(record)
Используется, если запись должна пройти обработку. Этот метод позволяет применить фильтры Python logger к записи и вернуть True-значение.
Просмотр фильтров осуществляется поочередно. Происходит это до тех пор, пока один из них не вернет ложное значение. Если этого так и не произошло, запись будет передана обработчикам. В противном случае дальнейшая ее обработка не производится.
addHandler(hdlr)
Метод, добавляющий указанный обработчик к logging.
removeHandler(hdlr)
Используется для удаления обработчика из logging.
findCaller(stack_info=False, stacklevel=1)
Метод, который:
- Обнаруживает исходник имени файла и номер строки.
- Возвращает имя файла, номер строки, имя функции и информацию о стеке в виде кортежа из 4-х элементов.
- Если stack_info не является TRUE, система вернут None.
Stacklavel будет передан из кода, который отвечает за возврат debug() и другие API. При значении более единицы, избыток используется для пропуска стековых фреймов перед определением возвращаемых значений. Этот прием особо полезен при вызове logging API из кода помощника/оболочки, чтобы информация в журнале событий относилась не к коду помощника/оболочки, а к коду, который отвечает за его вызов.
Handle(record)
Метод, который будет обрабатывать запись и передавать ее всем обработчикам, имеющим связь с логгером и его предками. Это происходит до тех пор, пока система не обнаружит propagate=False.
Соответствующий метод используется для записей, полученных из сокета, а также записей, созданных локально. Фильтрация на уровне logging Python производится при помощи filter().
makeRecord(name. Level, fn, ino, msg, args, exc_info, func-None, extra=None, sinfo=None)
Фабричный метод. Используется для переопределения подкласса для создания специализированных экземпляров LogRecord.
hasHandlers()
Используется для проверки факта настройки для логгеров тех или иных обработчиков. Процедура выполняется путем поиска обработчиков в логгере и его родительских компонентах. Значение True возвращается, если обработчик найден. В противном случае метод возвращает False.
HasHandlers() прекращает иерархический поиск тогда, когда система обнаруживает logger с атрибутом propagate, установленным в False.
Форматирование журнала
Форматирование журнала – это то, что поможет дополнить сообщение, выводимое системой, полезной контекстной информацией. В основном для реализации соответствующей операции используются ранее представленные методы.
С помощью форматирования журнала можно понять:
- когда была сделана соответствующая запись;
- из какого участка приложения поступило сообщение;
- потоки и процессы.
Форматирование журнала имеет огромное значение для отладки многопоточных проектов. Вот один из простейших примеров ее реализации. Речь идет о форматировании записи «hello world»:
В logging соответствующая информация будет отображена так:
Теперь можно более подробно рассмотреть другие важные аспекты logging.
Обработчик журналов
Обработчик журналирования – это специальный элемент, который отвечает за запись и отображение логов в программном обеспечении. StreamHandler будет выводить запись на консоль, а FileHandler – в файл, SMTPHandler – отправлять их сообщения на электронную почту.
Каждый обработчик поддерживает два ключевых поля:
- Форматер. Он отвечает за добавление в лог контекстной информации.
- Уровень лога. Служит для фильтрования журналов низшего уровня. Обработчик INFO-уровня не будет работать с журналами DEBUG-уровня.
Стандартная библиотека Python включает в себя обработчики, которых обычно достаточно для работы с приложениями. К ним относят StreamHandler и FileHandler.
Выше можно увидеть программный код их реализации.
Диспетчер журналирования
Диспетчер журналирования – то, что будет использоваться в программных кодах чаще всего. Этот элемент также является основным источником наибольших проблем в процессе разработки программного обеспечения.
Диспетчер журналирования может быть создан при помощи такого кодового фрагмента:
Он включает в себя три ключевых поля:
- Распространение. Это то, что определяет необходимость обработки logging (лога) родительским диспетчером. В настройках по умолчанию соответствующая опция (функция) является активной.
- Уровень. Здесь ситуация обстоит точно так же, как и в случае с обработчиком: уровень отвечает за фильтрацию менее важных журналов. Отличие заключается в том, что уровень будет проверяться исключительно в дочерних диспетчерах. Если осуществляется распространение вверх, уровень учитываться не будет.
- Список обработчиков, в которые необходимо направить попавшую в диспетчер запись. С помощью этого параметра удастся гибко настраивать обработку сообщений. В качестве примера можно создать обработчик, который будет записывать все, что имеет уровень DEBUG. А затем – обработчик для электронной почты – он будет работать только с CRITICAL-уровнем. Взаимоотношения диспетчера с обработчиками строятся, базируясь на схеме «издатель–потребитель». Запись передается всем обработчикам, стоит ей пройти уровневую проверку в диспетчере.
Имя logging диспетчера является уникальным. Это значит, что, если диспетчер с именем «toto» уже создан, последующее обращение к вызову logging.getLogger(“toto”) будет возвращать один и тот же объект.
Logging диспетчеры выстраиваются в соответствии с иерархией. На самой вершине будет находиться корневой диспетчер. Получить к нему доступ поможет logging.root(). Он вызывается при использовании методов вроде logging.warning или logging.debug. По умолчанию корневой журнал получает WARNING-уровень. Каждый журнал с меньшим уровнем будет игнорироваться.
Обработчик по умолчанию для корневого диспетчера создается автоматически. Это происходит при добавлении первой записи в журнал, выше WARNING-уровня. Обращаться к корневому диспетчеру не рекомендуется напрямую. То же самое касается методов вроде logging.debug().
Если создается новый диспетчер, в качестве родительского будет установлен корневой:
«Запись с точкой» используется диспетчером, когда есть объект, который будет дочерним по отношению к другому. Пример – объект «a.b», выступающий дочерним по отношению к «a». Этот принцип действует только при существовании «a». В противном случае родительским будет установлен корневой диспетчер.
В процессе работы диспетчера осуществляются следующие операции:
- Запись проходит фильтр по уровню.
- Проверяется не действительный, а эффективный уровень. Он обычно совпадает с диспетчерским.
- Если используется NOTSET-уровень, он будет исключением. Эффективный level будет равен level-значению первого диспетчера, расположенного выше в вертикали наследования.
По умолчанию NOTSET-уровень присваивается новому диспетчеру в logging. У корневого он будет равен WARNING. Это приводит к тому, что эффективный уровень нового тоже окажется WARNING.
Диспетчерский уровень при работе с logging используется разработчиками для пропуска записей, которые будут игнорироваться системой, если их уровни недостаточно высоки.
Способы записи
Logging в общих чертах теперь понятен. Можно ознакомиться с несколькими примерами журналирования. Ранее было сказано, что допустимо сохранение путем вывода информации в консоль, а также записью в отдельный файл. Эти концепции логирования приведены ниже.
Вывод в консоль
Вот простейший пример записи информации в консоль:
Если запустить соответствующий кодовый фрагмент, на экране появится следующая картина:
INFO не появляется из-за WARNING-уровня. Распечатанное сообщение включает в себя level и описание события, представленного в вызове logging. Речь идет о «Watch out!». Фактический вывод поддерживает возможность гибкого форматирование при необходимости. Эта информация на первых порах не пригодится.
Запись в файл
Наиболее распространенный случай – запись событий журналирования в отдельный файл. Вот пример реализации соответствующего приема в программном коде:
Если открыть файл и посмотреть, что там написано, разработчик увидит:
Здесь показано, как можно установить уровень журналирования, который действует в качестве порога для отслеживания.
Если хочется установить уровень журналирования при помощи параметра командной строки, рекомендуется использовать запись:
- -log=INFO
Теперь можно ознакомиться с лучшими практиками в процессе реализации logging.
Советы по журналированию
А вот несколько простых советов, которые помогут при журналировании:
- Не использовать только один корневой логгер. Это связано с тем, что контроль над ним сильно ограничен, а регистраторами управлять весьма проблематично. Лучше создавать logging (логгеры) для каждого модуля или компонента приложения.
- Использовать правильные logging levels. Они помогают обозначать степень серьезности сообщения журнала. Это способ классификации сообщений по значимости. Levels и их значения уже были представлены выше.
- Составлять содержательные сообщения для журнала.
- Использовать % для форматирования строк. Этот прием позволяет добиться совместимости со старыми версиями Python, в которых нет поддержки f-строк. % также используется для использования более широкого диапазона типов данных и при необходимости более точно управлять исходным кодом. Оно дает более высокую производительность, чем f-строки.
- Пользоваться ведением журнала в формате JSON. Это значительно упрощает работу с logging в приложении.
- Пользоваться ротацией файлов журнала. Это периодическое создание новых файлов журнала и архивирование/удаление старых. Прием помогает управлять размерами журнальных файлов, а также повышать производительность программы, упрощать отладку и повышать безопасность исходного проекта. Ротация может производиться по времени, размеру или гибридно.
Особенности logging были представлены выше. Это – всего лишь начало изучения журналирования. Быстрее и лучше разобраться с ним помогут дистанционные компьютерные курсы.
Интересует Python? Добро пожаловать на курс в Otus!
<!DOCTYPE html>
<html dir="ltr" lang="ru-RU">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="profile" href="http://gmpg.org/xfn/11" />
<title>Логирование в Python OTUS</title>
<!-- All in One SEO 4.5.2.1 - aioseo.com -->
<meta name="description" content="Python – язык программирования, который поддерживает множество разнообразных и полезных инструментов для разработки программного обеспечения. Он часто используется для бизнес-приложений, а также для небольших игр. В крупных проектах может служить в качестве вспомогательного инструмента. Зная возможности Python, программист сможет понять, что именно он способен реализовать в своих приложениях. Сегодня предстоит познакомиться с таким процессом, как" />
<meta name="robots" content="max-image-preview:large" />
<link rel="canonical" href="https://otus.ru/journal/logirovanie-v-python/" />
<meta name="generator" content="All in One SEO (AIOSEO) 4.5.2.1" />
<script type="application/ld+json" class="aioseo-schema">
{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#article","name":"\u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Python OTUS","headline":"\u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Python","author":{"@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author"},"publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2024\/07\/oj-1080x720-2024-07-14T181234.352.jpg","width":2245,"height":1587},"datePublished":"2024-07-14T15:12:49+00:00","dateModified":"2024-07-14T15:14:13+00:00","inLanguage":"ru-RU","mainEntityOfPage":{"@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#webpage"},"isPartOf":{"@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#webpage"},"articleSection":"\u041f\u043e\u043b\u0435\u0437\u043d\u043e\u0435, Python"},{"@type":"BreadcrumbList","@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/#listItem","position":1,"name":"\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430","item":"https:\/\/otus.ru\/journal\/","nextItem":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#listItem"},{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#listItem","position":2,"name":"\u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Python","previousItem":"https:\/\/otus.ru\/journal\/#listItem"}]},{"@type":"Organization","@id":"https:\/\/otus.ru\/journal\/#organization","name":"\u041e\u0442\u0443\u0441 \u043e\u043d\u043b\u0430\u0439\u043d-\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435","url":"https:\/\/otus.ru\/journal\/","sameAs":["https:\/\/www.youtube.com\/channel\/UCetgtvy93o3i3CvyGXKFU3g"],"contactPoint":{"@type":"ContactPoint","telephone":"+74999389202","contactType":"Customer Support"}},{"@type":"Person","@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author","url":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/","name":"A. Pavlenko","image":{"@type":"ImageObject","@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/d4c499a104d7c2522fa41f89e6819499?s=96&d=mm&r=g","width":96,"height":96,"caption":"A. Pavlenko"}},{"@type":"WebPage","@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#webpage","url":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/","name":"\u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Python OTUS","description":"Python \u2013 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0445 \u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f. \u041e\u043d \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438\u0433\u0440. \u0412 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u0443\u0436\u0438\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430. \u0417\u043d\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 Python, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0442\u0430\u043a\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c, \u043a\u0430\u043a","inLanguage":"ru-RU","isPartOf":{"@id":"https:\/\/otus.ru\/journal\/#website"},"breadcrumb":{"@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#breadcrumblist"},"author":{"@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author"},"creator":{"@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2024\/07\/oj-1080x720-2024-07-14T181234.352.jpg","@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#mainImage","width":2245,"height":1587},"primaryImageOfPage":{"@id":"https:\/\/otus.ru\/journal\/logirovanie-v-python\/#mainImage"},"datePublished":"2024-07-14T15:12:49+00:00","dateModified":"2024-07-14T15:14:13+00:00"},{"@type":"WebSite","@id":"https:\/\/otus.ru\/journal\/#website","url":"https:\/\/otus.ru\/journal\/","name":"OTUS JOURNAL","description":"Blog about IT","inLanguage":"ru-RU","publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"}}]}
</script>
<!-- All in One SEO -->
<link rel='dns-prefetch' href='//otus.ru' />
<link rel='dns-prefetch' href='//fonts.googleapis.com' />
<link rel='stylesheet' id='wp-block-library-css' href='https://otus.ru/journal/wp-includes/css/dist/block-library/style.min.css?ver=6.4.7' type='text/css' media='all' />
<style id='classic-theme-styles-inline-css' type='text/css'>
/*! This file is auto-generated */
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}
</style>
<style id='global-styles-inline-css' type='text/css'>
body{--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
.wp-block-navigation a:where(:not(.wp-element-button)){color: inherit;}
:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}
:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}
.wp-block-pullquote{font-size: 1.5em;line-height: 1.6;}
</style>
<link rel='stylesheet' id='wbcr-comments-plus-url-span-css' href='https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/css/url-span.css?ver=2.2.0' type='text/css' media='all' />
<link rel='stylesheet' id='wpel-style-css' href='https://otus.ru/journal/wp-content/plugins/wp-external-links/public/css/wpel.css?ver=2.59' type='text/css' media='all' />
<link rel='stylesheet' id='ez-toc-css' href='https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/css/screen.min.css?ver=2.0.61' type='text/css' media='all' />
<style id='ez-toc-inline-css' type='text/css'>
div#ez-toc-container .ez-toc-title {font-size: 120%;}div#ez-toc-container .ez-toc-title {font-weight: 500;}div#ez-toc-container ul li {font-size: 95%;}div#ez-toc-container nav ul ul li {font-size: 90%;}
.ez-toc-container-direction {direction: ltr;}.ez-toc-counter ul{counter-reset: item ;}.ez-toc-counter nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }.ez-toc-widget-direction {direction: ltr;}.ez-toc-widget-container ul{counter-reset: item ;}.ez-toc-widget-container nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }
</style>
<link rel='stylesheet' id='contentberg-fonts-css' href='https://fonts.googleapis.com/css?family=Roboto%3A400%2C500%2C700%7CPT+Serif%3A400%2C400i%2C600%7CIBM+Plex+Serif%3A500' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-core-css' href='https://otus.ru/journal/wp-content/themes/contentberg/style.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-lightbox-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/lightbox.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='font-awesome-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/fontawesome/css/font-awesome.min.css?ver=1.8.3' type='text/css' media='all' />
<script type="text/javascript" id="breeze-prefetch-js-extra">
/* <![CDATA[ */
var breeze_prefetch = {"local_url":"https:\/\/otus.ru\/journal","ignore_remote_prefetch":"1","ignore_list":["\/wp-admin\/"]};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/breeze/assets/js/js-front-end/breeze-prefetch-links.min.js" id="breeze-prefetch-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.min.js" id="jquery-core-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery-migrate.min.js" id="jquery-migrate-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/lazysizes.js" id="lazysizes-js"></script>
<link rel="https://api.w.org/" href="https://otus.ru/journal/wp-json/" /><link rel="alternate" type="application/json" href="https://otus.ru/journal/wp-json/wp/v2/posts/10309" /><link rel='shortlink' href='https://otus.ru/journal/?p=10309' />
<link rel="alternate" type="application/json+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Flogirovanie-v-python%2F" />
<link rel="alternate" type="text/xml+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Flogirovanie-v-python%2F&format=xml" />
<script>var Sphere_Plugin = {"ajaxurl":"https:\/\/otus.ru\/journal\/wp-admin\/admin-ajax.php"};</script><link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-32x32.png" sizes="32x32" />
<link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-180x180.png" />
<meta name="msapplication-TileImage" content="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-270x270.png" />
<style type="text/css" id="wp-custom-css">
#menu-item-10406 .wpel-icon {
display: none;
}
#menu-item-10407 .wpel-icon {
display: none;
}
.otus-login-site a .wpel-icon {
display: none;
}
.menu-menju-navykov-container a .wpel-icon {
display: none;
}
.otus-login-site a
{
background: #ffd709;
border-radius: 12px;
color: #0f0f10;
font-size: 14px;
font-weight: 700;
line-height: 20px;
display: block;
text-align: center;
padding: 8px 25px;
}
.main-footer.dark {
background: linear-gradient(90deg, #a64fc5, #4f54e6);
border-color: transparent;
}
.main-footer.bold .copyright {
color: #fff;
}
.main-footer.bold .to-top i {
color: #fff;
}
.main-footer.bold .back-to-top {
color: #fff;
}
.nav__scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.scrollable-menu .menu {
display: flex;
}
.nav__scroll
{
background: linear-gradient(90deg, #a64fc5, #4f54e6);
}
.scrollable-menu .menu .menu-item {
flex: 0 0 auto;
padding: 15px 15px;
}
.scrollable-menu .menu .menu-item a {
color: #fff;
}
.nav__scroll::-webkit-scrollbar{background-color:#fff;height:5px;}
.nav__scroll::-webkit-scrollbar-thumb{background-color:#dcdcdc;}
.nav__scroll::-webkit-scrollbar-track{-webkit-border-radius:0;border-radius:0;background-color:#fff;}/
body {
min-width: 320px;
}
.banner-click img {
margin: 0 auto;
display: block;
}
.banner-click {
cursor: pointer;
}
.banner-footer-area {
margin-bottom: 20px;
}
.banner-left-area {
margin-top: 40px;
} </style>
<!--Start VDZ Yandex Metrika Plugin-->
<!-- Yandex.Metrika counter --><script type="text/javascript" >(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");ym(34531570, "init", {clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ecommerce:"dataLayer"});</script>
<noscript><div><img src="https://mc.yandex.ru/watch/34531570" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter --><!--START ADD EVENTS FROM CF7--><script type='text/javascript'>document.addEventListener( 'wpcf7submit', function( event ) {
//event.detail.contactFormId;
if(ym){
//console.log(event.detail);
ym(34531570, 'reachGoal', 'VDZ_SEND_CONTACT_FORM_7');
ym(34531570, 'params', {
page_url: window.location.href,
status: event.detail.status,
locale: event.detail.contactFormLocale,
form_id: event.detail.contactFormId,
});
}
}, false );
</script><!--END ADD EVENTS FROM CF7-->
<!--End VDZ Yandex Metrika Plugin-->
</head>
<body class="post-template-default single single-post postid-10309 single-format-standard right-sidebar lazy-normal has-lb">
<div class="main-wrap">
<header id="main-head" class="main-head head-nav-below has-search-modal simple simple-boxed">
<div class="inner inner-head" data-sticky-bar="0">
<div class="wrap cf wrap-head">
<div class="left-contain">
<span class="mobile-nav"><i class="fa fa-bars"></i></span>
<div class="title">
<a href="https://otus.ru/journal/" title="OTUS JOURNAL" rel="home" data-wpel-link="internal">
<span class="text-logo"><img src="/journal/wp-content/themes/contentberg/img/logo_site.svg" alt="OTUS JOURNAL"></span>
</a>
</div>
</div>
<div class="navigation-wrap inline">
<nav class="navigation inline simple light" data-sticky-bar="0">
<div class="menu-rubriki-container"><ul id="menu-rubriki" class="menu"><li id="menu-item-109" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-1 menu-item-109"><a href="https://otus.ru/journal/category/pro-it/" data-wpel-link="internal"><span>Про IT</span></a></li>
<li id="menu-item-113" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-cat-4 menu-item-113"><a href="https://otus.ru/journal/category/polza/" data-wpel-link="internal"><span>Полезное</span></a></li>
<li id="menu-item-114" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-3 menu-item-114"><a href="https://otus.ru/journal/category/lifestyle/" data-wpel-link="internal"><span>Лайфстайл</span></a></li>
<li id="menu-item-10406" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10406"><a href="https://otus.ru/catalog/courses" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Обучение</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10407" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10407"><a href="https://otus.ru/about" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Информация</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </nav>
</div>
<div class="actions">
<div class="otus-login-site">
<a href="https://otus.ru/login/" target="_blank" data-wpel-link="external" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Войти<span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
<a href="#" title="Search" class="search-link"><i class="fa fa-search"></i></a>
</div>
</div>
</div>
</header> <!-- .main-head -->
<div class="nav nav_disable nav_colored nav_transparent course-categories__nav nav__scroll ">
<div class="container wrap">
<div class="links inline simple light scrollable-menu">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov" class="menu"><li id="menu-item-10413" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10414" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10415" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10416" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10417" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10418" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10419" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10420" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10421" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
</div>
</div>
<div class="main wrap">
<div class="ts-row cf">
<div class="col-8 main-content cf">
<article id="post-10309" class="the-post post-10309 post type-post status-publish format-standard has-post-thumbnail category-polza tag-python">
<header class="post-header the-post-header cf">
<div class="post-meta the-post-meta">
<span class="post-cat">
<a href="https://otus.ru/journal/category/polza/" class="category" data-wpel-link="internal">Полезное</a>
</span>
<h1 class="post-title">
Логирование в Python
</h1>
<a href="https://otus.ru/journal/logirovanie-v-python/" class="date-link" data-wpel-link="internal"><time class="post-date">14 июля, 2024</time></a>
</div>
<div class="featured">
<a href="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T181234.352.jpg" class="image-link" data-wpel-link="internal"><img width="770" height="515" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20770%20515%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-contentberg-main size-contentberg-main lazyload wp-post-image" alt="Логирование в Python" title="Логирование в Python" decoding="async" fetchpriority="high" data-srcset="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T181234.352-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T181234.352-270x180.jpg 270w" data-src="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T181234.352-770x515.jpg" data-sizes="(max-width: 770px) 100vw, 770px" /> </a>
</div>
</header><!-- .post-header -->
<div class="post-content description cf entry-content content-normal">
<div id="ez-toc-container" class="ez-toc-v2_0_61 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction">
<div class="ez-toc-title-container">
<p class="ez-toc-title " >Содержание</p>
<span class="ez-toc-title-toggle"><a href="#" class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" aria-label="Toggle Table of Content"><span class="ez-toc-js-icon-con"><span class=""><span class="eztoc-hide" style="display:none;">Toggle</span><span class="ez-toc-icon-toggle-span"><svg style="fill: #999;color:#999" xmlns="http://www.w3.org/2000/svg" class="list-377408" width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path d="M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z" fill="currentColor"></path></svg><svg style="fill: #999;color:#999" class="arrow-unsorted-368013" xmlns="http://www.w3.org/2000/svg" width="10px" height="10px" viewBox="0 0 24 24" version="1.2" baseProfile="tiny"><path d="M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z"/></svg></span></span></span></a></span></div>
<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-1" href="#%D0%9E%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5" title="Определение">Определение</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-2" href="#%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%E2%80%93_%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0_%D0%BD%D1%83%D0%B6%D0%BD%D0%BE_%D0%BB%D0%BE%D0%B3%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5" title="Использование – когда нужно логирование">Использование – когда нужно логирование</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-3" href="#%D0%A3%D1%80%D0%BE%D0%B2%D0%BD%D0%B8_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F" title="Уровни журналирования">Уровни журналирования</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-4" href="#%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_logging" title="Модуль logging">Модуль logging</a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-5" href="#Logger-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B" title="Logger-объекты">Logger-объекты</a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-6" href="#Propagate" title="Propagate">Propagate</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-7" href="#setLevellevel" title="setLevel(level)">setLevel(level)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-8" href="#IsEnablefForlevel" title="IsEnablefFor(level)">IsEnablefFor(level)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-9" href="#getEffectiveLevel" title="getEffectiveLevel()">getEffectiveLevel()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-10" href="#getChildsuffix" title="getChild(suffix)">getChild(suffix)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-11" href="#Debugmsg_args_kwargs" title="Debug(msg), *args, **kwargs)">Debug(msg), *args, **kwargs)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-12" href="#Infowarningerrorcriticalmsg_args_kwargs" title="Info/warning/error/critical(msg, *args, **kwargs)">Info/warning/error/critical(msg, *args, **kwargs)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-13" href="#Loglevel_msg_args_kwargs" title="Log(level, msg, *args, **kwargs)">Log(level, msg, *args, **kwargs)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-14" href="#Exceptionmsg_args_kwargs" title="Exception(msg, *args, **kwargs)">Exception(msg, *args, **kwargs)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-15" href="#addFilterfilter" title="addFilter(filter)">addFilter(filter)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-16" href="#removeFilterfilter" title="removeFilter(filter)">removeFilter(filter)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-17" href="#Filterrecord" title="Filter(record)">Filter(record)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-18" href="#addHandlerhdlr" title="addHandler(hdlr)">addHandler(hdlr)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-19" href="#removeHandlerhdlr" title="removeHandler(hdlr)">removeHandler(hdlr)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-20" href="#findCallerstack_infoFalse_stacklevel1" title="findCaller(stack_info=False, stacklevel=1)">findCaller(stack_info=False, stacklevel=1)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-21" href="#Handlerecord" title="Handle(record)">Handle(record)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-22" href="#makeRecordname_Level_fn_ino_msg_args_exc_info_func-None_extraNone_sinfoNone" title="makeRecord(name. Level, fn, ino, msg, args, exc_info, func-None, extra=None, sinfo=None)">makeRecord(name. Level, fn, ino, msg, args, exc_info, func-None, extra=None, sinfo=None)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class="ez-toc-link ez-toc-heading-23" href="#hasHandlers" title="hasHandlers()">hasHandlers()</a></li></ul></li></ul></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-24" href="#%D0%A4%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B0" title="Форматирование журнала">Форматирование журнала</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-25" href="#%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2" title="Обработчик журналов">Обработчик журналов</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-26" href="#%D0%94%D0%B8%D1%81%D0%BF%D0%B5%D1%82%D1%87%D0%B5%D1%80_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F" title="Диспетчер журналирования">Диспетчер журналирования</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-27" href="#%D0%A1%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%D1%8B_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8" title="Способы записи">Способы записи</a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-28" href="#%D0%92%D1%8B%D0%B2%D0%BE%D0%B4_%D0%B2_%D0%BA%D0%BE%D0%BD%D1%81%D0%BE%D0%BB%D1%8C" title="Вывод в консоль">Вывод в консоль</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-29" href="#%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D1%8C_%D0%B2_%D1%84%D0%B0%D0%B9%D0%BB" title="Запись в файл">Запись в файл</a></li></ul></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-30" href="#%D0%A1%D0%BE%D0%B2%D0%B5%D1%82%D1%8B_%D0%BF%D0%BE_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E" title="Советы по журналированию">Советы по журналированию</a></li></ul></nav></div>
<h1 class="wp-block-heading"></h1>
<p>Python – язык программирования, который поддерживает множество разнообразных и полезных инструментов для разработки программного обеспечения. Он часто используется для бизнес-приложений, а также для небольших игр. В крупных проектах может служить в качестве вспомогательного инструмента.</p>
<p>Зная возможности Python, программист сможет понять, что именно он способен реализовать в своих приложениях. Сегодня предстоит познакомиться с таким процессом, как логирование (Python logging). Также необходимо разобраться с тем, что собой представляют логи. Дополнительно будут внимательно изучены методы и атрибуты, позволяющие осуществлять логирование.</p>
<p>Предложенная информация рассчитана на широкий круг лиц. Она в большей степени подойдет опытным разработчикам, планирующим начать работу с логированием. Новичкам соответствующие сведения тоже пригодятся, но усвоение материала может быть для них на первых порах трудноватым.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9E%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5"></span>Определение<span class="ez-toc-section-end"></span></h2>
<p>Python logging – это логирование или журналирование. Так называется средства отслеживания событий, происходящих в процессе запуска того или иного программного обеспечения.</p>
<p>Разработчик при использовании logging добавляет свой код вызова журналирования, чтобы указать, что произошли те или иные события. Событие определяется в качестве сообщения-описания, опционально содержащее изменяющиеся данные – те, которые потенциально могут меняться (различаться) для каждого наступившего события. Каждое событие имеет так называемую важность. Разработчик придает ее каждому «происшествию». Важность – это еще и уровень/серьезность.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%E2%80%93_%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0_%D0%BD%D1%83%D0%B6%D0%BD%D0%BE_%D0%BB%D0%BE%D0%B3%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5"></span>Использование – когда нужно логирование<span class="ez-toc-section-end"></span></h2>
<p>Журналирование (или логирование) – процедура, которая может оказаться очень полезной. Ее необходимо грамотно использовать в своих проектах. Logging предлагает множество полезных функций, которые могут быть задействованы в рассматриваемой операции.</p>
<p>Вот таблица, которая поможет понять, когда целесообразно использовать print() для выполнения тех или иных задач, а когда – пользоваться logging:</p>
<figure class="wp-block-table"><table><tbody><tr><td>Выполняемая процедура</td><td>Оптимальный инструмент для решения поставленной задачи</td></tr><tr><td>Вывод информации в консоли для обычного использования сценария командной строки или программного обеспечения</td><td>print()</td></tr><tr><td>Вывод сообщений о событиях, которые происходят в процессе нормального функционирования программного обеспечения. Примером может служить мониторинг состояний или отслеживание неисправностей</td><td>Logging.info(). Если необходимо добиться очень подробного вывода в целях дальнейшей диагностики, требуется использовать функцию logging.debug()</td></tr><tr><td>Вывод предупреждений о событиях в процессе выполнения</td><td>Warnings.warn() – в коде библиотеки используется, если проблема может быть устранена, а клиентское приложение – должно быть изменено, чтобы исключить предупреждениеLogging.warning() – используется, если клиентская программа никак не реагирует на ситуацию, но событие все равно требует фиксации </td></tr><tr><td>Отображение сообщения об ошибке, которая связана с событием во время исполнения</td><td>Программист должен воспользоваться вызовом исключения</td></tr><tr><td>Вывод сообщения о подавлении ошибки без обращения к вызову исключений. В качестве примера можно привести ситуацию с нахождением обработчика ошибок в длительном серверном процессе</td><td>В зависимости от ошибки и области применения программного обеспечения могут использоваться функции logging.error(), logging.exception(), logging.critical()</td></tr></tbody></table></figure>
<p>Предложенная информация поможет понять, в каких случаях print() использовать не рекомендуется.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A3%D1%80%D0%BE%D0%B2%D0%BD%D0%B8_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F"></span>Уровни журналирования<span class="ez-toc-section-end"></span></h2>
<p>Уровни журналирования соотносятся с важностью (или серьезностью) имеющегося лога: информация об ошибке должна быть важнее предупреждения. Отладочный журнал должен быть полезен только в процессе отладки используемого программного обеспечения.</p>
<p>В Python существуют шесть уровней логирования. Каждый из них получил собственное целое число, указывающее на важность лога.</p>
<figure class="wp-block-table"><table><tbody><tr><td>Уровень лога</td><td>Описание</td><td>Число, указывающее на важность</td></tr><tr><td>NOTSET</td><td>Используется при создании средства ведения журнала. Приводит к обработке всех сообщений, если логгер является корневым, или к делегации родительскому объекту – если логгер не является корневым. Корневой логгер создается с уровнем WARNING.</td><td>0</td></tr><tr><td>DEBUG</td><td>Вывод подробной информации. Обычно соответствующие данные представляют интерес только для диагностики ошибок и неполадок.</td><td>10</td></tr><tr><td>INFO</td><td>Подтверждение нормальной (ожидаемой) работы программного продукта</td><td>20</td></tr><tr><td>WARNING</td><td>Ссылка на то, что в процессе работы произошло что-то неожиданное. Данный уровень также указывает на вероятность появления проблем в программном обеспечении в будущем. Примером может служить сообщение о недостаточном количестве пространства на жестком диске. Исходное приложение в соответствующем случае все еще работает нормально.</td><td>30</td></tr><tr><td>ERROR</td><td>Возникновение более серьезных сбоев, при которых программное обеспечение не смогло выполнить ту или иную функцию.</td><td>40</td></tr><tr><td>CRITICAL</td><td>Уровень, ссылающийся на очень серьезную (критическую) ошибку. Он указывает на то, что программное обеспечение больше не может продолжать дальнейшее функционирование.</td><td>50</td></tr></tbody></table></figure>
<p>По умолчанию журналирование получает уровень WARNING. Это значит, что отслеживаться будут только события этого уровня или выше при условии, что пакет the logging Python не настроен на другие операции.</p>
<p>Все представленные уровни являются последовательно упорядоченными. Это значит, что актуально следующее выражение:</p>
<p><code>DEBUG < INFO < WARNING < ERROR < CRITICAL</code></p>
<p>Отдельного внимания требует NOTSET. Этот уровень будет рассмотрен более подробно, но чуть позже. Для начала необходимо запомнить, что отслеживаемые события могут быть обработаны различными способами. Наиболее простым вариантом является их вывод на консоль. Второй подход к реализации поставленной задачи – это запись логов в отдельный файл на жестком диске устройства. Эти операции тоже будут рассмотрены более подробно, но сначала предстоит получше познакомиться с главным модулем логирования Python.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_logging"></span>Модуль logging<span class="ez-toc-section-end"></span></h2>
<p>The logging Python – это модуль, который определяет функции и классы, отвечающие за гибкую систему журналирования. Он активно используется как программистами-новичками, так и опытными специалистами. В основном применяется большинством сторонних библиотек Python. За счет этого the logging может интегрировать логи с сообщениями разнообразных библиотек рассматриваемого языка для формирования единого журнала логов в итоговом программном обеспечении.</p>
<p>Основным преимуществом API-журналирования является то, что в логировании могут участвовать любые Python-модули. Это дает возможность включать собственные сообщения в программу, которые будут интегрированы с сообщениями от сторонних модулей.</p>
<p>The logging – модуль, оснащенный большой функциональностью. Он является достаточно быстрым. Распространяется в составе стандартной Python-библиотеки.</p>
<p>Для добавления упомянутого модуля необходимо написать следующую строчку в исходном коде программного обеспечения:</p>
<p><code>Import logging</code></p>
<p>Перед активным использованием журналирования необходимо ознакомиться с его классами и методами. Эта информация представлена ниже.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Logger-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"></span>Logger-объекты<span class="ez-toc-section-end"></span></h3>
<p>Логгеры имеют разнообразные атрибуты и методы. Для них не допускается создание экземпляров напрямую. Вместо этого разработчику необходимо вызвать функцию logger.getLogger(name) на уровне модуля. Несколько вызовов getLogger() с одним и тем же именем будут всегда производить возврат ссылки на один и тот же logger-объект.</p>
<p>Name – это потенциально иерархическое значение, которое разделяется точками. Точки могут отсутствовать, если имя состоит из одного слова. Представленные ниже логгеры размещаются в порядке иерархии. Они – потомки логгеров, размещенных в списке позициями выше.</p>
<p>Пример – логгер с именем foo. Его потомками будут foo.bar, foo.bam, foo.bar.baz. Иерархия имен логгеров будет точно такой же, как и иерархия Python-пакетов.</p>
<p>Далее будут представлены методы класса logging.loder. У этого класса есть разнообразные методы и атрибуты. Он является основным в рассматриваемом модуле.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Propagate"></span><em>Propagate</em><span class="ez-toc-section-end"></span></h4>
<p>Если у атрибута устанавливается истинное значение, события, которые были зарегистрированы в соответствующем логгере, передаются обработчикам более высокого уровня (предкам) дополнительно к любым обработчикам, подключенным к данному логгеру. Сообщения будут передаваться непосредственно обработчикам логгеров предков – ни фильтры, ни их уровни не принимаются во внимание.</p>
<p>Если атрибут propagate принимает значение false, сообщения журнала передаваться обработчикам логирования не будут. По умолчанию для соответствующего атрибута устанавливается значение True.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="setLevellevel"></span><em>setLevel(level)</em><span class="ez-toc-section-end"></span></h4>
<p>Используется для установки уровня лога. Сообщения журнала, которые менее важные, чем установленный параметр level, будут проигнорированы системой. Если уровень серьезности у сообщения равен или больше level, они будут выводиться обработчиком (или обработчиками), если для его (их) уровней не задан более высокий уровень серьезности, чем level.</p>
<p>В процессе создания журналирования устанавливается уровень NOTSET. Это приводит к тому, что все сообщения будут обрабатываться согласно указанным в таблице выше инструкциям.</p>
<p>«Делегирование родителю» – это термин, который означает, что, если у логгера установлен уровень NOTSET, цепочка его логгеров-предков будет просматриваться до тех пор, пока не будет обнаружен предок с отличным от NOTSET уровнем. Также просмотр заканчивается при достижении корня.</p>
<p>Если система обнаружит предка с отличным от NOTSET-уровнем, его уровень будет рассматриваться как эффективный для журнала, с которого начался поиск предка. Соответствующее значение используется для определения дальнейших принципов обработки событий.</p>
<p>Если достигнут корень, но у него установлен уровень NOTSET, все сообщения будут обрабатываться системой. Иначе корневой уровень рассматривается в качестве эффективного.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="IsEnablefForlevel"></span><em>IsEnablefFor(level)</em><span class="ez-toc-section-end"></span></h4>
<p>Используется для указания факта обработки имеющимся логгером сообщения с серьезностью level. Здесь происходит следующее:</p>
<ol>
<li>Метод осуществляет проверку уровня модуля, установленного logging.disable(level).</li>
<li>После соответствующей проверки определяется эффективный уровень. Делается это при помощи getEffectiveLevel().</li>
</ol>
<p>Существуют и другие интересные и полезные методы рассматриваемого класса. Каждый из них должен быть изучен перед непосредственным журналированием.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="getEffectiveLevel"></span><em>getEffectiveLevel()</em><span class="ez-toc-section-end"></span></h4>
<p>Помогает указать эффективный уровень для имеющегося журнала (логгера). Если значение соответствующего параметра отличается от NOTSET, а также оно было установлено через setLevel(), оно будет возвращено. В противном случае иерархия будет возвращаться к корню до обнаружения значения, отличного от NOTSET. В конечном итоге соответствующий параметр тоже будет возвращен.</p>
<p>Возвращаемое значение – это целое число. Обычно оно представлено logging.DEBUG, logging.INFO и так далее.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="getChildsuffix"></span><em>getChild(suffix)</em><span class="ez-toc-section-end"></span></h4>
<p>Отвечает за возврат логгера-потомка заданного журнала, как определено суффиксом. Это значит, что logging.getLogger(‘abc’).getChild(‘def.ghi’) будет возвращать тот же логгер, что и logging.getLogger(‘abc.def.ghi’).</p>
<p>Соответствующий метод удобен, когда родительский логгер именуется с использованием отличной от литеральной строки элементом. Примером может служить __name__.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Debugmsg_args_kwargs"></span><em>Debug(msg), *args, **kwargs)</em><span class="ez-toc-section-end"></span></h4>
<p>Метод регистрации сообщений с DEBUG-уровнем. Здесь:</p>
<ul>
<li>msg – это строка формата сообщения;</li>
<li>args – аргументы, которые будут объединены в msg с использованием оператора форматирования строки;</li>
<li>kwargs – проверка четырех аргументов. К ним относят exc_info, stack_info, extra, stacklevel.</li>
</ul>
<p>Если exc_info не имеет значения False, информация об исключении будет добавлена в сообщение журнала. При предоставлении кортежа исключения или экземпляра исключения соответствующие элементы будут успешно использованы. Иначе для получения данных об исключении нужно вызвать sys.exc_info().</p>
<p>Stack_info – это еще один необязательный ключевой аргумент. По умолчанию у него установлено значение False. Если оно меняется на True, данные о стеке будут добавлены к logging-сообщению, включая фактический вызов логирования.</p>
<p>Stacklevel имеет значение по умолчанию 1. Если оно больше, при вычислении номера строки и имени функции, заданных в LogRecord, будет пропускаться соответствующее количество фреймов стека.</p>
<p>Extra – аргумент, который может быть использован для передачи словаря, используемого для заполнения __dict__ LogRecord, сформированного для the logging Python.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Infowarningerrorcriticalmsg_args_kwargs"></span><em>Info/warning/error/critical(msg, *args, **kwargs)</em><span class="ez-toc-section-end"></span></h4>
<p>Info отвечает за регистрацию сообщения с INFO-уровнем в журнале. Все аргументы здесь будут интерпретироваться в качестве debug().</p>
<p>При помощи методов error и critical будут регистрироваться сообщения с соответствующими уровнями. Аргументы, как и в предыдущем случае, интерпретируются в виде debug().</p>
<p>Отдельного внимания требует warning. Отвечает за регистрацию сообщений WARNING-уровня с аргументами debug(). Но в the Python есть устаревший метод для аналогичной операции. Он носит название warn. Задействовать его в программном коде не рекомендуется, хоть и принцип работы у него точно такой же, как и у метода warning.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Loglevel_msg_args_kwargs"></span><em>Log(level, msg, *args, **kwargs)</em><span class="ez-toc-section-end"></span></h4>
<p>Метод, который осуществляет запись в установленный логгер сообщения с целочисленным level-уровнем. В нем все остальные параметры (аргументы) будут интерпретированы как debug().</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Exceptionmsg_args_kwargs"></span><em>Exception(msg, *args, **kwargs)</em><span class="ez-toc-section-end"></span></h4>
<p>Метод, который используется для регистрации сообщений с ERROR-уровнем в logging. Аргументы тут будут интерпретированы как debug().</p>
<p>При использовании соответствующего метода информация об исключении добавляется в сообщение журнала. Вызывается он только из обработчика исключений.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="addFilterfilter"></span><em>addFilter(filter)</em><span class="ez-toc-section-end"></span></h4>
<p>Используется для добавления указанного фильтра (filter) к логгеру.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="removeFilterfilter"></span><em>removeFilter(filter)</em><span class="ez-toc-section-end"></span></h4>
<p>Удаляет заданный фильтр из логгера.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Filterrecord"></span><em>Filter(record)</em><span class="ez-toc-section-end"></span></h4>
<p>Используется, если запись должна пройти обработку. Этот метод позволяет применить фильтры Python logger к записи и вернуть True-значение.</p>
<p>Просмотр фильтров осуществляется поочередно. Происходит это до тех пор, пока один из них не вернет ложное значение. Если этого так и не произошло, запись будет передана обработчикам. В противном случае дальнейшая ее обработка не производится.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="addHandlerhdlr"></span><em>addHandler(hdlr)</em><span class="ez-toc-section-end"></span></h4>
<p>Метод, добавляющий указанный обработчик к logging.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="removeHandlerhdlr"></span><em>removeHandler(hdlr)</em><span class="ez-toc-section-end"></span></h4>
<p>Используется для удаления обработчика из logging.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="findCallerstack_infoFalse_stacklevel1"></span><em>findCaller(stack_info=False, stacklevel=1)</em><span class="ez-toc-section-end"></span></h4>
<p>Метод, который:</p>
<ol>
<li>Обнаруживает исходник имени файла и номер строки.</li>
<li>Возвращает имя файла, номер строки, имя функции и информацию о стеке в виде кортежа из 4-х элементов.</li>
<li>Если stack_info не является TRUE, система вернут None.</li>
</ol>
<p>Stacklavel будет передан из кода, который отвечает за возврат debug() и другие API. При значении более единицы, избыток используется для пропуска стековых фреймов перед определением возвращаемых значений. Этот прием особо полезен при вызове logging API из кода помощника/оболочки, чтобы информация в журнале событий относилась не к коду помощника/оболочки, а к коду, который отвечает за его вызов.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="Handlerecord"></span><em>Handle(record)</em><span class="ez-toc-section-end"></span></h4>
<p>Метод, который будет обрабатывать запись и передавать ее всем обработчикам, имеющим связь с логгером и его предками. Это происходит до тех пор, пока система не обнаружит propagate=False.</p>
<p>Соответствующий метод используется для записей, полученных из сокета, а также записей, созданных локально. Фильтрация на уровне logging Python производится при помощи filter().</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="makeRecordname_Level_fn_ino_msg_args_exc_info_func-None_extraNone_sinfoNone"></span><em>makeRecord(name. Level, fn, ino, msg, args, exc_info, func-None, extra=None, sinfo=None)</em><span class="ez-toc-section-end"></span></h4>
<p>Фабричный метод. Используется для переопределения подкласса для создания специализированных экземпляров LogRecord.</p>
<h4 class="wp-block-heading"><span class="ez-toc-section" id="hasHandlers"></span><em>hasHandlers()</em><span class="ez-toc-section-end"></span></h4>
<p>Используется для проверки факта настройки для логгеров тех или иных обработчиков. Процедура выполняется путем поиска обработчиков в логгере и его родительских компонентах. Значение True возвращается, если обработчик найден. В противном случае метод возвращает False.</p>
<p>HasHandlers() прекращает иерархический поиск тогда, когда система обнаруживает logger с атрибутом propagate, установленным в False.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A4%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B0"></span>Форматирование журнала<span class="ez-toc-section-end"></span></h2>
<p>Форматирование журнала – это то, что поможет дополнить сообщение, выводимое системой, полезной контекстной информацией. В основном для реализации соответствующей операции используются ранее представленные методы.</p>
<p>С помощью форматирования журнала можно понять:</p>
<ul>
<li>когда была сделана соответствующая запись;</li>
<li>из какого участка приложения поступило сообщение;</li>
<li>потоки и процессы.</li>
</ul>
<p>Форматирование журнала имеет огромное значение для отладки многопоточных проектов. Вот один из простейших примеров ее реализации. Речь идет о форматировании записи «hello world»:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXezd3a-EHivA7xsOhKlqG3I38bPybt-n710tJGjGRolLEjUe-uTH-FRR7wzBm468xYMxyHfKiDTOmF-eh6ot8V7_1KvAzA2BHZRm1X_ZXossOMtBhMW7qi87YPAocKkdEaTBBHbBN4xXbPnmOJ8w8ro-rHdFgxygyKqzdUUN24iNjyZChIkmWA?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>В logging соответствующая информация будет отображена так:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXfuoQM8xkGAEmo3Owaj9T-nAPJu4pV9fg0dBhFXlUL9QeVZ7IDyGiAXf8eDmaxwXJLHNe30K6eXmJhXdyI-awVKaUf9o3oWVNu8Ag3jwthH1w4wdwLk9C9wBKp7KbZAJ0qHHbzPg13OKcDWWTLX41NGoaoR0jvHPRLGqX-4xON0hn04wMhGUSI?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Теперь можно более подробно рассмотреть другие важные аспекты logging.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2"></span>Обработчик журналов<span class="ez-toc-section-end"></span></h2>
<p>Обработчик журналирования – это специальный элемент, который отвечает за запись и отображение логов в программном обеспечении. StreamHandler будет выводить запись на консоль, а FileHandler – в файл, SMTPHandler – отправлять их сообщения на электронную почту.</p>
<p>Каждый обработчик поддерживает два ключевых поля:</p>
<ol>
<li>Форматер. Он отвечает за добавление в лог контекстной информации.</li>
<li>Уровень лога. Служит для фильтрования журналов низшего уровня. Обработчик INFO-уровня не будет работать с журналами DEBUG-уровня.</li>
</ol>
<p>Стандартная библиотека Python включает в себя обработчики, которых обычно достаточно для работы с приложениями. К ним относят StreamHandler и FileHandler.</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXfjB0AhaEKjLAGk0NAcMw9q9rCTVvgTPIgIoMCXelF7C6hJQQ0DHB4qE-EezHxLNVdOS30Hz9uBQKEXWCIdn6tIexdCeRcngZPe-9O2g_OIf2Dq3PRO0oV8XqQN6_bXKw2rKi5u-kBSz9lhCW0c9wcX814l9Gf7IoQMX9VeNtZEV0mXIvde5-Q?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Выше можно увидеть программный код их реализации.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%94%D0%B8%D1%81%D0%BF%D0%B5%D1%82%D1%87%D0%B5%D1%80_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F"></span>Диспетчер журналирования<span class="ez-toc-section-end"></span></h2>
<p>Диспетчер журналирования – то, что будет использоваться в программных кодах чаще всего. Этот элемент также является основным источником наибольших проблем в процессе разработки программного обеспечения.</p>
<p>Диспетчер журналирования может быть создан при помощи такого кодового фрагмента:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXdLICOYHPUkxb7DZV82mjwaKFgMH8bzR1iXxrvNcoIOwJjNAhj1vgduABMkU7Tkj7rRLkzZKsHdw9Y7ljd_wydoP99I7k598JMy5fZrWgcfCfjo-r9GhzsUfkIWSAa1w25RkRSah0sNDFC30_tvyWH-7P1h9aWw48u9mBgV4e-XEAjKrFBRbCc?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Он включает в себя три ключевых поля:</p>
<ol>
<li>Распространение. Это то, что определяет необходимость обработки logging (лога) родительским диспетчером. В настройках по умолчанию соответствующая опция (функция) является активной.</li>
<li>Уровень. Здесь ситуация обстоит точно так же, как и в случае с обработчиком: уровень отвечает за фильтрацию менее важных журналов. Отличие заключается в том, что уровень будет проверяться исключительно в дочерних диспетчерах. Если осуществляется распространение вверх, уровень учитываться не будет.</li>
<li>Список обработчиков, в которые необходимо направить попавшую в диспетчер запись. С помощью этого параметра удастся гибко настраивать обработку сообщений. В качестве примера можно создать обработчик, который будет записывать все, что имеет уровень DEBUG. А затем – обработчик для электронной почты – он будет работать только с CRITICAL-уровнем. Взаимоотношения диспетчера с обработчиками строятся, базируясь на схеме «издатель–потребитель». Запись передается всем обработчикам, стоит ей пройти уровневую проверку в диспетчере.</li>
</ol>
<p>Имя logging диспетчера является уникальным. Это значит, что, если диспетчер с именем «toto» уже создан, последующее обращение к вызову logging.getLogger(“toto”) будет возвращать один и тот же объект.</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXcGj_85z5H2CQT39VNW50g3s8iHHeEhswLMhqv0i0SIVDarIqldrXtgCrfULHULcs00jNMkfi3CR6fQZg5wS9bhVczqYIB3Ym5GKry5EIUcB1VT3Sdi6Of0xHv-NB5uamo49T49WipbePovLB8JUM8nwI3Sjlu82O1YSYfQ9d_EZ8DmFcZ9XXw?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Logging диспетчеры выстраиваются в соответствии с иерархией. На самой вершине будет находиться корневой диспетчер. Получить к нему доступ поможет logging.root(). Он вызывается при использовании методов вроде logging.warning или logging.debug. По умолчанию корневой журнал получает WARNING-уровень. Каждый журнал с меньшим уровнем будет игнорироваться.</p>
<p>Обработчик по умолчанию для корневого диспетчера создается автоматически. Это происходит при добавлении первой записи в журнал, выше WARNING-уровня. Обращаться к корневому диспетчеру не рекомендуется напрямую. То же самое касается методов вроде logging.debug().</p>
<p>Если создается новый диспетчер, в качестве родительского будет установлен корневой:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXdp0mLhTAZwf2DFTYq7bk_zdxUTwvyWe9wlTxJ6HDMJs5eI_D7jpRUKcc5UWcKI6k9hgZq_tckuMdu9KrGZKT2iq0zZwSSXfgmHX27-F8QmYJ5b74CB4nS2OWNrdVCbNx5fa-bLLZt8qymSqHj1y7fki_LrMZCHXjrOvuGs9EmxWP9qfaDI7K4?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>«Запись с точкой» используется диспетчером, когда есть объект, который будет дочерним по отношению к другому. Пример – объект «a.b», выступающий дочерним по отношению к «a». Этот принцип действует только при существовании «a». В противном случае родительским будет установлен корневой диспетчер.</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXdFGLNh_uAAesPoQk411cbY-16vI2Bsh-IIMF-EtV4fP4H_BWsx10vLJPl8NERfk4Ucb0xzzW33dsa1W4GzRHy4lQGXG47InmqINAse0PzNVuzhpco_pE7HKLkQHYGL3zOXj61aNrYuUZRP0qZKmmten3n2nevnOgO2o5QhMsOaLBt2TpQHr3E?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>В процессе работы диспетчера осуществляются следующие операции:</p>
<ol>
<li>Запись проходит фильтр по уровню.</li>
<li>Проверяется не действительный, а эффективный уровень. Он обычно совпадает с диспетчерским.</li>
<li>Если используется NOTSET-уровень, он будет исключением. Эффективный level будет равен level-значению первого диспетчера, расположенного выше в вертикали наследования.</li>
</ol>
<p>По умолчанию NOTSET-уровень присваивается новому диспетчеру в logging. У корневого он будет равен WARNING. Это приводит к тому, что эффективный уровень нового тоже окажется WARNING.</p>
<p>Диспетчерский уровень при работе с logging используется разработчиками для пропуска записей, которые будут игнорироваться системой, если их уровни недостаточно высоки.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A1%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%D1%8B_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8"></span>Способы записи<span class="ez-toc-section-end"></span></h2>
<p>Logging в общих чертах теперь понятен. Можно ознакомиться с несколькими примерами журналирования. Ранее было сказано, что допустимо сохранение путем вывода информации в консоль, а также записью в отдельный файл. Эти концепции логирования приведены ниже.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="%D0%92%D1%8B%D0%B2%D0%BE%D0%B4_%D0%B2_%D0%BA%D0%BE%D0%BD%D1%81%D0%BE%D0%BB%D1%8C"></span>Вывод в консоль<span class="ez-toc-section-end"></span></h3>
<p>Вот простейший пример записи информации в консоль:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXdmhbMb4Vx1W3QyqFbj5D_PuSL9wf3M20Mx40eiFTxy8PiKhspQaNFa22k_0R5w549XptiZYrSEHHXvU8VfTBPIcYhWsw-VE3jfOePiYQ_GQLzXf5LIcVrZp_kDgaSF6JjKLVXMceVAnsMX_tPCyrI3UmOAaEbH1WuruNK5BXJc6U6rIj7z6A?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Если запустить соответствующий кодовый фрагмент, на экране появится следующая картина:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXeGsXZFKnG9t5aSVe54LEzBc5CF0wyBMpHFV-idCFtarp6s8B-gEim3Puw8zlLC84h_Fxv8py8Q6skU0rs42M_dK4zvozOhIFDVJVx8ihxm1_KKcWBAVJCK9GwBh3vHzcoEZlUXH0mV7yV1l-9PF_GzZZd6gTh6WUUZzmY6tjn1RFuxCjderw?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>INFO не появляется из-за WARNING-уровня. Распечатанное сообщение включает в себя level и описание события, представленного в вызове logging. Речь идет о «Watch out!». Фактический вывод поддерживает возможность гибкого форматирование при необходимости. Эта информация на первых порах не пригодится.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D1%8C_%D0%B2_%D1%84%D0%B0%D0%B9%D0%BB"></span>Запись в файл<span class="ez-toc-section-end"></span></h3>
<p>Наиболее распространенный случай – запись событий журналирования в отдельный файл. Вот пример реализации соответствующего приема в программном коде:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXdYR2Q3tSCsBYGsnd_AUyCMigm0_sXPsnn8NSKKw1_INkf5_Z50hKDETjZulVW8tZjX5wrAM0QO5fn-sX5Drsv0oi21ujXSlk0jq9pAmDHwB1fFF2ZEYCNCjosL84kTTWEnjzelk7XnYRZ67bOx-06264GiHwLlcoG5L4WCzgFeDiTvvVQ3XZA?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Если открыть файл и посмотреть, что там написано, разработчик увидит:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/docsz/AD_4nXfE00iBvZYuCmeFyb4jnstjEiwoyShwkHMnqUej8OXcio0UGPSlYlxJiHO9EbVt2SrCjwjcRJncvk188t5eSH8an56-l3iRPZGXy7N2unWL8SzLvetCGoNP8aNkYMxGk_Q1Zz0VKfSsnaGaE2B7zc0TjAwQdt71ZGoQproB-eM7a8Npbo37LZc?key=9XNRYnDoPRYrXMfr_tTLAA" alt="Логирование в Python"/></figure>
<p>Здесь показано, как можно установить уровень журналирования, который действует в качестве порога для отслеживания.</p>
<p>Если хочется установить уровень журналирования при помощи параметра командной строки, рекомендуется использовать запись:</p>
<p><code>- -log=INFO</code></p>
<p>Теперь можно ознакомиться с лучшими практиками в процессе реализации logging.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A1%D0%BE%D0%B2%D0%B5%D1%82%D1%8B_%D0%BF%D0%BE_%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E"></span>Советы по журналированию<span class="ez-toc-section-end"></span></h2>
<p>А вот несколько простых советов, которые помогут при журналировании:</p>
<ol>
<li>Не использовать только один корневой логгер. Это связано с тем, что контроль над ним сильно ограничен, а регистраторами управлять весьма проблематично. Лучше создавать logging (логгеры) для каждого модуля или компонента приложения.</li>
<li>Использовать правильные logging levels. Они помогают обозначать степень серьезности сообщения журнала. Это способ классификации сообщений по значимости. Levels и их значения уже были представлены выше.</li>
<li>Составлять содержательные сообщения для журнала.</li>
<li>Использовать % для форматирования строк. Этот прием позволяет добиться совместимости со старыми версиями Python, в которых нет поддержки f-строк. % также используется для использования более широкого диапазона типов данных и при необходимости более точно управлять исходным кодом. Оно дает более высокую производительность, чем f-строки.</li>
<li>Пользоваться ведением журнала в формате JSON. Это значительно упрощает работу с logging в приложении.</li>
<li>Пользоваться ротацией файлов журнала. Это периодическое создание новых файлов журнала и архивирование/удаление старых. Прием помогает управлять размерами журнальных файлов, а также повышать производительность программы, упрощать отладку и повышать безопасность исходного проекта. Ротация может производиться по времени, размеру или гибридно.</li>
</ol>
<p>Особенности logging были представлены выше. Это – всего лишь начало изучения журналирования. Быстрее и лучше разобраться с ним помогут дистанционные компьютерные курсы.</p>
<p>Интересует <a href="https://otus.ru/lessons/python-professional/?utm_source=oj&utm_medium=affilate&utm_campaign=python" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external" class="wpel-icon-right">Python<span class="wpel-icon wpel-image wpel-icon-6"></span></a>? Добро пожаловать на курс в Otus!</p>
</div><!-- .post-content -->
<div class="the-post-foot cf">
<div class="tag-share cf">
<div class="post-tags"><a href="https://otus.ru/journal/tag/python/" rel="tag" data-wpel-link="internal">Python</a></div>
<div class="post-share">
<div class="post-share-icons cf">
<span class="counters">
</span>
<a href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Fotus.ru%2Fjournal%2Flogirovanie-v-python%2F" class="link facebook wpel-icon-right" target="_blank" title="Share on Facebook" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-facebook"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fotus.ru%2Fjournal%2Flogirovanie-v-python%2F&text=%D0%9B%D0%BE%D0%B3%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%B2%20Python" class="link twitter wpel-icon-right" target="_blank" title="Share on Twitter" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-twitter"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fotus.ru%2Fjournal%2Flogirovanie-v-python%2F" class="link linkedin wpel-icon-right" target="_blank" title="LinkedIn" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-linkedin"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fotus.ru%2Fjournal%2Flogirovanie-v-python%2F&media=https%3A%2F%2Fotus.ru%2Fjournal%2Fwp-content%2Fuploads%2F2024%2F07%2Foj-1080x720-2024-07-14T181234.352.jpg&description=%D0%9B%D0%BE%D0%B3%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%B2%20Python" class="link pinterest wpel-icon-right" target="_blank" title="Pinterest" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-pinterest-p"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
</div>
</div>
</div>
<div class="post-nav">
<div class="post previous cf">
<a href="https://otus.ru/journal/selektory-kratko-o-glavnom/" title="Prev Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-left"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/selektory-kratko-o-glavnom/" class="image-link" rel="previous" data-wpel-link="internal">
<img width="150" height="106" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20106%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="Селекторы: кратко о главном" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T173338.932-150x106.jpg 150w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T173338.932-300x212.jpg 300w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T173338.932-1024x724.jpg 1024w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T173338.932-768x543.jpg 768w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T173338.932-1536x1086.jpg 1536w" data-src="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T173338.932-150x106.jpg" data-sizes="(max-width: 150px) 100vw, 150px" title="Селекторы: кратко о главном" /> </a>
<div class="post-meta">
<span class="label">Prev Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/selektory-kratko-o-glavnom/" data-wpel-link="internal">Селекторы: кратко о главном</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/selektory-kratko-o-glavnom/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2024-07-14T14:33:53+00:00">14 июля, 2024</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">8 Mins Read</span>
</div>
</div> </div>
</span>
</div>
<div class="post next cf">
<a href="https://otus.ru/journal/cisc-risc-i-drugie-tipy-mikroprocessorov/" title="Next Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-right"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/cisc-risc-i-drugie-tipy-mikroprocessorov/" class="image-link" rel="next" data-wpel-link="internal">
<img width="150" height="106" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20106%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="CISC, RISC и другие типы микропроцессоров" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T182828.374-150x106.jpg 150w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T182828.374-300x212.jpg 300w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T182828.374-1024x724.jpg 1024w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T182828.374-768x543.jpg 768w, https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T182828.374-1536x1086.jpg 1536w" data-src="https://otus.ru/journal/wp-content/uploads/2024/07/oj-1080x720-2024-07-14T182828.374-150x106.jpg" data-sizes="(max-width: 150px) 100vw, 150px" title="CISC, RISC и другие типы микропроцессоров" /> </a>
<div class="post-meta">
<span class="label">Next Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/cisc-risc-i-drugie-tipy-mikroprocessorov/" data-wpel-link="internal">CISC, RISC и другие типы микропроцессоров</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/cisc-risc-i-drugie-tipy-mikroprocessorov/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2024-07-14T15:28:46+00:00">14 июля, 2024</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">7 Mins Read</span>
</div>
</div> </div>
</span>
</div>
</div>
<section class="related-posts grid-3">
<h4 class="section-head"><span class="title">Читать ещё</span></h4>
<div class="ts-row posts cf">
<article class="post col-4">
<a href="https://otus.ru/journal/uroven-gotovnosti-cto-k-2026/" title="Уровень готовности CTO к 2026" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Уровень готовности CTO к 2026" title="Уровень готовности CTO к 2026" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-270x180.jpg 270w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-370x245.jpg 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-270x180.jpg" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/uroven-gotovnosti-cto-k-2026/" class="post-link" data-wpel-link="internal">Уровень готовности CTO к 2026</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-16T19:50:59+00:00">16 ноября, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/novye-uroki-noyabrya-tolko-top-temy-po-programmirovaniju/" title="Новые уроки ноября: только топ-темы по программированию" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Новые уроки ноября: только топ-темы по программированию" title="Новые уроки ноября: только топ-темы по программированию" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-270x180.jpg 270w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-370x245.jpg 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-270x180.jpg" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/novye-uroki-noyabrya-tolko-top-temy-po-programmirovaniju/" class="post-link" data-wpel-link="internal">Новые уроки ноября: только топ-темы по программированию</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-09T23:24:11+00:00">9 ноября, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/schjot-idjot-na-chasy/" title="Счёт идёт на часы" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Счёт идёт на часы" title="Счёт идёт на часы" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-270x180.png 270w, https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-770x515.png 770w, https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-370x245.png 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-270x180.png" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/schjot-idjot-na-chasy/" class="post-link" data-wpel-link="internal">Счёт идёт на часы</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-10-30T15:04:59+00:00">30 октября, 2025</time>
</div>
</div>
</article >
</div>
</section>
</article> <!-- .the-post -->
</div>
<aside class="col-4 sidebar">
<div class="inner">
<ul>
<li id="search-2" class="widget widget_search"><h5 class="widget-title"><span>Поиск по блогу</span></h5>
<form method="get" class="search-form" action="https://otus.ru/journal/">
<label>
<span class="screen-reader-text">Search for:</span>
<input type="search" class="search-field" placeholder="Введите запрос и нажмите Enter" value="" name="s" title="Search for:" />
</label>
<button type="submit" class="search-submit"><i class="fa fa-search"></i></button>
</form>
</li>
<li id="tag_cloud-5" class="widget widget_tag_cloud"><h5 class="widget-title"><span>Метки</span></h5><div class="tagcloud"><a href="https://otus.ru/journal/tag/android-2/" class="tag-cloud-link tag-link-74 tag-link-position-1" style="font-size: 12.472222222222pt;" aria-label="Android (34 элемента)" data-wpel-link="internal">Android</a>
<a href="https://otus.ru/journal/tag/c-3/" class="tag-cloud-link tag-link-91 tag-link-position-2" style="font-size: 10.916666666667pt;" aria-label="C (23 элемента)" data-wpel-link="internal">C</a>
<a href="https://otus.ru/journal/tag/c-2/" class="tag-cloud-link tag-link-81 tag-link-position-3" style="font-size: 12.666666666667pt;" aria-label="C# (35 элементов)" data-wpel-link="internal">C#</a>
<a href="https://otus.ru/journal/tag/c/" class="tag-cloud-link tag-link-20 tag-link-position-4" style="font-size: 12.472222222222pt;" aria-label="c++ (34 элемента)" data-wpel-link="internal">c++</a>
<a href="https://otus.ru/journal/tag/computer-science/" class="tag-cloud-link tag-link-209 tag-link-position-5" style="font-size: 15.972222222222pt;" aria-label="computer science (78 элементов)" data-wpel-link="internal">computer science</a>
<a href="https://otus.ru/journal/tag/css/" class="tag-cloud-link tag-link-288 tag-link-position-6" style="font-size: 8.6805555555556pt;" aria-label="CSS (13 элементов)" data-wpel-link="internal">CSS</a>
<a href="https://otus.ru/journal/tag/data-science/" class="tag-cloud-link tag-link-151 tag-link-position-7" style="font-size: 8pt;" aria-label="Data Science (11 элементов)" data-wpel-link="internal">Data Science</a>
<a href="https://otus.ru/journal/tag/devops/" class="tag-cloud-link tag-link-98 tag-link-position-8" style="font-size: 10.138888888889pt;" aria-label="devops (19 элементов)" data-wpel-link="internal">devops</a>
<a href="https://otus.ru/journal/tag/docker/" class="tag-cloud-link tag-link-143 tag-link-position-9" style="font-size: 8.2916666666667pt;" aria-label="Docker (12 элементов)" data-wpel-link="internal">Docker</a>
<a href="https://otus.ru/journal/tag/gamedev/" class="tag-cloud-link tag-link-25 tag-link-position-10" style="font-size: 11.694444444444pt;" aria-label="gamedev (28 элементов)" data-wpel-link="internal">gamedev</a>
<a href="https://otus.ru/journal/tag/hr/" class="tag-cloud-link tag-link-103 tag-link-position-11" style="font-size: 8pt;" aria-label="hr (11 элементов)" data-wpel-link="internal">hr</a>
<a href="https://otus.ru/journal/tag/html/" class="tag-cloud-link tag-link-217 tag-link-position-12" style="font-size: 11.208333333333pt;" aria-label="HTML (25 элементов)" data-wpel-link="internal">HTML</a>
<a href="https://otus.ru/journal/tag/ios/" class="tag-cloud-link tag-link-101 tag-link-position-13" style="font-size: 8.9722222222222pt;" aria-label="iOS (14 элементов)" data-wpel-link="internal">iOS</a>
<a href="https://otus.ru/journal/tag/it/" class="tag-cloud-link tag-link-50 tag-link-position-14" style="font-size: 10.527777777778pt;" aria-label="IT (21 элемент)" data-wpel-link="internal">IT</a>
<a href="https://otus.ru/journal/tag/java/" class="tag-cloud-link tag-link-75 tag-link-position-15" style="font-size: 15.680555555556pt;" aria-label="Java (73 элемента)" data-wpel-link="internal">Java</a>
<a href="https://otus.ru/journal/tag/javascript/" class="tag-cloud-link tag-link-83 tag-link-position-16" style="font-size: 14.319444444444pt;" aria-label="JavaScript (53 элемента)" data-wpel-link="internal">JavaScript</a>
<a href="https://otus.ru/journal/tag/linux/" class="tag-cloud-link tag-link-141 tag-link-position-17" style="font-size: 11.888888888889pt;" aria-label="Linux (29 элементов)" data-wpel-link="internal">Linux</a>
<a href="https://otus.ru/journal/tag/machine-learning/" class="tag-cloud-link tag-link-167 tag-link-position-18" style="font-size: 8.6805555555556pt;" aria-label="Machine Learning (13 элементов)" data-wpel-link="internal">Machine Learning</a>
<a href="https://otus.ru/journal/tag/otus-book/" class="tag-cloud-link tag-link-261 tag-link-position-19" style="font-size: 9.9444444444444pt;" aria-label="otus book (18 элементов)" data-wpel-link="internal">otus book</a>
<a href="https://otus.ru/journal/tag/php/" class="tag-cloud-link tag-link-45 tag-link-position-20" style="font-size: 10.527777777778pt;" aria-label="PHP (21 элемент)" data-wpel-link="internal">PHP</a>
<a href="https://otus.ru/journal/tag/python/" class="tag-cloud-link tag-link-27 tag-link-position-21" style="font-size: 16.944444444444pt;" aria-label="Python (99 элементов)" data-wpel-link="internal">Python</a>
<a href="https://otus.ru/journal/tag/qa/" class="tag-cloud-link tag-link-155 tag-link-position-22" style="font-size: 11.402777777778pt;" aria-label="qa (26 элементов)" data-wpel-link="internal">qa</a>
<a href="https://otus.ru/journal/tag/sql/" class="tag-cloud-link tag-link-38 tag-link-position-23" style="font-size: 12.861111111111pt;" aria-label="SQL (37 элементов)" data-wpel-link="internal">SQL</a>
<a href="https://otus.ru/journal/tag/team-lead/" class="tag-cloud-link tag-link-364 tag-link-position-24" style="font-size: 9.9444444444444pt;" aria-label="team lead (18 элементов)" data-wpel-link="internal">team lead</a>
<a href="https://otus.ru/journal/tag/unity/" class="tag-cloud-link tag-link-24 tag-link-position-25" style="font-size: 8pt;" aria-label="unity (11 элементов)" data-wpel-link="internal">unity</a>
<a href="https://otus.ru/journal/tag/algoritmy/" class="tag-cloud-link tag-link-30 tag-link-position-26" style="font-size: 9.9444444444444pt;" aria-label="Алгоритмы (18 элементов)" data-wpel-link="internal">Алгоритмы</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh/" class="tag-cloud-link tag-link-40 tag-link-position-27" style="font-size: 10.138888888889pt;" aria-label="Базы данных (19 элементов)" data-wpel-link="internal">Базы данных</a>
<a href="https://otus.ru/journal/tag/matematika/" class="tag-cloud-link tag-link-44 tag-link-position-28" style="font-size: 10.916666666667pt;" aria-label="Математика (23 элемента)" data-wpel-link="internal">Математика</a>
<a href="https://otus.ru/journal/tag/arhitektura-po/" class="tag-cloud-link tag-link-10 tag-link-position-29" style="font-size: 9.4583333333333pt;" aria-label="архитектура ПО (16 элементов)" data-wpel-link="internal">архитектура ПО</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh-2/" class="tag-cloud-link tag-link-251 tag-link-position-30" style="font-size: 10.138888888889pt;" aria-label="базы данных (19 элементов)" data-wpel-link="internal">базы данных</a>
<a href="https://otus.ru/journal/tag/vebinar/" class="tag-cloud-link tag-link-201 tag-link-position-31" style="font-size: 13.930555555556pt;" aria-label="вебинар (48 элементов)" data-wpel-link="internal">вебинар</a>
<a href="https://otus.ru/journal/tag/dajdzhest/" class="tag-cloud-link tag-link-308 tag-link-position-32" style="font-size: 10.722222222222pt;" aria-label="дайджест (22 элемента)" data-wpel-link="internal">дайджест</a>
<a href="https://otus.ru/journal/tag/zapis-vebinara/" class="tag-cloud-link tag-link-226 tag-link-position-33" style="font-size: 14.902777777778pt;" aria-label="запись вебинара (61 элемент)" data-wpel-link="internal">запись вебинара</a>
<a href="https://otus.ru/journal/tag/zapis-uroka/" class="tag-cloud-link tag-link-272 tag-link-position-34" style="font-size: 16.069444444444pt;" aria-label="запись урока (80 элементов)" data-wpel-link="internal">запись урока</a>
<a href="https://otus.ru/journal/tag/informacionnaya-bezopasnost/" class="tag-cloud-link tag-link-232 tag-link-position-35" style="font-size: 10.138888888889pt;" aria-label="информационная безопасность (19 элементов)" data-wpel-link="internal">информационная безопасность</a>
<a href="https://otus.ru/journal/tag/karera-v-it/" class="tag-cloud-link tag-link-292 tag-link-position-36" style="font-size: 9.9444444444444pt;" aria-label="карьера в IT (18 элементов)" data-wpel-link="internal">карьера в IT</a>
<a href="https://otus.ru/journal/tag/podborka/" class="tag-cloud-link tag-link-7 tag-link-position-37" style="font-size: 12.666666666667pt;" aria-label="подборка (35 элементов)" data-wpel-link="internal">подборка</a>
<a href="https://otus.ru/journal/tag/podborka-statej/" class="tag-cloud-link tag-link-219 tag-link-position-38" style="font-size: 15.777777777778pt;" aria-label="подборка статей (75 элементов)" data-wpel-link="internal">подборка статей</a>
<a href="https://otus.ru/journal/tag/programmirovanie/" class="tag-cloud-link tag-link-65 tag-link-position-39" style="font-size: 22pt;" aria-label="программирование (332 элемента)" data-wpel-link="internal">программирование</a>
<a href="https://otus.ru/journal/tag/proekt/" class="tag-cloud-link tag-link-321 tag-link-position-40" style="font-size: 11.888888888889pt;" aria-label="проект (29 элементов)" data-wpel-link="internal">проект</a>
<a href="https://otus.ru/journal/tag/proektnaya-rabota/" class="tag-cloud-link tag-link-310 tag-link-position-41" style="font-size: 11.597222222222pt;" aria-label="проектная работа (27 элементов)" data-wpel-link="internal">проектная работа</a>
<a href="https://otus.ru/journal/tag/seti/" class="tag-cloud-link tag-link-181 tag-link-position-42" style="font-size: 12.958333333333pt;" aria-label="сети (38 элементов)" data-wpel-link="internal">сети</a>
<a href="https://otus.ru/journal/tag/testirovanie/" class="tag-cloud-link tag-link-69 tag-link-position-43" style="font-size: 13.930555555556pt;" aria-label="тестирование (48 элементов)" data-wpel-link="internal">тестирование</a>
<a href="https://otus.ru/journal/tag/upravlenie-komandoj/" class="tag-cloud-link tag-link-63 tag-link-position-44" style="font-size: 11.694444444444pt;" aria-label="управление командой (28 элементов)" data-wpel-link="internal">управление командой</a>
<a href="https://otus.ru/journal/tag/habr-2/" class="tag-cloud-link tag-link-203 tag-link-position-45" style="font-size: 13.930555555556pt;" aria-label="хабр (48 элементов)" data-wpel-link="internal">хабр</a></div>
</li>
</ul>
</div>
</aside>
</div> <!-- .ts-row -->
</div> <!-- .main -->
<footer class="main-footer dark bold">
<section class="lower-footer cf">
<div class="wrap">
<div class="links">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov-1" class="menu"><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
<p class="copyright"> © 2015-2026 OTUS </p>
<div class="to-top">
<a href="#" class="back-to-top"><i class="fa fa-angle-up"></i> Top</a>
</div>
</div>
</section>
</footer>
</div> <!-- .main-wrap -->
<div class="mobile-menu-container off-canvas" id="mobile-menu">
<a href="#" class="close"><i class="fa fa-times"></i></a>
<div class="logo">
</div>
<ul class="mobile-menu"></ul>
</div>
<div class="search-modal-wrap">
<div class="search-modal-box" role="dialog" aria-modal="true">
<form method="get" class="search-form" action="https://otus.ru/journal/">
<input type="search" class="search-field" name="s" placeholder="Search..." value="" required />
<button type="submit" class="search-submit visuallyhidden">Submit</button>
<p class="message">
Type above and press <em>Enter</em> to search. Press <em>Esc</em> to cancel. </p>
</form>
</div>
</div>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/js/url-span.js" id="wbcr-comments-plus-url-span-js"></script>
<script type="text/javascript" id="ez-toc-scroll-scriptjs-js-extra">
/* <![CDATA[ */
var eztoc_smooth_local = {"scroll_offset":"30"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/smooth_scroll.min.js" id="ez-toc-scroll-scriptjs-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/js-cookie/js.cookie.min.js" id="ez-toc-js-cookie-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/sticky-kit/jquery.sticky-kit.min.js" id="ez-toc-jquery-sticky-kit-js"></script>
<script type="text/javascript" id="ez-toc-js-js-extra">
/* <![CDATA[ */
var ezTOC = {"smooth_scroll":"1","visibility_hide_by_default":"","scroll_offset":"30","fallbackIcon":"<span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span>"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/front.min.js" id="ez-toc-js-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/custom-script.js" id="custom-script-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/magnific-popup.js" id="magnific-popup-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.fitvids.js" id="jquery-fitvids-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/imagesloaded.min.js" id="imagesloaded-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/object-fit-images.js" id="object-fit-images-js"></script>
<script type="text/javascript" id="contentberg-theme-js-extra">
/* <![CDATA[ */
var Bunyad = {"custom_ajax_url":"\/journal\/logirovanie-v-python\/"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theme.js" id="contentberg-theme-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theia-sticky-sidebar.js" id="theia-sticky-sidebar-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.slick.js" id="jquery-slick-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jarallax.js" id="jarallax-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/masonry.min.js" id="masonry-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.masonry.min.js" id="jquery-masonry-js"></script>
</body>
</html>
<!-- Cache served by breeze CACHE - Last modified: Mon, 09 Mar 2026 18:52:06 GMT -->