我同意:这是一个违反直觉的设计决策,恕我直言。
最简单的解决方案是将过滤器附加到每个可能的处理程序。例如,假设您有一个控制台处理程序、一个邮件处理程序和一个数据库处理程序,您应该将您的“根”过滤器附加到它们中的每一个。 :-/
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! :-)