从check_output中抑制stdout,但将其写入日志

hob*_*es3 3 python logging subprocess stdout

我有以下代码:

try:
    subprocess.check_output(command.split())
except subprocess.CalledProcessError as e:
    count_failure.increment()
    logger.error(e.__dict__)
    return
Run Code Online (Sandbox Code Playgroud)

如果check_output()失败,那么我想从stdout中删除该消息,但将其写入我的logger.

现在stdout错误消息搞砸了我的tqdm进度条:

[hobbes3@hobbes3 bin]$ ./mass_index.py
34%|??????????????????????????????????????????                                                                                | 13/38 [00:00<00:14,  1.75it/s]
unable to open file: path='/mnt/data/samples/irs_990/foo.xml' error='Permission denied'
100%|??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????| 38/38 [00:02<00:00,  5.96it/s]
Run Code Online (Sandbox Code Playgroud)

此外,实际消息Permission denied不存储在内部e.我e.__dict__唯一说的

{'returncode': 22, 'cmd': ['/opt/splunk/bin/splunk', 'add', 'oneshot', '/mnt/data/samples/irs_990/foo.xml', '-index', 'main', '-sourcetype', 'irs_990'], 'output': b'', 'stderr': None}
Run Code Online (Sandbox Code Playgroud)

Jea*_*bre 6

这是因为您正在运行的命令正在向标准错误流发出错误消息.

check_output除非您使用额外参数,否则仅捕获标准输出.所以要么:

subprocess.check_output(command.split(),stderr=subprocess.STDOUT)
Run Code Online (Sandbox Code Playgroud)

所以错误也在输出中,或者(python 3):

subprocess.check_output(command.split(),stderr=subprocess.DEVNULL)
Run Code Online (Sandbox Code Playgroud)

完全抑制此错误消息.

要获得包含标准错误的正确异常消息,您必须将错误流重定向到特定管道,这样您就不会有 stderr=None

subprocess.check_output(command.split(),stderr=subprocess.PIPE)
Run Code Online (Sandbox Code Playgroud)

但这可能导致输出和错误流之间的死锁(取决于程序输出到输出或错误的方式,如果管道没有以智能方式读取(例如:带线程),一个写入可能因为缓冲区已满而阻塞'正在读另一个空的).

也许在你的情况下,你会更好,subprocess.Popencommunicate处理这种情况很好(线程或其他工作在下面)

p = subprocess.Popen(command.split(),stderr=subprocess.PIPE,stdout=subprocess.PIPE)
output,error = p.communicate()
Run Code Online (Sandbox Code Playgroud)

(并保持相同的异常处理)