帮助我理解python的日志记录模块及其处理程序

Help me understanding python's logging module and its handlers

我真的很怀念关于Python日志模块的一些基本知识。

在下面的代码中,我创建了一个logger对象(log并向它添加了两个处理程序。一个带"信息"级别和"警告"级别。它们都应该打印到stdout。我想打电话给EDOCX1[1]将在我的stdout中生成一份msg的副本,并调用log.warn(msg)的sould result两份打印在我的标准输出上的msg。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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会产生两份打印到stdout的msg副本(可以),另一份打印到stderr(为什么?)。这是上述代码的输出。请注意此输出中最后一行的格式。此行打印到stderr。

1
2
3
4
5
6
7
8
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的调用会导致对stderr的额外输出?

  • 你需要知道两件事:

  • 根记录器初始化为WARNING级别。

    如果到达记录器的任何日志消息的级别低于记录器的级别,则将丢弃该消息。如果未设置记录器的级别,它将从其父记录器获取其"有效级别"。因此,如果根记录器的级别为WARNING,则所有记录器的默认有效级别都为WARNING。如果不进行其他配置,则所有级别低于该级别的日志消息都将被丢弃。

  • 当您调用basicConfig()时,系统会自动在根记录器上设置一个StreamHandler以打印到标准错误流。

    当您的程序打印出它的日志消息时,实际上有三个处理程序:您添加的两个处理程序有自己的级别,系统中的一个处理程序将打印出任何没有被它的记录器拒绝的消息。这就是为什么你要排队的原因

    1
    WARNING:myLogger:this is a warning

    它来自系统记录器。对于INFO级消息,它不会这样做,因为正如前面讨论的那样,根记录器被配置为在默认情况下拒绝那些消息。

    如果您不想要这个输出,不要调用basicConfig()

  • 进一步阅读:http://docs.python.org/howto/logging.html


    日志记录实际上有五个级别:调试、信息、警告、错误和关键。我看到,当您设置日志程序时,您没有显式地设置级别——我相信如果没有设置级别,日志程序可能默认为警告。

    至于为什么它会多次打印以发出警告,我认为这是因为您创建了两个信息和警告处理程序。发生的情况是记录器从warning->info->debug以严重性级联,为每个事件调用处理程序。由于级别设置为"警告",因此将忽略信息处理程序。此外,我相信警告消息通常会写入sys.stderr。

    请尝试以下操作:

    1
    logging.basicConfig(level=logging.INFO)

    另请参见:

    • 日志模块文档
    • 日志记录基本示例