首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何确保报告管道中的错误

如何确保报告管道中的错误
EN

Stack Overflow用户
提问于 2013-08-08 05:53:31
回答 3查看 262关注 0票数 2

我做了一个

代码语言:javascript
复制
python py_prog.py | java scalaProg.Pkg

python程序必须从DB中获取内容并将其输送到Scala程序。我们已经对python进行了集中的错误监视,但是scala程序可能会悄悄地使失败。因此,如果Scala程序失败,我希望它的stderr通过第三个程序转移到我们的监控系统中,比如bash伪代码:

代码语言:javascript
复制
(python py_prog.py | java scalaProg.Pkg) || python logging_program.py

(编写logging_program并让它与我们的错误监控对话很容易,为scala程序设置一个类似的系统是很困难的)。

那么我该如何完成:

  1. 当scalaProg失败时,将其stderr输送到第三个程序。
  2. IOError: [Errno 32] Broken pipe失败时,在py_prog中处理scalaProg
EN

回答 3

Stack Overflow用户

发布于 2013-08-08 06:48:52

使用bash,您可以使用process,并且仍然可以看到java scalaProg.Pkg的输出。

代码语言:javascript
复制
python py_prog.py | java scalaProg.Pkg 2> >(python logging_program.py)

或者您也可以将它放在tee上,以便在终端上看到stderr:

代码语言:javascript
复制
python py_prog.py | java scalaProg.Pkg 2> >(tee >(python logging_program.py))

如果运行java scalaProg.Pkg的shell发送错误消息,则可以将其封装在子shell中以获得错误:

代码语言:javascript
复制
python py_prog.py | (java scalaProg.Pkg;) 2> >(tee >(python logging_program.py))

如果您需要获得所有东西(从java scalaProg.Pkg获得stdout和stderr ),请执行以下操作:

代码语言:javascript
复制
python py_prog.py | java scalaProg.Pkg > >(tee >(python logging_program.py)) 2>&1

或者这个:

代码语言:javascript
复制
python py_prog.py | (java scalaProg.Pkg;) > >(tee >(python logging_program.py)) 2>&1

如果您想从python py_prog.pyjava scalaProg.Pkg获得所有的stdout和stderr,请执行以下操作:

代码语言:javascript
复制
{python py_prog.py | java scalaProg.Pkg;} > >(tee >(python logging_program.py)) 2>&1

或者包括可能从调用shell生成的错误:

代码语言:javascript
复制
(python py_prog.py | java scalaProg.Pkg;) > >(tee >(python logging_program.py)) 2>&1

如果您只想从会话中获取stderr,那么只需使用2>

代码语言:javascript
复制
(python py_prog.py | java scalaProg.Pkg;) 2> >(tee >(python logging_program.py))
票数 1
EN

Stack Overflow用户

发布于 2013-08-08 07:19:22

Tadeck的回答可以帮助您实现大部分的目标;但是,还有一个遗留的问题是py_prog.py的管道断裂错误。

事实证明,为sys.stdout捕捉断管是很棘手的,因为有时在关闭时,当为时已晚时,它们就会发生。

如果my_prog.py相对干净,你可以用一些特殊的样板包装它。为了举例说明,让我们假设它看起来类似于这个琐碎的程序:

代码语言:javascript
复制
$ 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程序通常使用的样板。根据这个答案,我可能需要改变它。

无论如何,如果我尝试使用两种“坏”情况来运行它,一种是立即退出,另一种是读取一点,然后退出,它表现为两种不同的方式。首先,管道进入“立即退出”:

代码语言:javascript
复制
$ 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

这就是我所期望的。但是:

代码语言:javascript
复制
$ 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(),但到目前为止我只测试了这么多)

代码语言:javascript
复制
if __name__ == '__main__':
    try:
        ret = main()
    except KeyboardInterrupt:
        ret = '\nInterrupted'
    try:
        sys.stdout.flush()
    finally:
        sys.exit(ret)

有了这一点,我现在可以可靠地捕获最外层的IOError,并检查断管情况。下面是最后(或多或少)版本,再次包括main

代码语言:javascript
复制
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是否正确,因为我还没有测试它。

运行此操作将提供:

代码语言:javascript
复制
$ 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,这完全取决于您想要发生的事情。

代码语言:javascript
复制
python py_prog.py | python wrap_java_thing.py

(不过,我不会为您编写包装器:-)

顺便提一下,lost sys.stderr是一个Python,第11380期。一种简单的挑衅方式:python -c 'print "foo\n"*10000' | head -1

票数 1
EN

Stack Overflow用户

发布于 2013-08-08 06:20:24

执行以下操作:https://stackoverflow.com/a/2342841/548696

代码语言:javascript
复制
python py_prog.py | java scalaProg.Pkg 2>&1 >/dev/null | python logging_program.py

这将从stdout中删除任何内容,并且只有stderr传递给Python脚本。

这对你有用吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18118809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档