Python中依赖于上下文的日志级别

时间:2013-07-07 22:39:13

标签: python logging thread-local

我正在用Python构建一个Web应用程序框架原型(主要是出于教育目的)而且我坚持了很长一段时间我想要的一个功能:每个路由的日志级别。

此功能的目标是确定我们正在执行诊断的一些特定入口点。例如,我想跟踪呼叫者点击POST /sessions/login时发生的情况。现在,我希望获得100%的日志条目,以便通过此URL的请求处理命中代码。这意味着一切,包括第三方应用程序中发生的任何事情。

示例:虚构的应用程序有两条路线:/sessions/login/sessions/info。两个请求处理程序都使用记录器users命中了myapp.users.db个包中的相同数据库代码。对/sessions/login的请求处理应该在记录器myapp.users.db上发出日志消息,但/sessions/info的请求处理不应该。{/ p>

问题在于,它不适合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

现在,这甚至适用于根记录器。我不得不承认,我对猴子修补这个功能感到有些不舒服,但是它又回到了通常的基础设施上,所以它实际上并没有看起来那么脏。

1 个答案:

答案 0 :(得分:0)

最好使用附加到记录器(或处理程序)的logging.Filter,它使用上下文来删除事件(通过从False方法返回filter )或允许记录事件(通过从True方法返回filter)。

虽然不完全适合您的用例,但我在this post中说明了使用带有线程局部上下文的过滤器。