我在Python中原型化了一个web应用程序框架(主要用于教育目的),而且我被困在了一个我想要的如此长时间的功能上:每个路由日志级别。Python中的上下文相关日志级别
此功能的目标是确定我们执行诊断的某些特定入口点。例如,我想跟踪当呼叫者打到POST /sessions/login
时发生了什么。现在,我希望获得该URL的请求处理命中的100%日志条目。这意味着一切,包括第三方应用程序中发生的一切。
示例:虚构应用程序有两条路线:/sessions/login
和/sessions/info
。两个请求处理程序都使用记录器myapp.users.db
打包users
中的相同数据库代码。 /sessions/login
的请求处理应在日志记录器myapp.users.db
上发送日志消息,但不应请求处理/sessions/info
。
问题是,这不符合Python的日志记录库,它以层次结构的方式分解日志,这对于分层(例如通过应用程序层控制日志级别)很好。
我真正想要的是一个依赖于上下文的日志级别。想到的自然实现是使得logger.getEffectiveLevel()
返回线程本地日志级别(使用调试中间件有条件地降低日志级别以在请求URL受调试时调试)。但是,我正在查看Python文档中的logging flow,并且我不明白如何使用任何不同类型的配置挂钩来实现此操作。
问题:你如何在Python中实现上下文相关的日志级别?
更新:我发现的部分解决方案。
context = threading.local()
class ContextualLogger(logging.Logger):
def getEffectiveLevel(self):
global context
level = getattr(context, 'log_level', logging.NOTSET)
if level == logging.NOTSET:
level = super(ContextualLogger, self).getEffectiveLevel()
return level
logging.setLoggerClass(ContextualLogger)
但是,这对于根记录器不起作用。有任何想法吗?
更新:它也可以猴子修补getEffectiveLevel()
功能。
context = threading.local()
# Monkey patch "getEffectiveLevel()" to consult the current setting in the
# `context.log_level` thread-local storage. If that value is present, use
# it to override the current value; else, compute the level using the usual
# infrastructure.
default_getEffectiveLevel = logging.Logger.getEffectiveLevel
def patched_getEffectiveLevel(self):
level = getattr(context, 'log_level', logging.NOTSET)
if level == logging.NOTSET:
level = default_getEffectiveLevel(self)
return level
logging.Logger.getEffectiveLevel = patched_getEffectiveLevel
现在,即使对于根记录器也是如此。我不得不承认,我对猴子修补这个功能有点不舒服,但是它又回到了平常的基础设施上,所以它实际上不像看起来那么脏。
由于该解决方案只允许我应用比已经实施的日志级别更严格的日志级别(当当前级别为logging.DEBUG时,过滤器可以应用logging.WARNING,而不是其他方式)我怀疑我必须将所有记录器配置到'logging.DEBUG'级别,然后仅从线程变量中控制日志级别呢?将其与我的问题中的部分解决方案进行对比,这使您可以完全替换有效的日志级别,而不考虑当前级别。 –