来自 logging
Python 2.7 的指南(我的重点):
命名记录器时使用的一个好的约定是使用模块级记录器,在每个使用日志记录的模块中,命名如下:
logger = logging.getLogger(__name__)
这意味着记录器名称跟踪包/模块层次结构,而且很明显,仅从记录器名称记录事件的位置。
听起来是个好建议。
现在, logging
cookbook 提供了多个模块的示例,它使用硬编码记录器名称而不是 __name__
常量。在示例中的“主模块”中,我们发现
logger = logging.getLogger('spam_application')
在“辅助模块”中我们发现
module_logger = logging.getLogger('spam_application.auxiliary')
我将这个示例逐字复制到具有以下结构的包文件夹中:
cookbook-example
|- __init__.py
|- main_module.py
|- auxiliary_module.py
这运行没有问题,从主模块和辅助模块产生预期的日志输出,但事情是这样的:
如果我现在按照 logging
howto 的建议,用 __name__
常量替换硬编码的记录器名称,食谱示例将崩溃:我只从主模块获取日志消息,但辅助模块什么也没有。
我一定错过了一些明显的东西。知道我做错了什么吗?
笔记:
有很多非常相似的问题和相关答案,例如: 1 、 2 、 3 、 4 、 5 、 6 等等。但是,这些似乎都没有解决这个具体问题。
- 编辑 -
这是一个基于食谱示例的最小示例,其中显式名称字符串替换为 __name__
。
主模块.py
import logging
import auxiliary_module
# create and configure main logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler with a higher log level
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
# create formatter and add it to the handler
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# add the handler to the logger
logger.addHandler(handler)
logger.info('message from main module')
auxiliary_module.some_function()
辅助模块.py
import logging
# create logger
module_logger = logging.getLogger(__name__)
def some_function():
module_logger.info('message from auxiliary module')
原文由 djvg 发布,翻译遵循 CC BY-SA 4.0 许可协议
正如@shmee 在 这个答案 中指出的那样,记录器层次结构必须使用点符号在记录器名称中明确定义。 That is, if the logger name in
main_module.py
is eg'a'
, then the logger name inauxiliary_module.py
must be'a.b'
(not just'b'
),以使其继承记录器的配置'a'
。getLogger()
文档 中也提到了这一点。然而,这应该在使用
__name__
时自动处理,如logging
操作方法 中所述:问题是,要使其正常工作,您需要以正确的方式使用
__name__
,而我没有这样做。我的示例中的问题在于
cookbook-example
包文件夹中的文件组织:主模块和辅助模块都处于同一级别(即在同一文件夹中)。因此,如此 处 所述,主模块的
__name__
将是'__main__'
(因为它是顶级脚本),而__name__
-d2辅助模块将是'auxiliary_module'
(即文件名),而不是'__main__.auxiliary_module'
。因此,辅助模块中的记录器将是根记录器的子项,而不是
'__main__'
记录器的子项,因此它将继承根记录器配置(仍具有默认日志记录级别WARNING
) 而不是主模块中指定的配置。所以,为了让这个例子工作,我们有几个选择:
将 主 模块中的
getLogger(__name__)
替换为getLogger()
。这会将配置应用到根记录器,因此也应用到辅助模块记录器,正如@shmee 所建议的那样。将 辅助 模块中的
getLogger(__name__)
替换为getLogger('__main__.' + __name__)
。结果将等同于原始食谱示例(除了主记录器现在称为'__main__'
而不是'spam_application'
)。