我想在不退出的情况下捕获和记录异常,例如,

try:
    do_stuff()
except Exception as err:
    print(Exception, err)
    # I want to print the entire traceback here,
    # not just the exception name and details

我想打印与抛出异常时打印的完全相同的输出,而不使用try/,只是拦截异常,并且我不希望它退出程序。


当前回答

您需要将try/except放在可能发生错误的最内层循环中,即。

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

... 等等

换句话说,您需要将可能在try/中失败的语句包装在尽可能具体的内部循环中。

其他回答

Python 3解决方案

stacktrace_helper.py:

from linecache import getline
import sys
import traceback


def get_stack_trace():
    exc_type, exc_value, exc_tb = sys.exc_info()
    trace = traceback.format_stack()
    trace = list(filter(lambda x: ("\\lib\\" not in x and "/lib/" not in x and "stacktrace_helper.py" not in x), trace))
    ex_type = exc_type.__name__
    ex_line = exc_tb.tb_lineno
    ex_file = exc_tb.tb_frame.f_code.co_filename
    ex_message = str(exc_value)
    line_code = ""
    try:
        line_code = getline(ex_file, ex_line).strip()
    except:
        pass

    trace.insert(
        0, f'File "{ex_file}", line {ex_line}, line_code: {line_code} , ex: {ex_type} {ex_message}',
    )
    return trace


def get_stack_trace_str(msg: str = ""):
    trace = list(get_stack_trace())
    trace_str = "\n".join(list(map(str, trace)))
    trace_str = msg + "\n" + trace_str
    return trace_str

如何在不停止程序的情况下打印完整的回溯?

当你不想因为一个错误而停止你的程序时,你需要用try/except来处理这个错误:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

要提取完整的回溯,我们将使用标准库中的traceback模块:

import traceback

并创建一个相当复杂的stacktrace来演示我们得到完整的stacktrace:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

印刷

要打印完整的回溯,请使用traceback。print_exc方法:

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

打印:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

优于打印、日志:

但是,最佳实践是为您的模块设置一个记录器。它将知道模块的名称,并且能够更改级别(在其他属性中,例如处理程序)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

在这种情况下,您将需要记录器。异常函数改为:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

日志:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

或者,您可能只想要字符串,在这种情况下,您将需要回溯。Format_exc函数改为:

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

日志:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

结论

对于这三个选项,我们看到我们得到的输出和我们有错误时是一样的:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

使用哪种

性能问题在这里并不重要,因为IO通常占主导地位。我更喜欢,因为它精确地以向前兼容的方式执行请求:

logger.exception(error)

日志级别和输出可以调整,这样就可以很容易地关闭,而不需要修改代码。通常做直接需要的是最有效的方法。

除了Aaron Hall的回答之外,如果您正在记录日志,但不想使用logging.exception()(因为它在ERROR级别记录日志),您可以使用更低的级别并传递exc_info=True。如。

try:
    do_something_that_might_error()
except Exception:
    logging.info('General exception noted.', exc_info=True)

首先,不要使用打印来记录日志,有一个稳定的、经过验证的、经过深思熟虑的stdlib模块可以做到这一点:日志。你绝对应该用它来代替。

其次,当有原生的简单方法时,不要试图用不相关的工具搞得一团糟。下面就是:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

就是这样。现在你完成了。

为任何对事物的工作原理感兴趣的人提供解释

什么日志。异常实际上所做的只是对日志的调用。error(即记录级别为error的事件),然后打印traceback。

为什么更好呢?

这里有一些注意事项:

它刚刚好; 这很简单; 这很简单。

为什么没有人应该使用exc_info=True的跟踪或调用记录器,或者用sys.exc_info弄脏他们的手?

嗯,就是因为!它们存在的目的各不相同。例如,traceback。Print_exc的输出与解释器本身产生的回溯略有不同。如果你使用它,你会让任何阅读你日志的人感到困惑,他们会用头去撞你的日志。

将exc_info=True传递给日志调用是不合适的。但是,当捕获可恢复的错误并且你想用回溯记录它们(使用,例如INFO级别)时,它是有用的,因为log。exception只产生一个级别的日志- ERROR。

而且你绝对应该避免和sys搞混。Exc_info。它不是一个公共接口,而是一个内部接口——如果你明确知道自己在做什么,你就可以使用它。它不仅仅用于打印异常。

如果你正在调试,只想查看当前的堆栈跟踪,你可以简单地调用:

traceback.print_stack ()

没有必要为了再次捕获异常而手动引发异常。