我有以下代码:
import logging
class A(object):
def __init__(self):
self._l = self._get_logger()
def _get_logger(self):
loglevel = logging.INFO
l = logging.getLogger(__name__)
l.setLevel(logging.INFO)
h = logging.StreamHandler()
f = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
h.setFormatter(f)
l.addHandler(h)
l.setLevel(loglevel)
return l
def p(self, msg):
self._l.info(msg)
for msg in ["hey", "there"]:
a = A()
a.p(msg)
Run Code Online (Sandbox Code Playgroud)
我得到的输出是:
2013-07-19 17:42:02,657 INFO hey
2013-07-19 17:42:02,657 INFO there
2013-07-19 17:42:02,657 INFO there
Run Code Online (Sandbox Code Playgroud)
为什么"那里"被打印两次?同样,如果我在循环中添加A类的另一个对象并打印一条消息,它将被打印三次.
文档说如果记录器的名称匹配,logging.getLogger()将始终返回相同的记录器实例.在这种情况下,名称确实匹配.它不应该返回相同的记录器实例吗?如果它实际上是这样做的,为什么消息会被多次打印?
fal*_*tru 18
logger创建一次,但创建了多个处理程序.
创建A一次.
a = A()
for msg in ["hey", "there"]:
a.p(msg)
Run Code Online (Sandbox Code Playgroud)
或者改变_get_logger如下:
def _get_logger(self):
loglevel = logging.INFO
l = logging.getLogger(__name__)
if not getattr(l, 'handler_set', None):
l.setLevel(loglevel)
h = logging.StreamHandler()
f = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
h.setFormatter(f)
l.addHandler(h)
l.setLevel(loglevel)
l.handler_set = True
return l
Run Code Online (Sandbox Code Playgroud)
UPDATE
从Python 3.2开始,您可以使用它logging.Logger.hasHandlers来查看此记录器是否配置了任何处理程序.(感谢@toom)
def _get_logger(self):
loglevel = logging.INFO
l = logging.getLogger(__name__)
if not l.hasHandlers():
...
return l
Run Code Online (Sandbox Code Playgroud)
在我的例子中,root loggers处理程序也被调用,我所做的就是将propagatelogger实例的属性设置为False.
import logging
logger = logging.getLogger("MyLogger")
# stop propagting to root logger
logger.propagate = False
# other log configuration stuff
# ....
Run Code Online (Sandbox Code Playgroud)
从 python 3.2 及更高版本开始:
考虑使用hasHandlers()来检查记录器是否有处理程序。
https://docs.python.org/3/library/logging.html#logging.Logger.hasHandlers