帮助我理解Python的日志模块及其处理器
我对Python的日志模块有些基本的困惑。
在下面的代码中,我创建了一个日志记录器对象(log
),并给它添加了两个处理器。一个是'INFO'级别,另一个是'WARNING'级别。它们都应该打印到标准输出(stdout)。我本来期待调用log.info(msg)
时,会在我的标准输出中看到一份msg
,而调用log.warn(msg)
时,会在标准输出中看到两份msg
。以下是代码:
import logging
import sys
logging.basicConfig()
log = logging.getLogger('myLogger')
log.handlers = []
h1 = logging.StreamHandler(sys.stdout)
h1.level = logging.INFO
h1.formatter = logging.Formatter('H1 H1 %(message)s ')
h2 = logging.StreamHandler(sys.stdout)
h2.level = logging.WARNING
h2.formatter = logging.Formatter('H2 H2 %(message)s')
log.addHandler(h1)
log.addHandler(h2)
print 'log.level == %s'%logging.getLevelName(log.level)
print 'log.info'
log.info('this is some info')
print 'done'
print 'log.warn'
log.warn('this is a warning')
print 'done'
但是输出结果让我感到很奇怪。调用.info
时没有任何可见的效果。不过,调用warn
时却在标准输出中打印了两份msg
(这没问题),但同时还在标准错误输出(stderr)中打印了一份(这为什么呢?)。这是上面代码的输出结果。注意输出最后一行的格式。这一行是打印到标准错误输出的。
log.level == NOTSET
log.info
done
log.warn
H1 H1 this is a warning
H2 H2 this is a warning
done
WARNING:myLogger:this is a warning
所以我有两个问题:
- 为什么我调用
info
时没有任何输出,尽管h1
的级别设置为INFO? - 为什么我调用
warn
时会额外输出到标准错误输出?
2 个回答
你需要知道两件事:
根日志记录器的初始级别是
WARNING
。任何到达日志记录器的日志信息,如果它的级别低于日志记录器的级别,就会被丢弃。如果一个日志记录器没有设置级别,它会从它的父日志记录器那里继承一个“有效级别”。所以,如果根日志记录器的级别是
WARNING
,那么所有的日志记录器默认的有效级别也是WARNING
。如果你没有做其他配置,所有级别低于这个的日志信息都会被丢弃。当你调用
basicConfig()
时,系统会自动在根日志记录器上设置一个StreamHandler
,它会将信息打印到标准错误流。当你的程序打印日志信息时,实际上有 三个处理器:你添加的两个处理器,它们有自己的级别,还有一个来自系统的处理器,它会打印出任何没有被日志记录器拒绝的信息。这就是你看到的那一行
WARNING:myLogger:this is a warning
它来自系统日志记录器。对于
INFO
级别的信息,它不会这样做,因为正如之前讨论的,根日志记录器默认配置是拒绝这些信息的。如果你不想看到这个输出,就不要调用
basicConfig()
。