【问题标题】:Context-dependent log level in PythonPython中依赖于上下文的日志级别
【发布时间】:2013-07-05 05:20:08
【问题描述】:

我正在用 Python 制作一个 Web 应用程序框架的原型(主要用于教育目的),但我一直坚持我想要很久的一个特性:每个路由的日志级别。

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

示例:虚构的应用程序有两个路由:/sessions/login/sessions/info。两个请求处理程序都命中了包users 中的相同数据库代码,该代码使用记录器myapp.users.db/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

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

【问题讨论】:

    标签: python logging thread-local


    【解决方案1】:

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

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

    【讨论】:

    • 因为该解决方案只允许我应用比已经强制执行的日志级别更严格的日志级别(当当前级别为 logging.DEBUG 时,过滤器可以应用 logging.WARNING,但反之则不行) ,我怀疑我必须将所有记录器配置为logging.DEBUG 级别,然后仅从线程变量控制日志级别?将此与我的问题中的部分解决方案进行对比,它允许您完全替换有效日志级别,而不管当前级别如何。
    猜你喜欢
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-16
    相关资源
    最近更新 更多