为什么Exception输出没有被contextlib捕获.Redirect_stderr上下文管理器?



在下面的代码中,我希望异常输出和回溯被写入test.txt文件,但这并没有发生。

import contextlib
with open("test.txt", "a") as f:
with contextlib.redirect_stderr(f):
raise Exception("Hello")

为什么它不像预期的那样工作,我如何正确地将异常输出重定向到文件?

因为重定向sys.stderr不会捕获python中的异常(如果捕获了异常就很糟糕了,对吧?因为异常只应该被try/except块捕获),所以异常处理代码会中断正在运行的代码(和重定向)。

证明:

import contextlib
from sys import stderr
with open("test.txt", "a") as f:
with contextlib.redirect_stderr(f):
sys.stderr.write("hello")
sys.stderr.flush()

写正确。

要将所有异常的输出重定向到文件,您有两个选项:在try/except块中全局捕获所有异常并自己编写,或使用shell重定向将脚本的标准错误发送到文件,使用类似

的内容
python my_script.py 2>errors.txt

如果您想自己执行,请参阅这个问题以了解获取回溯的讨论。

只是为了添加一个我想要的替代实现。

下面将异常输出重定向到记录器。在我的例子中,记录器被设置为stdout(默认),所以我使用contextlib.redirect_stdout将记录器的输出重定向到一个文件,但是您当然可以直接使记录器写入一个文件。

import logging
import contextlib
from typing import Iterator

@contextlib.contextmanager
def capture_exception(logger: logging.Logger) -> Iterator[None]:
"""
Captures exceptions and redirects output to the logger
>>> import logging
>>> logger = logging.getLogger()
>>> with capture_exception(logger=logger):
>>>     raise Exception("This should be outputed to the logger")
"""
try:
# try/except block where exception is captured and logged
try:
yield None
except Exception as e:
logger.exception(e)
finally:
pass

用法:

logger = logging.getLogger()   # default should be stdout
with open("test.txt", "a") as f:
with contextlib.redirect_stdout(f), capture_exception(logger):
# ^-- multiple context managers in one `with` statement
raise Exception("The output of this exception will appear in the log. Great success.")

日志中出现的异常输出:

The output of this exception will appear in the log. Great success.
Traceback (most recent call last):
File "/tmp/ipykernel_9802/2529855525.py", line 52, in capture_exception
yield None
File "/tmp/ipykernel_9802/3344146337.py", line 9, in <module>
raise Exception("The output of this exception will appear in the log. Great success.")
Exception: The output of this exception will appear in the log. Great success.

相关内容

  • 没有找到相关文章

最新更新