##~~ ... Пропускаем все остальное ...
def setup_logging(configfile, stdout=False):
log = logging.getLogger('diamond')
if stdout:
log.setLevel(logging.DEBUG)
streamHandler = logging.StreamHandler(sys.stdout)
streamHandler.setFormatter(DebugFormatter())
streamHandler.setLevel(logging.DEBUG)
log.addHandler(streamHandler)
else:
##~~ ... Пропускаем это ...
В противном случае он анализирует файл конфигурации с помощью функции logging.config.file.fileConfig() из стандартной библиотеки Python. Перед вами вызов функции — он выделен отступами, поскольку находится внутри предшествующего оператора if/else и блока try/except: logging.config.fileConfig(configfile,
disable_existing_loggers=False)
Конфигурация журналирования игнорирует ключевые слова в конфигурационном файле, которые не связаны с журналированием. Так Diamond может использовать один и тот же конфигурационный файл как для своей конфигурации, так и для конфигурации журналирования. В примере конфигурационного файла, который располагается по адресу Diamond/conf/diamond.conf.example, среди прочих обработчиков определяется и обработчик журналирования: ### Настройки обработчиков
[handlers]
# обработчик(и) для журналирования
keys = rotated_file
Далее в файле конфигурации под заголовком «Настройки для журналирования» определяются примеры средств ведения журнала. Для получения более подробной информации смотрите документацию к конфигурационным файлам для журналирования (http://bit.ly/configfile-format).
Примеры из структуры Diamond
Diamond — это больше чем исполняемое приложение. Он также является библиотекой, которая предоставляет пользователям возможность создавать и применять собственные сборщики.
Мы продемонстрируем те элементы структуры пакета, которые нам нравятся, а затем изучим, как именно Diamond позволяет приложению импортировать и использовать определенные извне сборщики.
Разбиваем функциональность между пространствами имен (поскольку пространства имен — это отличная штука!)
На схеме рис. 5.2 показан модуль сервера, взаимодействующий с тремя другими модулями проекта: diamond.handler, diamond.collector и diamond.utils.
В подпакете utils можно было бы разместить все классы и функции в одном большом модуле util.py, однако можно подключить пространства имен для того, чтобы разбить код на отдельные файлы, — и команда разработчиков ею воспользовалась. Отличный выбор!
Все реализации обработчиков содержатся в каталоге diamond/handler (это логично), но структура для сборщиков отличается. Для них не предусмотрен каталог — только модуль diamond/collector.py, в котором определяются базовые классы Collector и ProcessCollector. Все реализации подклассов класса Collector определены в каталоге Diamond/src/collectors/, в виртуальной среде они будут установлены по адресу venv/share/diamond/collectors, если вы устанавливали Diamond с помощью PyPI (рекомендованный способ), а не с помощью GitHub (как это сделали мы). Это помогает пользователю создать новые реализации сборщиков: размещение всех сборщиков в одном месте упрощает их поиск для приложения, а также создание аналогичных сборщиков. Наконец, каждая реализация сборщика в Diamond/src/collectors находится в своем каталоге (а не в отдельном файле), что позволяет разделить тесты для каждой реализации класса Collector. Также отлично придумано!
Расширяемые пользователем классы (сложное лучше, чем запутанное)
Добавить новую реализацию класса Collector нетрудно: нужно создать подкласс абстрактного базового класса diamond.collector.Collector58, реализовать метод Collector.collect() и поместить реализацию в отдельный каталог по адресу venv/src/collectors/.
Сама по себе реализация сложна, но пользователь этого не знает. В данном разделе рассматриваются простая часть API сборщиков, которая видна пользователю, и сложный код, благодаря которому появился подобный интерфейс.
Сложное против запутанного. Мы можем сравнить работу со сложным кодом со швейцарскими часами — они просто работают, но внутри находится множество маленьких деталей, взаимодействующих с высокой точностью, чтобы упростить работу с API. Использование запутанного кода похоже на управление самолетом — вы наверняка должны знать, что делать, чтобы не разбиться и не сгореть59. Мы не хотим жить в мире без самолетов, но при этом желаем пользоваться часами, не вникая в тонкости их работы. Везде, где это возможно, создавайте менее сложные пользовательские интерфейсы.