我在代码中使用
alembic
在应用程序启动时应用数据库迁移。我还使用 Python 的内置 logging
lib 来登录终端。应用迁移后(或运行任何打印到 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.")
我可以做些什么来确保我的记录器正在记录?我想继续使用内置的日志记录功能,但我也愿意为此使用一些库。
答案将在您的
alembic.ini
文件中找到。
您正在运行一个旨在作为脚本而不是 API 调用的命令,因此 alembic 使用 logging.fileConfig
配置自己的日志记录,默认情况下使用
disable_existing_loggers=True
。该选项将禁用任何现有的非根记录器,除非它们或其祖先在日志记录配置文件中明确命名。
因此,阻力最小的方法就是在那里设置日志配置。
alembic.ini
中将有一个包含日志配置的部分 - 查找 [loggers]
部分标题。您需要修改内容,以便您自己的记录器保持可见 - 添加包含所需处理程序、格式化程序等的 [logger_app]
部分。
为了保持一致性,您可能也想从自己的脚本中切换到使用
fileConfig
,而不是 logging.basicConfig
。
另一种选择是在子进程中运行 alembic 脚本,这样它们的日志配置就不需要你关心了。子进程的 stdout/stderr 始终可以被捕获并作为主进程中的日志事件重新发送。
虽然wim的答案引导我找到了解决方案,但我最终会为我实现的解决方案添加一个答案。采用这种方法,我不必在
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)
更改第四行以包含关键字参数
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)
logging docs提到此参数默认设置为
True
以实现向后兼容性:
警告
函数采用默认参数fileConfig()
,出于向后兼容性的原因,默认为disable_existing_loggers
。这可能是也可能不是您想要的,因为它会导致True
调用之前存在的任何非根记录器被禁用,除非它们(或祖先)在配置中明确命名。请参阅参考文档了解更多信息,如果您愿意,请为此参数指定fileConfig()
。False
它没有提到这种兼容性到底是什么,并且我不确定我的应用程序是否使用 Python 3.12,是否需要它。