Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 忽略并使用contextlib contextmanager记录错误_Python_Exception Handling_Contextmanager - Fatal编程技术网

Python 忽略并使用contextlib contextmanager记录错误

Python 忽略并使用contextlib contextmanager记录错误,python,exception-handling,contextmanager,Python,Exception Handling,Contextmanager,我希望上下文管理器捕获异常,打印堆栈跟踪,然后允许执行继续 我想知道我是否可以用contextlib contextmanager装饰器来实现这一点。如果没有,我怎么做 文件表明: 在生成器生成时,将执行with语句中嵌套的块。然后,在模块退出后,发电机恢复运行。如果块中发生未处理的异常,则会在发生屈服点的生成器内部重新调用该异常。因此,您可以使用try…except…finally语句来捕获错误(如果有),或者确保进行一些清理。如果捕获异常只是为了记录它或执行某些操作(而不是完全抑制它),则生

我希望上下文管理器捕获异常,打印堆栈跟踪,然后允许执行继续

我想知道我是否可以用contextlib contextmanager装饰器来实现这一点。如果没有,我怎么做

文件表明:

在生成器生成时,将执行with语句中嵌套的块。然后,在模块退出后,发电机恢复运行。如果块中发生未处理的异常,则会在发生屈服点的生成器内部重新调用该异常。因此,您可以使用try…except…finally语句来捕获错误(如果有),或者确保进行一些清理。如果捕获异常只是为了记录它或执行某些操作(而不是完全抑制它),则生成器必须重新释放该异常

因此,我尝试了文档引导我采用的显而易见的方法:

import contextlib
import logging


@contextlib.contextmanager
def log_error():
    try:
        yield
    except Exception as e:
        logging.exception('hit exception')
    finally:
        print 'done with contextmanager'


def something_inside_django_app():
    with log_error():
        raise Exception('alan!')


something_inside_django_app()


print 'next block of code'
这将产生输出

ERROR:root:hit exception
Traceback (most recent call last):
  File "exception_test.py", line 8, in log_error
    yield
  File "exception_test.py", line 17, in something_inside_django_app
    raise Exception('alan!')
Exception: alan!
done with contextmanager
next block of code
这将丢失有关引发异常的位置的关键信息。考虑一下当你调整上下文管理器以不排除异常时得到的:

Traceback (most recent call last):
  File "exception_test.py", line 20, in <module>
    something_inside_django_app()
  File "exception_test.py", line 17, in something_inside_django_app
    raise Exception('alan!')
Exception: alan!
回溯(最近一次呼叫最后一次):
文件“exception_test.py”,第20行,在
应用程序()中的某些内容
文件“exception\u test.py”,第17行,在应用程序中的某物中
引发异常('alan!')
例外:艾伦!
是的,它可以告诉我,例外情况是从17号线提出的,非常感谢,但之前在20号线的电话丢失了信息。如何让上下文管理器为我提供实际的完整调用堆栈,而不是它的截断版本?总而言之,我想满足两个要求:

  • 让python上下文管理器抑制在其包装的代码中引发的异常
  • 打印由该代码生成的堆栈跟踪,如果我没有使用上下文管理器的话

如果这不能用decorator完成,那么我将使用另一种风格的上下文管理器。如果无法使用上下文管理器完成此操作,我想知道什么是好的pythonic替代方案。

我已在此处更新了此问题的解决方案:

这个问题遗漏了更多的背景。为了在异常点获得完整的堆栈,我们需要返回到上下文管理器的回溯和当前上下文。然后我们可以把书堆的顶部和底部粘在一起

为了更好地说明用例,考虑一下:

def err_method1():
    print [1, 2][4]


def err_method2():
    err_method1()


def outside_method1():
    with log_error():
        err_method2()


def outside_method2():
    outside_method1()

outside_method2()
为了真正完成这个问题所要寻找的,我们希望在调用堆栈中同时看到外部方法和内部方法

这里有一个解决方案似乎确实适用于此:

class log_error(object):

    def __enter__(self):
        return

    def __exit__(self, exc_type, exc_value, exc_traceback):
        if exc_value:
            # We want the _full_ traceback with the context, so first we
            # get context for the current stack, and delete the last 2
            # layers of context, saying that we're in the __exit__ method...
            top_stack = StringIO.StringIO()
            tb.print_stack(file=top_stack)
            top_lines = top_stack.getvalue().strip('\n').split('\n')[:-4]
            top_stack.close()
            # Now, we glue that stack to the stack from the local error
            # that happened within the context manager
            full_stack = StringIO.StringIO()
            full_stack.write('Traceback (most recent call last):\n')
            full_stack.write('\n'.join(top_lines))
            full_stack.write('\n')
            tb.print_tb(exc_traceback, file=full_stack)
            full_stack.write('{}: {}'.format(exc_type.__name__, str(exc_value)))
            sinfo = full_stack.getvalue()
            full_stack.close()
            # Log the combined stack
            logging.error('Log message\n{}'.format(sinfo))
        return True
回溯看起来像:

ERROR:root:Log message
Traceback (most recent call last):
  File "exception_test.py", line 71, in <module>
    outside_method2()
  File "exception_test.py", line 69, in outside_method2
    outside_method1()
  File "exception_test.py", line 65, in outside_method1
    err_method2()
  File "exception_test.py", line 60, in err_method2
    err_method1()
  File "exception_test.py", line 56, in err_method1
    print [1, 2][4]
IndexError: list index out of range
错误:根:日志消息
回溯(最近一次呼叫最后一次):
文件“exception_test.py”,第71行,在
外部方法2()
文件“exception_test.py”,第69行,in-out_method2
外部方法1()
文件“exception_test.py”,第65行,in-out_method1
错误方法2()
文件“exception_test.py”,第60行,在err_method2中
错误方法1()
文件“exception_test.py”,第56行,在err_method1中
印刷版[1,2][4]
索引器:列表索引超出范围
这与您在尝试中执行
日志记录时所期望的信息相同。异常
,除了在上下文管理器中包装的相同代码上。

类似于