我做了
python py_prog.py | java scalaProg.Pkg
python程序必须从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
答案 0 :(得分:1)
使用bash,您可以使用流程替代,但仍会看到java scalaProg.Pkg
的输出:
python py_prog.py | java scalaProg.Pkg 2> >(python logging_program.py)
或者你可以将它放在发球台上以便在终端上看到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))
答案 1 :(得分:1)
Tadeck's answer可以帮助你完成大部分工作;但剩下的一个大问题就是管道错误导致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
哇!辣妈! : - )
事实证明,通过稍微调整我的包装,我可以通过lost sys.stderr
获得奇怪的行为(head -1
)。而不仅仅是sys.exit(main())
,我需要调用sys.stdout.flush()
(理想情况下,也可能sys.stderr.flush()
,但到目前为止我只测试了这么多),然后再调用sys.exit
:
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)
sys.stderr.write
之后EPIPE
以及ret
值的变化,主要是为了说明 - 123没有什么特别之处。另外我不知道最后的{{1}因为我没有测试它,所以工作正确。
运行此命令:
raise
(注意:这完全在python 2.7中,但3.2表现相似。)
如果您可以修改$ python badpipe.py | (exit 0)
caught pipe-based IO-error
$ python badpipe.py | (head -1)
line 0
caught pipe-based IO-error
$
,这一切都很好,但是如果你不能做什么呢?
在这种情况下,我建议编写一个包装器脚本(无论使用何种语言,Python都可以正常工作)。让你的包装器脚本读取它的所有stdin并将它全部复制(即写入)到stdout,但检查(捕获)损坏的管道错误。如果发生这种情况,更改策略:读取stdin的其余部分并将其丢弃,以便py_prog.py
愉快地相信它设法将所有内容发送到stdout并完成。您甚至可以将其写入运行py_prog.py
命令的subprocess.Popen
,并为您执行所有所需的特殊日志记录。
即使可以修改java scalaProg.pkg
,您也可能想要编写此包装器,具体取决于您希望发生的事情。
py_prog.py
(我不会为你编写包装器:-))
顺便说一下,python py_prog.py | python wrap_java_thing.py
是一个Python错误,issue 11380。激发它的一种简单方法:lost sys.stderr
答案 2 :(得分:0)
执行以下操作:https://stackoverflow.com/a/2342841/548696
python py_prog.py | java scalaProg.Pkg 2>&1 >/dev/null | python logging_program.py
这将从stdout中删除任何内容,并且只将stderr传递给Python脚本。
这对你有用吗?