我做了一个
python py_prog.py | java scalaProg.Pkgpython程序必须从DB中获取内容并将其输送到Scala程序。我们已经对python进行了集中的错误监视,但是scala程序可能会悄悄地使失败。因此,如果Scala程序失败,我希望它的stderr通过第三个程序转移到我们的监控系统中,比如bash伪代码:
(python py_prog.py | java scalaProg.Pkg) || python logging_program.py(编写logging_program并让它与我们的错误监控对话很容易,为scala程序设置一个类似的系统是很困难的)。
那么我该如何完成:
IOError: [Errno 32] Broken pipe失败时,在py_prog中处理scalaProg发布于 2013-08-08 06:48:52
使用bash,您可以使用process,并且仍然可以看到java scalaProg.Pkg的输出。
python py_prog.py | java scalaProg.Pkg 2> >(python logging_program.py)或者您也可以将它放在tee上,以便在终端上看到stderr:
python py_prog.py | java scalaProg.Pkg 2> >(tee >(python logging_program.py))如果运行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 > >(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;} > >(tee >(python logging_program.py)) 2>&1或者包括可能从调用shell生成的错误:
(python py_prog.py | java scalaProg.Pkg;) > >(tee >(python logging_program.py)) 2>&1如果您只想从会话中获取stderr,那么只需使用2>。
(python py_prog.py | java scalaProg.Pkg;) 2> >(tee >(python logging_program.py))发布于 2013-08-08 07:19:22
Tadeck的回答可以帮助您实现大部分的目标;但是,还有一个遗留的问题是py_prog.py的管道断裂错误。
事实证明,为sys.stdout捕捉断管是很棘手的,因为有时在关闭时,当为时已晚时,它们就会发生。
如果my_prog.py相对干净,你可以用一些特殊的样板包装它。为了举例说明,让我们假设它看起来类似于这个琐碎的程序:
$ cat badpipe.py
import sys
def main():
for i in range(1000):
print 'line', i
return 0
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit('\nInterrupted')最后,__name__ == '__main__'测试下的代码是--或者一直是--我的独立python程序通常使用的样板。根据这个答案,我可能需要改变它。
无论如何,如果我尝试使用两种“坏”情况来运行它,一种是立即退出,另一种是读取一点,然后退出,它表现为两种不同的方式。首先,管道进入“立即退出”:
$ python badpipe.py | (exit 0)
Traceback (most recent call last):
File "badpipe.py", line 10, in <module>
sys.exit(main())
File "badpipe.py", line 5, in main
print 'line', i
IOError: [Errno 32] Broken pipe这就是我所期望的。但是:
$ python badpipe.py | head -1
line 0
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr哇哦!怪人!:-)
结果,我可以通过对包装器进行一些调优,就可以让head -1的怪异行为(head -1)消失。不只是sys.exit(main()),我需要在调用sys.exit之前调用sys.stdout.flush() (理想情况下,也可能也调用sys.stderr.flush(),但到目前为止我只测试了这么多)
if __name__ == '__main__':
try:
ret = main()
except KeyboardInterrupt:
ret = '\nInterrupted'
try:
sys.stdout.flush()
finally:
sys.exit(ret)有了这一点,我现在可以可靠地捕获最外层的IOError,并检查断管情况。下面是最后(或多或少)版本,再次包括main:
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)捕获EPIPE后的EPIPE和更改的ret值主要用于说明-- 123没有什么特别之处。而且,我也不知道最终的raise是否正确,因为我还没有测试它。
运行此操作将提供:
$ python badpipe.py | (exit 0)
caught pipe-based IO-error
$ python badpipe.py | (head -1)
line 0
caught pipe-based IO-error
$ (注意:这都在python 2.7中,但3.2的行为类似)。
如果您可以修改py_prog.py,那么这一切都很好,但是如果不能呢?
在这种情况下,我建议编写一个包装器脚本(不管用哪种语言,Python都能正常工作)。让包装器脚本读取其所有stdin,并将其全部复制(即写)到stdout,但检查(捕获)断管错误。如果发生这种情况,那么改变策略:阅读stdin的其余部分,并将其扔掉,这样py_prog.py就会高兴地相信它成功地将所有内容发送到stdout并完成。您甚至可以将其写入运行您的subprocess.Popen命令并为您执行所有所需的特殊日志记录的java scalaProg.pkg。
您可能希望编写这个包装器,即使您可以修改py_prog.py,这完全取决于您想要发生的事情。
python py_prog.py | python wrap_java_thing.py(不过,我不会为您编写包装器:-)
顺便提一下,lost sys.stderr是一个Python,第11380期。一种简单的挑衅方式:python -c 'print "foo\n"*10000' | head -1
发布于 2013-08-08 06:20:24
执行以下操作:https://stackoverflow.com/a/2342841/548696
python py_prog.py | java scalaProg.Pkg 2>&1 >/dev/null | python logging_program.py这将从stdout中删除任何内容,并且只有stderr传递给Python脚本。
这对你有用吗?
https://stackoverflow.com/questions/18118809
复制相似问题