我试图创建一个用于记录的自定义属性(调用者的类名,模块名称等),并且遇到一个奇怪的异常,告诉我在进程中创建的LogRecord实例没有必要的属性。经过一些测试后,我最终得到了这个:
import logging
class MyLogger(logging.getLoggerClass()):
value = None
logging.setLoggerClass(MyLogger)
loggers = [
logging.getLogger(),
logging.getLogger(""),
logging.getLogger("Name")
]
for logger in loggers:
print(isinstance(logger, MyLogger), hasattr(logger, "value"))
这段看似正确的代码产生了:
False False
False False
True True
错误或功能?
答案 0 :(得分:6)
查看源代码,我们可以看到以下内容:
root = RootLogger(WARNING)
def getLogger(name=None):
if name:
return Logger.manager.getLogger(name)
else:
return root
也就是说,导入模块时默认会创建根记录器。因此,每次查找根目录(传递假值,例如空字符串)时,无论是否调用logging.RootLogger
,您都将获得logging.setLoggerClass
个对象。
关于正在使用的记录器类,我们可以看到:
_loggerClass = None
def setLoggerClass(klass):
...
_loggerClass = klass
这意味着全局变量保存将来使用的记录器类。
除此之外,查看logging.Manager
(由logging.getLogger
使用),我们可以看到:
def getLogger(self, name):
...
rv = (self.loggerClass or _loggerClass)(name)
也就是说,如果没有设置self.loggerClass
(除非你明确设置它,否则不会这样),使用全局变量中的类。
因此,这是一个功能。根记录器始终是logging.RootLogger
对象,其他记录器对象是根据当时的配置创建的。
答案 1 :(得分:2)
logging.getLogger()
和logging.getLogger("")
不会返回MyLogger
,因为它们会返回日志记录层次结构的根记录器,如logging documentation中所述:
logging.getLogger([名称])
返回具有指定名称的记录器,或者,如果未指定名称,则返回记录器,该记录器是层次结构的根记录器。
因此,正如您设置了记录器:
>>> logging.getLogger()
<logging.RootLogger object at 0x7d9450>
>>> logging.getLogger("foo")
<test3.MyLogger object at 0x76d9f0>
我认为这与您发布帖子的KeyError无关。您应该发布导致该异常的代码(test.py
)。