使用多个模块记录时的记录器层次结构和根记录器
Logger hierarchy and the root logger when logging with multiple modules
我有这个设置:
main.py
/module
/module/__init__.py (empty)
/module.py
这里是我的两个文件的代码,分别是 main.py
和 module.py
:
main.py
import logging
from module import module
logger = logging.getLogger(__name__)
def test():
logger.warning('in main.py/test')
def main():
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(name)s/%(module)s [%(levelname)s]: %(message)s', '%Y-%m-%d %H:%M:%S')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.warning('in main.py/main')
module.something()
if __name__ == "__main__":
main()
module.py
import logging
logger = logging.getLogger(__name__)
def something():
logger.warning('in module.py/something')
所以,我注意到输出如下(注意模块记录器没有格式化):
2019-10-01 09:03:40 __main__/main [WARNING]: in main.py/main
in module.py/something
似乎只有在我在 main.py
中进行编辑后才能将 logger = logging.getLogger( __ name __ )
更改为 logger = logging.getLogger()
或 添加 logger = logging.getLogger()
在 def main():
之后它像这样记录(这就是我想要的):
2019-10-01 09:04:13 root/main [WARNING]: in main.py/main
2019-10-01 09:04:13 module.module/module [WARNING]: in module.py/something
这是为什么?我认为因为 main.py
正在导入 module.py
,它自然在层次结构上更高,所以 module.py
将继承 main.py
中定义的记录器设置。是否需要在 main 中显式设置根记录器(使用 logger = logging.getLogger()
)才能使继承工作?是我没有正确配置我的文件夹结构以使 module.py
的记录器继承 main.py
的记录器设置,还是文件夹结构不相关?
我问的原因是因为我认为应该始终使用 logger = logging.getLogger( __ name __ )
(甚至在 main.py
中),然后根据导入结构(或文件夹结构?)来确定层次结构记录器将相应地继承。我做出这种假设的原因是,如果我将 main.py
导入另一个程序会怎样?我想我的意思是,我想让日志记录尽可能通用,这样我就可以将一个模块导入另一个模块,并且它始终继承父记录器的设置。有没有办法显示所有模块的底层层次结构以达到 debugging/learning 目的?
日志层次结构与程序中的文件结构无关。层次结构仅由记录器的名称确定。当您配置记录器时,除非另有明确说明,否则名称前缀中包含其名称的所有记录器都是其子项并继承其配置。
在您的示例中,日志记录设置更多地与执行顺序和您选择的名称有关。当您的程序 运行s 时,它会执行以下操作:
- 运行s
logging.py
来自标准库,因为 import logging
- 运行s
module.py
履行from module import module
- 将
main
中的 logger
属性设置为名为 __main__
的 Logger
。
- 创建一个
test
函数
- 创建一个
main
函数
- 运行主要功能
这一系列事件的一些后果:
module.logger
在 main.logger
之前创建。这不会影响您看到的行为,但在这种情况下值得注意。
如果您将 main
作为脚本调用,main.logger
将被命名为 __main__
。如果它被称为 main
,您看到的行为不会改变,例如来自 python -m main
.
module
显然与 main
不在同一层级。两者都是根记录器沿不同分支的后代。
最后一项确实是您问题的答案。如果您希望程序中的所有记录器共享相同的默认记录方法,则应配置根记录器,或确保它们具有相同的名称前缀,然后将其配置为根记录器。
您可以让所有记录器继承自 main
。在 module/module.py
,你会做
logger = logging.getLogger('__main__.' + __name__)
这里的问题是名称 __main__
是硬编码的。您无法保证它将是 __main__
与 main
。您可以在 module
中尝试 import main
,这样您就可以执行 main.__name__ + '.' + __name__
,但这不会按预期工作。如果 main
是 运行 作为 __main__
,导入它实际上会创建第二个具有完全独立的日志层次结构的模块对象。
这就是根记录器没有名字的原因。它准确地提供了您想要的可维护性和一致性。您不必费尽心思找出根名称。
话虽如此,您仍然应该 main.py
记录到 __main__
或 main
记录器。根记录器只能在导入守卫中设置。那样的话,如果 main
作为常规模块导入,它会遵守驱动程序的日志设置 运行ning。
TL;DR
通常在您的程序驱动程序中设置匿名根记录器。不要尝试从 __main__
或驱动模块名称继承记录器。
我有这个设置:
main.py
/module
/module/__init__.py (empty)
/module.py
这里是我的两个文件的代码,分别是 main.py
和 module.py
:
main.py
import logging
from module import module
logger = logging.getLogger(__name__)
def test():
logger.warning('in main.py/test')
def main():
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(name)s/%(module)s [%(levelname)s]: %(message)s', '%Y-%m-%d %H:%M:%S')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.warning('in main.py/main')
module.something()
if __name__ == "__main__":
main()
module.py
import logging
logger = logging.getLogger(__name__)
def something():
logger.warning('in module.py/something')
所以,我注意到输出如下(注意模块记录器没有格式化):
2019-10-01 09:03:40 __main__/main [WARNING]: in main.py/main
in module.py/something
似乎只有在我在 main.py
中进行编辑后才能将 logger = logging.getLogger( __ name __ )
更改为 logger = logging.getLogger()
或 添加 logger = logging.getLogger()
在 def main():
之后它像这样记录(这就是我想要的):
2019-10-01 09:04:13 root/main [WARNING]: in main.py/main
2019-10-01 09:04:13 module.module/module [WARNING]: in module.py/something
这是为什么?我认为因为 main.py
正在导入 module.py
,它自然在层次结构上更高,所以 module.py
将继承 main.py
中定义的记录器设置。是否需要在 main 中显式设置根记录器(使用 logger = logging.getLogger()
)才能使继承工作?是我没有正确配置我的文件夹结构以使 module.py
的记录器继承 main.py
的记录器设置,还是文件夹结构不相关?
我问的原因是因为我认为应该始终使用 logger = logging.getLogger( __ name __ )
(甚至在 main.py
中),然后根据导入结构(或文件夹结构?)来确定层次结构记录器将相应地继承。我做出这种假设的原因是,如果我将 main.py
导入另一个程序会怎样?我想我的意思是,我想让日志记录尽可能通用,这样我就可以将一个模块导入另一个模块,并且它始终继承父记录器的设置。有没有办法显示所有模块的底层层次结构以达到 debugging/learning 目的?
日志层次结构与程序中的文件结构无关。层次结构仅由记录器的名称确定。当您配置记录器时,除非另有明确说明,否则名称前缀中包含其名称的所有记录器都是其子项并继承其配置。
在您的示例中,日志记录设置更多地与执行顺序和您选择的名称有关。当您的程序 运行s 时,它会执行以下操作:
- 运行s
logging.py
来自标准库,因为import logging
- 运行s
module.py
履行from module import module
- 将
main
中的logger
属性设置为名为__main__
的Logger
。 - 创建一个
test
函数 - 创建一个
main
函数 - 运行主要功能
这一系列事件的一些后果:
module.logger
在main.logger
之前创建。这不会影响您看到的行为,但在这种情况下值得注意。
如果您将 main.logger
将被命名为__main__
。如果它被称为main
,您看到的行为不会改变,例如来自python -m main
.module
显然与main
不在同一层级。两者都是根记录器沿不同分支的后代。
main
作为脚本调用,最后一项确实是您问题的答案。如果您希望程序中的所有记录器共享相同的默认记录方法,则应配置根记录器,或确保它们具有相同的名称前缀,然后将其配置为根记录器。
您可以让所有记录器继承自 main
。在 module/module.py
,你会做
logger = logging.getLogger('__main__.' + __name__)
这里的问题是名称 __main__
是硬编码的。您无法保证它将是 __main__
与 main
。您可以在 module
中尝试 import main
,这样您就可以执行 main.__name__ + '.' + __name__
,但这不会按预期工作。如果 main
是 运行 作为 __main__
,导入它实际上会创建第二个具有完全独立的日志层次结构的模块对象。
这就是根记录器没有名字的原因。它准确地提供了您想要的可维护性和一致性。您不必费尽心思找出根名称。
话虽如此,您仍然应该 main.py
记录到 __main__
或 main
记录器。根记录器只能在导入守卫中设置。那样的话,如果 main
作为常规模块导入,它会遵守驱动程序的日志设置 运行ning。
TL;DR
通常在您的程序驱动程序中设置匿名根记录器。不要尝试从 __main__
或驱动模块名称继承记录器。