gpt4 book ai didi

python - 为什么附加到根记录器的过滤器不传播到后代记录器?

转载 作者:太空狗 更新时间:2023-10-29 21:55:43 26 4
gpt4 key购买 nike

摘自 python logging documentation 的第 15.7.4 段:

Note that filters attached to handlers are consulted whenever an event is emitted by the handler, whereas filters attached to loggers are consulted whenever an event is logged to the handler (using debug(), info(), etc.) This means that events which have been generated by descendant loggers will not be filtered by a logger’s filter setting, unless the filter has also been applied to those descendant loggers.

我不明白这个设计决定。将根记录器的过滤器也应用于后代记录器不是更有意义吗?

最佳答案

我同意:恕我直言,这是一个违反直觉的设计决定。

最简单的解决方案是将过滤器附加到每个可能的处理程序。例如,假设您有一个控制台处理程序、一个邮件处理程序和一个数据库处理程序,您应该将“根”过滤器附加到它们中的每一个。 :-/

import logging
import logging.config

class MyRootFilter(logging.Filter):
def filter(self, record):
# filter out log messages that include "secret"
if "secret" in record.msg:
return False
else:
return True

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'my_root_filter': {
'()': MyRootFilter,
},
},
'handlers': {
'stderr': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'filters': ['my_root_filter'],
},
'mail_admins': {
'level': 'ERROR',
'class': 'some.kind.of.EmailHandler',
'filters': ['my_root_filter'],
},
'database': {
'level': 'ERROR',
'class': 'some.kind.of.DatabaseHandler',
'filters': ['my_root_filter'],
},
},
'loggers': {
'some.sub.project': {
'handlers': ['stderr'],
'level': 'ERROR',
},
},
}

logging.config.dictConfig(LOGGING)
logging.getLogger("some.sub.project").error("hello") # logs 'hello'
logging.getLogger("some.sub.project").error("hello secret") # filtered out! :-)

如果有很多处理程序,您可能希望以编程方式而不是手动方式将根过滤器附加到每个处理程序。我建议您直接在配置字典(或文件,取决于您加载日志配置的方式)上执行此操作,而不是加载配置后执行此操作,因为似乎没有记录方式获取所有处理程序的列表。我找到了 logger.handlers 和 logging._handlers,但由于没有记录它们,它们将来可能会中断。另外,不能保证它们是线程安全的。

先前的解决方案(在加载之前将根过滤器直接附加到配置中的每个处理程序)假定您在加载日志配置之前可以控制它,并且不会动态添加任何处理程序(使用 Logger#添加处理程序 ())。如果这不是真的,那么您可能想要对日志记录模块进行猴子修补(祝您好运!)。

编辑

我试了一下猴子补丁 Logger#addHandler,只是为了好玩。它实际上工作正常并简化了配置,但我不确定我会推荐这样做(我讨厌猴子修补,当出现问题时很难调试)。使用风险自负...

import logging
import logging.config

class MyRootFilter(logging.Filter):
[...] # same as above

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'stderr': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
# it's shorter: there's no explicit reference to the root filter
},
[...] # other handlers go here
},
'loggers': {
'some.sub.project': {
'handlers': ['stderr'],
'level': 'ERROR',
},
},
}

def monkey_patched_addHandler(self, handler):
result = self.old_addHandler(handler)
self.addFilter(MyRootFilter())
return result

logging.Logger.old_addHandler = logging.Logger.addHandler
logging.Logger.addHandler = monkey_patched_addHandler

logging.config.dictConfig(LOGGING)
logging.getLogger("some.sub.project").error("hello") # logs 'hello'
logging.getLogger("some.sub.project").error("hello secret") # filtered out! :-)

关于python - 为什么附加到根记录器的过滤器不传播到后代记录器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6850798/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com