Привет [Dev] мир! Это мой первый пост здесь:-)
Я начал использовать Библиотека регистрации Python Несколько лет назад; Это оконктно мощное lib, и я призываю вас принять его в ваших событиях кода.
Есть бесчисленные веб-страницы с Как И Учебники, объясняющие, как установить систему ведения журнала для вашего файлового сценария Python. Тем не менее, трудно найти места, которые объясняют, как настроить библиотеку журнала Python, которая должна использоваться наложение, и как правильно интегрировать и поделиться Регистрация
Во всех ваших прикладных модулях удобно. Вы все еще можете найти несколько примеров в Интернете и в Официальная документация поваренная книга . Изложенное отсутствие учебных пособий особенно верно, если ваш проект фокусируется как на разработке библиотеки, так и для распределения интерфейса не-разработчика. В этих случаях необходимо настроить журнал так, что он обеспечивает правильный выход, когда пользователи используют ваше приложение в качестве библиотеки, и когда пользователи используют его как автономное программное обеспечение. В последнем случае конечные пользователи ожидают .бревно
и/или .debug
файлы с записью выполнения. С другой стороны, пользователи ваших библиотек не понадобятся такие файлы, и почти наверняка напечатано сообщение sys.stdout
или Sys.Stderr
хватает. Итак, вопрос остается на том, как правильно настроить такие разностные интерфейсы. Вы увидите, что когда-то настроили, настройка выглядит довольно простой и очевидной. Но, честно говоря, потребовалось во мне время разложить Регистрация
Функциональные возможности до минимального набора операций, соответствующих этим требованиям. Для этой конфигурации журнала мы использовали два основных концепция: 1) глобальные переменные и 2) тот факт, что мы можем настроить Регистрация
динамично. Я представлю решение, которое я в настоящее время использую. Пожалуйста, поделитесь своими мыслями, если у вас есть другой или лучший подход.
Настройка регистратора широко
Рассмотрим следующую структуру проекта:
SampleProject/ # <- main repository folder src/ sampleproject/ __init__.py base.py (here is where your main API interface goes) logger.py package1/ __init__.py pkg1_module.py (... etc ...) docs/ (... other files...)
Что мы хотим это настроить наши Логин
объект до любой из модулей проекта инициирует так, чтобы они могли использовать бревно
прямо с самого начала.
Для этого, прямо в образецпроект
root __init__.py.
мы определяем главную Логин
с уровнем ведения журнала, установленным на Отладка
Отказ В конфигурации я представляю здесь, что я использую в наши дни, я определяю Один Логин
Это служит всему приложению/библиотеке/пакету.
# in src/sampleproject/__init__.py import logging log = logging.getLogger(__name__) log.setLevel(logging.DEBUG)
Журнал
Сейчас создается и является глобальной переменной, установленной на главном проекте __init__.py
файл.
Во-вторых, а сразу после в __init__.py.
Я определяю лесозаготовительный обработчик, ответственный за запись, по умолчанию, к Sys.Stderr
Подробнее о StreamHandler Отказ В элементарных словах это обработчик регистратора, который заменяет Печать
функция. Я не объясняю лесозаготовительные обработчики
Здесь, для этого, как сказано вначале, там проходят бесчисленные высококачественные объяснения:
# in src/sampleproject/__init__.py import logging from sampleproject.logger import INFOFORMATTER log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) # defines the stream handler _ch = logging.StreamHandler() # creates the handler _ch.setLevel(logging.INFO) # sets the handler info _ch.setFormatter(logging.Formatter(INFOFORMATTER)) # sets the handler formatting # adds the handler to the global variable: log log.addHandler(_ch)
Вы замечаете, что переменная Infoformatter
? Я импортирую его из logger.py
модуль в образецпроект
Когда я определяю дополнительные переменные или функции помощи или функции, связанные с журналом, например, форматтерами:
# in src/sampleproject/logger.py DEBUGFORMATTER = '%(filename)s:%(name)s:%(funcName)s:%(lineno)d: %(message)s' """Debug file formatter.""" INFOFORMATTER = '%(message)s' """Log file and stream output formatter."""
Как правило, я определяю высокую функцию Delbose Debug, которая идентифицирует файл и строку, где сообщение зарегистрировано и, с другой стороны, я использую простое и удобное для пользователя для Информация
Уровень журнала, который является только сообщением, которую необходимо распечатать программа.
Потому что регистратор в настоящее время определяется на корневом уровне образецпроект
Мы можем импортировать его в любой модуль.
Например:
# in src/sampleproject/package1/pkg1_module1.py from sampleproject import log # and then just use it log.info('message')
Вы можете использовать его одинаково, есть ли он внутри классов или внутри функций.
def myfunct(args): # do something log.info('worked, this is the result {}'.format(result)) return result
Поместите так, это звучит без усилий.
Другие соображения в файле __init__
Однако, если нам нужно импортировать любой из наших функций проекта на главную пространство имен И потому что мы хотим настроить регистрацию перед загрузкой всех других модулей в нашем проекте, мы должны сломать правило Pep8 на Импорт заявления , что говорит:
” Импорт всегда помещается в верхнюю часть файла, сразу после любого модуля комментариев и Docstrings и перед модульными глобалами и константами ».
__init__.py
Макет, наконец, выглядит так:
""" PROJECT MAIN DOCSTRING """ # import ... # Python standard library imports here import logging from sampleproject.logger import ( DEBUGFILE, DEBUGFORMATTER, INFOFILE, INFOFORMATTER, ) # this is exactly what we explained before log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) _ch = logging.StreamHandler() _ch.setLevel(logging.INFO) _ch.setFormatter(logging.Formatter(INFOFORMATTER)) log.addHandler(_ch) # finally you would import from your project what you need # to bring to the root NameSpace, if you need to do so. from sampleproject.package1.module1 import SuperClass, megafunction
Это перерывы, в моем понимании, сопоставляемое правило Pep8, потому что мы импортируем только после настроенного журнала. Если вы используете Checker Lint, например flake8.
и isort.
Возможно, вам может потребоваться добавить оператор игнорирования, в конце строки импорта:
from sampleproject.package1.module1 import SuperClass, megafunction # noqa: F401 isort:skip
Это круговой импорт?
Хотя Superclass
и Мегафункция
Используйте Журнал
Определяется в главном __init___.py
Файл и этот импортирует бывшие два объекта, я не нашел проблем с циркулярным импортом. Вы находите его в противном случае?
Настройка файлов регистрации для пользователей
Как сказано, что если вы разрабатываете проект, который обслуживает как в библиотеке, так и в автономном приложении, вам необходимо создать файлы журнала для выполнения программ. Я обычно создаю как минимум два файла: один info.log
и один Debug.log
Отказ Как и ожидалось, info.log
Регистрирует все сообщения с Информация
Уровень во время Debug.log
Регистрирует все Отладка
Минимальные сообщения уровня. Как мы можем отделить создание файлов журналов из самого объекта журнала, так что первая работа работает только тогда, когда программа работает как автономное программное обеспечение, например, в приложении командной строки? Проще говоря, добавьте обработчики
которые настраивают оба журнала в исполнении Точка входа
Отказ Как?
В logger.py
Модуль, определить init_log_files
Функция, которая называется из Точка входа
Когда образецпроект
выполняется как автономная программа. Если образецпроект
Используется как библиотека, эти файлы не будут созданы.
# in src/sampleproject/logger.py def init_log_files(log, mode='w'): """ Initiate log files. Two files are initiated: 1. :py:attr:`myapp.logger.DEBUGFILE` 2. :py:attr:`myapp.logger.INFOFILE` Adds the two files as log Handlers to :py:attr:`log`. Parameters ---------- mode : str, (``'w'``, ``'a'``) The writing mode to the log files. Defaults to ``'w'``, overwrites previous files. """ # here, I show a very simple configuration # but you can extend it to how many handlers # and tweaks you need. db = logging.FileHandler(DEBUGFILE, mode=mode) db.setLevel(logging.DEBUG) db.setFormatter(logging.Formatter(DEBUGFORMATTER)) info = logging.FileHandler(INFOFILE, mode=mode) info.setLevel(logging.INFO) info.setFormatter(logging.Formatter(INFOFORMATTER)) log.addHandler(db) log.addHandler(info)
Вы также можете продлить эту конфигурацию, чтобы лучше соответствовать вашим потребностям. Наконец, в вашем CLI
Файл, просто позвоните init_log_file
Отказ
# in a CLI file # for example, src/sampleproject/cli_1.py from sampleproject import log from sampleproject.logger import init_log_files # some where down the line def main(*args, **kwargs): init_log_files(log) # continue operating
Любые дополнительные конфигурации, такие как выделенные CLI
Журнальные имена файлов, могут быть добавлены в качестве параметров в init_log_files
Отказ
Резюме
В этом посте я поделился с тобой:
- В настоящее время я настрою Python
Регистрация
Библиотека для обслуживания проекта в целом, с несколькими пакетами и модулями - Чтобы отделить настройку ведения журнала и создание обработчиков файлов, это позволяет журналу служить как для библиотечных целей, так и для автономных приложений
- Активируйте обработчики файлов журнала на
CLI
запрос
Я надеюсь, что вы найдете эту статью интерес, и я с нетерпением жду ваших комментариев.
Примечание: Этот пост также доступен в мой сайт Отказ
Оригинал: “https://dev.to/joaomcteixeira/setting-up-python-logging-for-a-library-app-6ml”