Python 如何确保报告管道中的错误
我做一个 python程序必须从DB中获取内容并通过管道将其传输到Scala程序。我们已经为python集中了错误监控,但是scala程序可能会自动失败。因此,如果Scala程序失败,我希望它的stderr通过第三个程序(如bash伪代码)传输到我们的监控系统:Python 如何确保报告管道中的错误,python,bash,Python,Bash,我做一个 python程序必须从DB中获取内容并通过管道将其传输到Scala程序。我们已经为python集中了错误监控,但是scala程序可能会自动失败。因此,如果Scala程序失败,我希望它的stderr通过第三个程序(如bash伪代码)传输到我们的监控系统: python py_prog.py | java scalaProg.Pkg (编写logging_程序并使其与我们的错误监控对话很容易,为scala程序设置类似的系统很难) 那么,我如何做到: 当scalaProg失败时,将其std
python py_prog.py | java scalaProg.Pkg
(编写logging_程序
并使其与我们的错误监控对话很容易,为scala程序设置类似的系统很难)
那么,我如何做到:
IOError:[Errno 32]管道破裂
这对您有用吗?使用bash,您可以使用进程子替换,并且仍然可以看到
java scalaProg.Pkg的输出:
python py_prog.py | java scalaProg.Pkg 2>&1 >/dev/null | python logging_program.py
或者,您也可以将其放置在T形三通上,以查看终端上的stderr:
python py_prog.py | java scalaProg.Pkg 2> >(python logging_program.py)
{python py_prog.py | java scalaProg.Pkg;} > >(tee >(python logging_program.py)) 2>&1
如果是运行java scalaProg.Pkg
的shell发送错误消息,则可以将其封装在子shell中以获取错误:
python py_prog.py | java scalaProg.Pkg 2> >(tee >(python logging_program.py))
如果您需要从java scalaProg.Pkg
获取所有内容(包括stdout和stderr),请执行以下操作:
python py_prog.py | (java scalaProg.Pkg;) 2> >(tee >(python logging_program.py))
python py_prog.py | (java scalaProg.Pkg;) > >(tee >(python logging_program.py)) 2>&1
或者这个:
python py_prog.py | java scalaProg.Pkg > >(tee >(python logging_program.py)) 2>&1
如果您想从python py_prog.py
和java scalaProg.Pkg
获取所有stdout和stderr,请执行以下操作:
python py_prog.py | (java scalaProg.Pkg;) 2> >(tee >(python logging_program.py))
python py_prog.py | (java scalaProg.Pkg;) > >(tee >(python logging_program.py)) 2>&1
或者这也包括可能由调用shell生成的错误:
python py_prog.py | java scalaProg.Pkg 2> >(python logging_program.py)
{python py_prog.py | java scalaProg.Pkg;} > >(tee >(python logging_program.py)) 2>&1
如果您只想从会话中获取stderr,那么只需使用2>
:
(python py_prog.py | java scalaProg.Pkg;) > >(tee >(python logging_program.py)) 2>&1
可以让您完成大部分工作;但仍然存在的一个大问题是断管错误导致py_prog.py
事实证明,为sys.stdout
捕获损坏的管道是一件棘手的事情,因为有时它们会在关机时发生,但为时已晚
如果my_prog.py
相对干净,您可以使用一些特殊的样板文件来包装它。例如,为了便于说明,它看起来像这个简单的程序:
(python py_prog.py | java scalaProg.Pkg;) 2> >(tee >(python logging_program.py))
最后的\uuuu name\uuuu='\uuuuu main\uuuu'
测试下的代码是或已经是我的独立python程序的常用样板文件。根据这个答案,我可能需要更改它
无论如何,如果我试着用两个“坏”案例运行它,一个是立即退出,另一个是读一点然后退出,它的行为有两种不同的方式。首先,管道进入“立即退出”:
哇!奇怪!:-)
事实证明,我可以通过稍微调整一下包装器,使头-1的反常行为(lost sys.stderr
)消失。在调用sys.exit
之前,我需要调用sys.stdout.flush()
(理想情况下,也可以调用sys.stderr.flush()
,但到目前为止我只测试了这么多):
$ python badpipe.py | head -1
line 0
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
有了这个,我现在可以可靠地捕捉到最外层的IOError
,并检查是否有破损的管壳。以下是最终(或多或少)版本,再次包括main
:
if __name__ == '__main__':
try:
ret = main()
except KeyboardInterrupt:
ret = '\nInterrupted'
try:
sys.stdout.flush()
finally:
sys.exit(ret)
捕获EPIPE
后的sys.stderr.write
,以及更改的ret
值,主要用于说明123没有什么特别之处。另外,我也不知道最终的raise
是否正常工作,因为我还没有测试它
运行此命令将提供:
import errno, sys
def main():
for i in range(1000):
print 'line', i
return 0
if __name__ == '__main__':
ret = 0
try:
try:
ret = main()
except KeyboardInterrupt:
ret = '\nInterrupted'
finally:
sys.stdout.flush()
except IOError as err:
if err.errno == errno.EPIPE:
sys.stderr.write('caught pipe-based IO-error\n')
ret = 123 # or whatever
else:
raise # some other I/O error; attempt to get a traceback
finally:
sys.exit(ret)
(注意:这都在Python2.7中,但3.2的行为类似。)
如果您可以修改
py\u prog.py
,那么这一切都很好,但是如果您不能修改呢
在这种情况下,我建议编写一个包装器脚本(无论用哪种语言,Python都可以)。让您的包装器脚本读取其所有stdin并将其全部复制(即写入)到stdout,但检查(捕获)断开的管道错误。如果出现这种情况,改变策略:阅读stdin的其余部分并将其扔掉,这样py_prog.py
就会愉快地相信它成功地将所有内容发送到stdout并完成。您甚至可以将其写入一个subprocess.Popen
,该程序运行java scalaProg.pkg
命令,并为您执行所有需要的特殊日志情况
即使可以修改py\u prog.py
,您也可能希望编写此包装,具体取决于您希望发生的事情
$ python badpipe.py | (exit 0)
caught pipe-based IO-error
$ python badpipe.py | (head -1)
line 0
caught pipe-based IO-error
$
(不过我不会给你写包装纸:-)
顺便说一句,
丢失的sys.stderr
是一个Python错误。一个简单的方法引发它:python-c'print“foo\n”*10000'| head-1
scalaProg中的错误与py\u prog
中的管道破裂有什么关系?它发生在sys.stdout.write()中
因为scalaProg
已崩溃,但我希望logging\u程序
仅在scalaProg
失败时运行请解释它检查失败的部分,然后再将其重定向到logging\u程序
请注意scalaProg始终返回stderr,但我们仅在它崩溃时才需要它,在这种情况下,我们需要将其发送到日志记录_program@aitchnyu如果您只能在退出时检测到java scalaProg.Pkg
是否已经出现问题,那么您必须将错误输出临时发送到某个地方,比如缓冲区或文件上。如果您想运行python logging\u program.py
并在它不再运行后读取它的错误消息,这几乎是不可能的。如果你想有一个临时文件解决方案,它可以提供。即使在读取命名管道时,也不能继续或停止正在运行的程序,除非另一端有人从中读取。