我正在用 Python 制作一个 Web 应用程序框架的原型(主要用于教育目的),但我一直坚持我一直想要的一个功能:每个路由日志级别。
此功能的目标是识别我们正在执行诊断的一些特定入口点。例如,我想跟踪呼叫者点击时发生的事情POST /sessions/login
。现在,我想获得 100% 的日志条目,以获取此 URL 的请求处理命中的代码。这意味着一切,包括 3rd 方应用程序中发生的任何事情。
示例:虚构的应用程序有两条路线:/sessions/login
和/sessions/info
. users
两个请求处理程序都在使用 logger的包中访问相同的数据库代码myapp.users.db
。请求处理/sessions/login
应该在 logger 上发出日志消息myapp.users.db
,但请求处理/sessions/info
不应该。
问题是这不适合Python 的日志库,它以分层方式分解日志,这对于分层(例如,通过应用程序层控制日志级别)非常有用。
我真正想要的是一个依赖于上下文的日志级别。想到的自然实现是logger.getEffectiveLevel()
返回线程本地日志级别的东西(如果请求 URL 需要调试,则调试中间件有条件地降低日志级别以进行调试)。但是,我正在查看 Python 文档中的日志记录流程,但我不明白如何使用许多不同类型的配置挂钩来实现这一点。
问题:您将如何在 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
现在,这甚至适用于根记录器。我不得不承认我对猴子修补这个功能有点不舒服,但是它又回到了通常的基础设施上,所以它实际上并不像看起来那么脏。