Отделяйте сбор логов от обработки

Если ваша программа состоит из одного файла, то у вас нет проблем с логированием. Можете использовать модуль logging как хотите, в любом случае у вас всё получится. С большими программами дела обстоят сложнее и именно здесь проявляется настоящая сила модуля logging. В этой статье вы узнаете как ей воспользоваться. Перед чтением ознакомьтесь с вводной статьей о логировании в Python.

Рассмотрим пример. В репозитории лежат три скрипта — бот для VK, бот для Telegram и служебный скрипт для загрузки данных в БД. Для доступа к данным каждая программа использует вспомогательный файл db.py, где используется logging. Сначала вы пишите в db.py нечто подобное:

import logging

...
logging.debug('Send data to db')
...
logging.critical('Lost connection to DB')

Всё выглядит просто и незатейливо. Но вот вы запускаете ботов VK и Telegram на сервере и теперь хотите отправлять логи в чатик Telegram. Не большая проблема, можно сделать так:

import logging

...
logger = logging.getLogger('Logger')
logger.setLevel(logging.WARNING)
logger.addHandler(TelegramLogsHandler(bot))

...
logging.debug('Send data to db')
...
logging.critical('Lost connection to DB')

Теперь логи сыпятся в чатик, и вы моментально узнаете о проблемах. Это победа! Или не совсем? А как же скрипт для загрузки данных в БД? Это консольная программа, но её логи почему-то сыпятся в чат вместо терминала. Странное поведение...

Теперь поставьте себя на место разработчика популярной библиотеки, например Requests. Вам очень пригодилось бы логирование, ведь с ним так просто отлаживать код. Проходит время, в консоли собирается море отладочной информации, и пользователи библиотеки начинают бунтовать. Может, кому-то логи и нужны, но вот большинству пользователей они совсем ни к месту. Что же делать?

И здесь на сцену выходят архитектурные особенности библиотеки logging. Общий принцип такой:

Сначала собери сообщения в кучу, а уже потом думай что с ними делать

Для этого по файлам и модулям разбрасываем вызовы getLogger(...), собираем через них отладочные сообщения и снабжаем каждое подписью "через какой логер оно было собрано". Всю настройку логов: фильтрацию, форматирование и что куда выводить — собираем в основной программе внутри ifmain или def main. Следуем нескольким правилам:

  • Библиотеки отправляют сообщения в именованные логеры
  • Библиотеки не вмешиваются в настройку логирования
  • У каждой программы свои настройки логирования

Пример кода, файл db.py:

import logging

logger = logging.getLogger('db')

...
logging.debug('Send data to db')
...
logging.critical('Lost connection to DB')

Запускаемый файл c программой init_db.py:

import logging

...

if __name__ == '__main__':
    # по очереди настраиваем логгеры всех подключенных модулей
    db_logger = logging.getLogger('db')
    db_logger.setLevel(logging.WARNING)

    requests_logger = logging.getLogger('requests')
    requests_logger.setLevel(logging.ERROR)
    ...

Похожий код будет в файле с ботом VK и в файле с ботом Telegram. Чтобы избежать большого количества повторяющегося кода, можно воспользоваться методом dictConfig.

Обратите внимание, что в обоих файлах происходит вызов функции logging.getLogger('db'). В одном случае функция создает новый объект Logger, а в другом возвращает ранее созданный. Несмотря на то, что в каждом файле есть свой вызов get_logger, все они возвращают один и тот же объект.

Функция get_logger возвращает один и тот же объект

Эта особенность get_logger позволяет отделить сбор логов от настройки логирования. Если сначала настроить логер в файле script.py, а затем воспользоваться им в другом файле db.py, то настройка вступит в силу в обоих местах сразу:

from logging import get_logger

import db

if __name__ == '__main__':
    get_logger('db').addHandler(TelegramHandler)
    db.init()
from logging import get_logger

def init():
    get_logger('db').debug('Модуль db подключен')
    ...

Сообщение с текстом 'Модуль db подключен' из второго файла будет отправлено в Telegram благодаря TelegramHandler из первого файла.

Изменение настроек логера влияют на все файлы разом

Что читать дальше?

Прочитайте статьи с других сайтов: