Python 日志的复杂用法?

1 投票
2 回答
1288 浏览
提问于 2025-04-15 15:08

我正在尝试使用Python的日志模块来做一些复杂的事情。这里不讲我这样设计的原因,因为那样会让内容变得很长。不过,我需要一个根日志记录器,它会不停地往一个常规的日志文件里写我们的代码和库的日志,同时还有一组其他的日志记录器,它们会写入不同的日志文件。

整体的设置应该是这样的。为了简化代码,我在这个例子中会把所有输出都放到标准输出(stdout)上。


import logging, sys
root = logging.getLogger('')
top = logging.getLogger('top')
bottom = logging.getLogger('top.bottom')

class KillFilter(object):
    def filter(self, msg):
        return 0

root_handler = logging.StreamHandler(sys.stdout)
top_handler = logging.StreamHandler(sys.stdout)
bottom_handler = logging.StreamHandler(sys.stdout)
root_handler.setFormatter(logging.Formatter('ROOT'))
top_handler.setFormatter(logging.Formatter('TOP HANDLER'))
bottom_handler.setFormatter(logging.Formatter("BOTTOM HANDLER"))

msg_killer = KillFilter()

root.addHandler(root_handler)
top.addHandler(top_handler)
bottom.addHandler(bottom_handler)

top.addFilter(msg_killer)

root.error('hi')
top.error('hi')
bottom.error('hi')

这段代码的输出是


ROOT
BOTTOM HANDLER
ROOT

第二个根处理器的调用不应该有输出,因为根据日志文档,msg_killer会阻止消息传递到根日志记录器。显然,文档还有改进的空间。

编辑:我删掉了我之前对Python日志模块的“当时”苛刻的评价。

2 个回答

1

源代码中使用了不同的大小写标识符,下面是更有用的版本:

import logging, sys
root = logging.getLogger('')
level1 = logging.getLogger('level1')
level2 = logging.getLogger('level1.level2')

class KillFilter(object):
    def filter(self, msg):
        return 0

root_handler = logging.StreamHandler(sys.stdout)
top_handler = logging.StreamHandler(sys.stdout)
bottom_handler = logging.StreamHandler(sys.stdout)
root_handler.setFormatter(logging.Formatter('ROOT HANDLER - %(msg)s'))
top_handler.setFormatter(logging.Formatter('level1 HANDLER - %(msg)s'))
bottom_handler.setFormatter(logging.Formatter('level2 HANDLER - %(msg)s'))

msg_killer = KillFilter()

root.addHandler(root_handler)
level1.addHandler(top_handler)
level2.addHandler(bottom_handler)

level1.addFilter(msg_killer)
level1.propagate = False

root.error('root_message')
level1.error('level1_message')
level2.error('level2_message')
7

首先,我在我的机器上(运行的是Python 2.6)得到的输出和你们的不一样:

ROOT
BOTTOM HANDLER
TOP HANDLER
ROOT

过滤器只会应用到发出消息的那个日志记录器上,如果消息通过了过滤器,它就会被传递给所有父日志记录器的处理器(而不是日志记录器本身)——我不知道这样设计的原因是什么。如果你想在比如说“最上面的”日志记录器实例停止传递,可以设置:

top.propagation = False

撰写回答