Как я могу помешать регистратору перегонного куба деактивировать мои собственные регистраторы после использования команды перегонного куба в коде?

Я использую alembic в своем коде, чтобы применять миграцию базы данных при запуске приложения. Я также использую встроенную библиотеку logging Python для входа в терминал. Однако после применения миграций (или запуска любой команды alembic, которая, кажется, печатает stdout) мои регистраторы перестают работать.

Код:

import logging

import alembic.command
from alembic.config import Config as AlembicConfig

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("app")

logger.debug("Applying alembic migrations.")

alembic_config = AlembicConfig("alembic.ini")
alembic_config.attributes["sqlalchemy.url"] = connection_string
alembic.command.upgrade(alembic_config, "head", tag = "from_app")

logger.debug("Terminating app.")

Ожидаемый результат:

DEBUG:app:Applying alembic migrations.
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
DEBUG:app:Terminating app.

Фактический результат:

DEBUG:app:Applying alembic migrations.
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.

Последняя строка отсутствует.

Я попытался снова установить уровень журнала после применения миграции (я думал, что, возможно, это изменило уровень журнала корневого регистратора):

...
alembic.command.upgrade(alembic_config, "head", tag = "from_app")

logger.setLevel(logging.DEBUG)
logger.debug("Terminating app.")

Фактически даже logger.critical("blah") больше ничего не логирует.

Я также попробовал еще раз применить базовую конфигурацию и снова получить регистратор:

...
alembic.command.upgrade(alembic_config, "head", tag = "from_app")

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("app")
logger.debug("Terminating app.")

Но безрезультатно. Даже корневой регистратор больше не регистрирует:

...
alembic.command.upgrade(alembic_config, "head", tag = "from_app")

logging.basicConfig(level=logging.DEBUG)
logging.debug("Terminating app.")

Могу ли я что-нибудь сделать, чтобы убедиться, что мои регистраторы ведут журнал? Я хотел бы продолжать использовать встроенную функцию ведения журнала, но я также готов использовать для этого некоторую библиотеку.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ответ найдётся в вашем alembic.ini файле.

Вы запускаете команду, которая должна была быть сценарием, а не вызовом API, поэтому перегонный куб настраивает собственное ведение журнала с помощью logging.fileConfig, который по умолчанию использует disable_existing_loggers=True. Эта опция отключит все существующие средства ведения журнала без полномочий root, если только они или их предки не указаны явно в файле конфигурации ведения журнала.

Таким образом, путь наименьшего сопротивления будет заключаться в настройке конфигурации ведения журнала там же. В alembic.ini будет раздел с настройкой ведения журнала — найдите заголовок [loggers] раздела. Вы захотите изменить содержимое так, чтобы ваши собственные регистраторы оставались видимыми — добавьте раздел [logger_app] с нужными обработчиками, форматтерами и т. д.

Ради последовательности вы также можете переключиться на использование fileConfig из вашего собственного скрипта вместо logging.basicConfig.

Альтернативным вариантом может быть запуск сценариев перегонного куба в подпроцессе, чтобы их конфигурация журналирования вас не касалась. Stdout/stderr подпроцесса всегда можно захватить и повторно отправить в виде событий журнала из вашего основного процесса.

омг, огромное спасибо за этот указатель! Я попытался добавить свою конфигурацию в файл alembic.ini. Но я хочу установить уровень ведения журнала во время выполнения, поэтому я также попробовал отредактировать env.py алембика, где он создает свои регистраторы, и добавил disable_existing_loggers=False к вызову logging.config.fileConfig. Теперь все работает как ожидалось!

Tim 22.07.2024 21:12

Ах да, просто редактирование автоматически сгенерированного env.py тоже звучит разумно.

wim 22.07.2024 21:25

Хотя ответ Вима привел меня к решению, я добавлю ответ для решения, которое я реализовал в конце. При таком подходе мне не пришлось дублировать настройки логгера в alembic.ini, а необходимые изменения в коде были ограничены одной строкой.

Отредактируйте env.py, созданный alembic

В env.py от alembic есть раздел, близкий к импорту, где настраиваются их логгеры:

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
    fileConfig(config.config_file_name)

Изменение 4-й строки для включения параметра ключевого слова disable_existing_loggers=False позволит вашим собственным средствам ведения журнала продолжать работать и вести журнал:

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
    fileConfig(config.config_file_name, disable_existing_loggers=False)

В документации по журналированию упоминается, что для этого параметра по умолчанию установлено значение True для обратной совместимости:

Предупреждение

Функция fileConfig() принимает параметр по умолчанию disable_existing_loggers, который по умолчанию равен True из соображений обратной совместимости. Это может быть, а может и не быть тем, что вы хотите, так как это приведет к отключению любых средств ведения журнала без полномочий root, существовавших до вызова fileConfig(), если они (или предок) не указаны явно в конфигурации. Для получения дополнительной информации обратитесь к справочной документации и при желании укажите False для этого параметра.

Там не упоминается, что именно представляет собой эта совместимость, и, используя Python 3.12 для своего приложения, я не уверен, нужна ли она мне вообще.

Другие вопросы по теме