简体   繁体   English

如何在 Python 中从 LogRecord 获取堆栈跟踪?

[英]How do I Get Stack Trace from LogRecord in Python?

I am implementing a custom Handler with Python.我正在用 Python 实现一个自定义处理程序。 Naturally, I need to override emit(self, record) to do that.自然,我需要重写emit(self, record)来做到这一点。 An example:一个例子:

from logging import Handler, LogRecord

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

As you can see, everytime I log something with a Logger instance, this will provide a LogRecord to emit method.如您所见,每次我使用Logger实例记录某些内容时,这将提供一个LogRecordemit方法。

I see the current implementation of LogRecord from CPython source, you can also see it from here .我从 CPython 源代码中看到了LogRecord的当前实现,您也可以从这里看到它。

Assuming I have Logger instance called logger .假设我有一个名为loggerLogger实例。 Later somewhere in the code, I do these:稍后在代码中的某处,我执行以下操作:

# 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

Since @thebjorn has commented about traceback module, I think I can work around from that.由于@thebjorn 评论了回溯模块,我想我可以解决这个问题。 However I have three questions right now:但是我现在有三个问题:

  1. How do I get the exception from LogRecord instance?如何从LogRecord实例中获取异常?
  2. If I do logger.error("message", exc_info=True) , then I do not pass any exception instance.如果我执行logger.error("message", exc_info=True) ,那么我不会传递任何异常实例。 In this case, how do I get the traceback since I do not simply have any exception instance?在这种情况下,我如何获得回溯,因为我没有任何异常实例?

Thanks in advance.提前致谢。

Environment环境

  • Python 3.5 and above Python 3.5 及以上版本

I am the OP and this may not be the best answer, in practice or more Pythonic way but, for Googlers, there is a method.我是 OP,这可能不是最好的答案,在实践中或更 Pythonic 的方式,但对于谷歌人来说,有一种方法。

As @thebjorn stated in the comments of the question, you need traceback built-in module.正如@thebjorn在问题评论中所述,您需要回溯内置模块。

Then you need to make sure that the exception you are targeting is the latest exception your software has raised.然后,您需要确保您所针对的异常是您的软件引发的最新异常。 Then you can simply call:然后你可以简单地调用:

traceback.print_last()

If there is no exception, then you will get below as a string:如果没有例外,那么您将得到以下字符串:

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

In other case, you will get the latest exception's traceback:在其他情况下,您将获得最新异常的回溯:

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

Hope this helps to Googlers.希望这对 Google 员工有所帮助。

Things to Be Aware Of需要注意的事项

As I've mentioned, you will need to make sure that the last exception that has got raised is the exception that you are targeting.正如我所提到的,您需要确保引发的最后一个异常是您所针对的异常。 This might not be a viable solution这可能不是一个可行的解决方案

  • for multithreaded codebase because you must be extra careful about which thread your code is running on or对于多线程代码库,因为您必须格外小心您的代码在哪个线程上运行,或者
  • a codebase that is structured upon a framework such as Django because the exception handling of such frameworks might be quite complex and you might get a different Exception rather than the one you were excepting to get一个基于 Django 等框架构建的代码库,因为此类框架的异常处理可能非常复杂,并且您可能会得到一个不同的异常,而不是您想要得到的异常

The LogRecord object has an exc_text attribute that looks to be identical to the text provided in a traceback. LogRecord 对象有一个exc_text属性,该属性看起来与回溯中提供的文本相同。 It returns None when there isn't an exception.没有异常时返回None

So I think the following would get the OP what they were originally requesting:所以我认为以下内容会得到他们最初要求的 OP:

from logging import Handler, LogRecord

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

Expanding upon sazerac's code, exec_text didn't have any value when I ran it with a sample try except block, but exc_info WAS populated.扩展 sazerac 的代码,当我使用除块之外的示例尝试运行 exec_text 时,它没有任何价值,但 exc_info 已填充。 This is what I used to work around my scenario.这就是我用来解决我的场景的方法。

from logging import Handler, LogRecord
import traceback

class FooHandler(Handler):
    def emit(self, record: LogRecord):
        if record.exc_info:
            errType, errValue, errTraceback = record.exc_info
            msg = "".join(traceback.format_exception(errType, errValue, errTraceback))
        else:
            msg = ''
        print(msg)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM