2011-09-22 41 views
6

我真的错过了关于python日志记录模块的基本知识。帮我理解python的日志记录模块及其处理程序

在下面的代码中,我创建了一个记录器对象(log)并添加了两个处理程序。一个与 'INFO'级别和一个'警告'级别。他们都应该打印到标准输出。我希望调用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打印到stdout(这是OK),但也会将一个副本打印到stderr(为什么?)。这是上述代码的输出。请注意此输出中最后一行的格式。这一行打印到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 

所以我的问题是:

  1. 为什么,我呼吁info没有输出结果尽管h1的级别设置为INFO的事实?
  2. 为什么我打电话给warn会导致额外的输出到stderr?
+0

我不能肯定,但你可能会运行到麻烦,因为Python的'logging'有警告和信息一个内置的水平。 – brc

+0

@brc这会回答我的第一个问题,但不是第二个问题 –

回答

7

有两件事情你需要知道:

  1. 根记录器的初始化级别为WARNING

    如果达到记录器的任何日志消息的级别低于记录器的级别,则会被丢弃。如果没有设置记录器的级别,它将从其父记录器获取“有效级别”。因此,如果根记录器的级别为WARNING,则所有记录器的默认有效级别为WARNING。如果您没有配置它,则所有低于该级别的日志消息将被丢弃。

  2. 当您拨打basicConfig()时,系统会在根记录器上自动设置打印到标准错误流的StreamHandler

    当你的程序打印出它的日志消息,实际上有处理程序:您已添加了两下,它们有自己的水平,和一个从系统将打印出不被拒绝的任何消息它的记录器。这就是为什么你得到该行

    WARNING:myLogger:this is a warning 
    

    它来自系统记录器。它不会为INFO级别的消息执行此操作,因为如前所述,默认情况下会将根日志记录器配置为拒绝这些消息。

    如果您不想要这个输出,请不要拨打basicConfig()

延伸阅读:http://docs.python.org/howto/logging.html

3

实际上有五个级别的日志记录:debug,info,warning,error和critical。我发现当你设置你的记录器时,你没有明确设定你的级别 - 我相信如果没有设置级别,记录器可能会默认为警告。至于为什么它会多次打印出警告,我相信这是由于您为信息&警告创建了两个处理程序。会发生什么情况是记录器级联严重性从警告 - >信息 - >调试,调用每个处理程序。由于您的级别设置为警告,所以信息处理程序将被忽略。另外,我相信警告消息通常写入sys.stderr。

尝试以下操作:

logging.basicConfig(level=logging.INFO) 

参见:

+0

哈,像我一样抓住了我的错误 - 不知何故,这使我成为双后? –

+0

更具体地说,在他的示例中,@bgbg设置处理程序的级别,但从不设置记录程序的级别。因此记录器的级别默认为'logging.WARNING'。添加'log.level = logging.INFO'会解决这个问题。我同意@David Z认为最好完全除去'basicConfig()'调用,而不要依赖根记录器。 –

相关问题