【问题标题】:How do I Get Stack Trace from LogRecord in Python?如何在 Python 中从 LogRecord 获取堆栈跟踪?
【发布时间】:2026-02-20 10:15:02
【问题描述】:

我正在用 Python 实现一个自定义处理程序。当然,我需要覆盖 emit(self, record) 来做到这一点。一个例子:

from logging import Handler, LogRecord

class FooHandler(Handler):
    def emit(self, record: LogRecord):
        # handler logic

如您所见,每次我使用Logger 实例记录某些内容时,这都会提供LogRecordemit 的方法。

我从 CPython 源代码中看到了 LogRecord 的当前实现,您也可以从 here 中看到它。

假设我有一个名为 loggerLogger 实例。稍后在代码中的某个地方,我会这样做:

# either this
logger.exception(Exception("foo"))
# it does not have to be an instance of Exception, it's for the sake of simplicity

# or this
logger.error("foo", exc_info=True)
# this also provides a stack trace on the console handler

由于@thebjorn 评论了traceback 模块,我想我可以解决这个问题。但是我现在有三个问题:

  1. 如何从LogRecord 实例中获取异常?
  2. 如果我执行logger.error("message", exc_info=True),那么我不会传递任何异常实例。在这种情况下,由于我没有任何异常实例,我该如何获取回溯?

提前致谢。

环境

  • Python 3.5 及以上版本

【问题讨论】:

  • traceback 模块..?
  • 实际上,SteamHandler 的实现给了我一些洞察力,但我仍然可能需要对handleError 进行解释。
  • @thebjorn,这就是我想要的。我不知道标准库中存在这样的东西。

标签: python logging python-logging


【解决方案1】:

LogRecord 对象有一个exc_text 属性,看起来与回溯中提供的文本相同。没有异常时返回None

所以我认为以下内容会得到他们最初要求的 OP:

from logging import Handler, LogRecord

class FooHandler(Handler):
    def emit(self, record: LogRecord):
        print(record.exc_text)
        # other handler logic

【讨论】:

    【解决方案2】:

    我是 OP,这可能不是最好的答案,在实践中或更 Pythonic 的方式,但对于 Google 员工来说,有一种方法。

    正如@thebjorn在问题的cmets中所说,您需要traceback内置模块。

    然后,您需要确保您所针对的异常是您的软件引发的最新异常。然后你可以简单地调用:

    traceback.print_last()
    

    如果没有异常,那么你会得到下面的字符串:

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib64/python3.7/traceback.py", line 173, in print_last
        raise ValueError("no last exception")
    ValueError: no last exception
    

    其他情况,你会得到最新异常的回溯:

    raise Exception("foo")
    traceback.print_last()
    
    # will return a string similar to below
    
    Traceback (most recent call last):
      File "/foo/bar/baz.py", line 3296, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)
      File "/foo/bar/biz.py", line 1, in <module>
        raise Exception("foo")
    Exception: foo
    

    希望这对 Google 员工有所帮助。

    注意事项

    正如我所提到的,您需要确保最后一个引发的异常是您所针对的异常。这可能不是一个可行的解决方案

    • 对于多线程代码库,因为您必须格外小心您的代码在哪个线程上运行或
    • 基于 Django 等框架构建的代码库,因为此类框架的异常处理可能非常复杂,您可能会得到一个不同的异常,而不是您想要得到的异常

    【讨论】:

    • 如果两天内没有任何详细和不同方法的答案,我将接受此答案为有效。