gpt4 book ai didi

Python StringIO 没有正确地从 stderr 捕获数据

转载 作者:太空宇宙 更新时间:2023-11-04 05:59:17 25 4
gpt4 key购买 nike

我已经编写了一些单元测试来分析使用标准 python 日志记录功能记录的数据。使用我在这里找到的一些想法:Capture stdout from a script in Python关于如何从 stderr 捕获数据,我想出了以下脚本,我已将其简化到最低限度以说明我遇到的问题。 (下面的循环模拟了这个函数可能被各种单元测试调用的事实)

import logging, sys
from StringIO import StringIO

def get_stderr():
saved_stderr = sys.stderr

stderr_string_io = StringIO()
sys.stderr = stderr_string_io
try:
logging.error("Foobar!!!")

finally:
# set the stdout and stderr back to their original values
sys.stderr = saved_stderr

err_output = stderr_string_io.getvalue()
return err_output

for x in [1, 2]:
err_output = get_stderr()
print "Run %d: %s" % (x, err_output)

如果您运行该脚本,它将给出以下输出,其中第二次循环迭代的日志输出完全丢失:

Run 1: ERROR:root:Foobar!!!
Run 2:
Process finished with exit code 0

虽然我希望它能提供以下输出:

Run 1: ERROR:root:Foobar!!!
Run 2: ERROR:root:Foobar!!!
Process finished with exit code 0

注意:在函数末尾执行 stderr_string_io.close() 不起作用,因为脚本会在下次执行该函数时抛出 ValueError .

为什么这段代码没有按预期运行,解决这个问题的解决方案是什么?

最佳答案

当你打电话时

logging.error

运行

def error(msg, *args, **kwargs):
if len(root.handlers) == 0:
basicConfig()
root.error(msg, *args, **kwargs)

由于开始时没有根处理程序,它运行 basicConfig 时不带任何参数,这会:

def basicConfig():
_acquireLock()
try:
if len(root.handlers) == 0:
h = StreamHandler(None)
handlers = [h]
dfs = None
style = '%'
fs = kwargs.get("format", _STYLES[style][1])
fmt = Formatter(fs, dfs, style)
for h in handlers:
if h.formatter is None:
h.setFormatter(fmt)
root.addHandler(h)
finally:
_releaseLock()

我删除了没有参数时无法运行的代码。

所以这设置了handlers = [StreamHandler(None)]:

class StreamHandler(Handler):
def __init__(self, stream=None):
Handler.__init__(self)
if stream is None:
stream = sys.stderr
self.stream = stream

这意味着您将顶级记录器永久附加到您调用它时 stdout 的任何内容。

这会导致您的问题,因为您丢弃了该输出。这意味着输出将转到死的 StringIO 对象,并丢失。

处理此问题的一种方法是在更新 stderr 时通过 handlers 并替换任何引用 stderr 的内容:

import logging, sys
from StringIO import StringIO

def get_stderr():
saved_stderr = sys.stderr
stderr_string_io = StringIO()

for handler in logging.root.handlers:
if handler.stream is sys.stderr:
handler.stream = stderr_string_io

sys.stderr = stderr_string_io

try:
logging.error("Foobar!!!")

finally:
# set the stdout and stderr back to their original values
for handler in logging.root.handlers:
if handler.stream is sys.stderr:
handler.stream = saved_stderr

sys.stderr = saved_stderr

err_output = stderr_string_io.getvalue()
return err_output

for x in [1, 2]:
err_output = get_stderr()
print "Run %d: %s" % (x, err_output)

我不知道这会有多好。它也不会捕获任何不是根记录器的记录器。就个人而言,按值捕获 sys.stdout 的想法是荒谬的,这似乎是不可避免的结果。

关于Python StringIO 没有正确地从 stderr 捕获数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25989123/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com