无法从STDIN正确读取

时间:2012-02-24 21:18:43

标签: python rsyslog

我在python脚本中从STDIN读取时有一个奇怪的问题。

这是我的用例。我有rsyslog配置了一个输出模块,所以rsyslog可以将日志消息传递给我的Python脚本。

我的Python脚本非常简单:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys

fd = open('/tmp/testrsyslogomoutput.txt', 'a')
fd.write("Receiving log message : \n%s\n" % ('-'.join(sys.stdin.readlines())))
fd.close()

如果我运行echo "foo" | mypythonscript.py,我可以在目标文件/tmp/testrsyslogomoutput.txt中获得“foo”。但是当我在rsyslog中运行时,只有当我停止/重启rsyslog时才会发送消息(我相信某些缓冲区在某些时候被刷新)。

我首先认为这是Rsyslog的一个问题。所以我用一个shell替换了我的python程序,没有改变任何东西到rsyslog配置。 shell脚本与rsyslog完美配合,正如您在下面的代码中看到的那样,脚本非常简单:

#! /bin/sh
cat /dev/stdin >> /tmp/testrsyslogomoutput.txt

由于我的shell脚本有效,但我的Python脚本没有,我相信我在Python代码的某个地方犯了一个错误,但我无法找到它。如果你能指出我的错误那么好。

提前致谢:)

3 个答案:

答案 0 :(得分:2)

readlines在读完文件后才会返回。由于管道输送stdin永远不会完成,readlines也永远不会完成。停止rsyslog会关闭管道并让它完成。

答案 1 :(得分:0)

如果您使用readline(),它将在\n上返回,但这只会写一行然后退出。

如果你想长时间不断写行,你可以使用简单的for

for line in fd:
  fd.write("Receiving log message : \n%s\n" % (line)
fd.close()

答案 2 :(得分:0)

我还怀疑原因是rsyslog没有终止。 readlines()在达到真正的EOF之前不应该返回。但是为什么shell脚本会有不同的行为?也许使用/ dev / stdin是原因。试试这个版本,看它是否仍然没有挂起:

#!/bin/sh
cat >> /tmp/testrsyslogomoutput.txt

如果这有所不同,你也会有一个修复:从python中打开并读取/ dev / stdin,而不是sys.stdin。

编辑:所以cat以某种方式读取在stdin等待的东西并返回,但是python阻塞并等待直到stdin耗尽。奇怪。您也可以尝试将readlines()替换为read()后跟split("\n"),但此时我怀疑这会有所帮助。

所以,忘记诊断,让我们尝试解决方法:强制stdin进行非阻塞i / o。应该这样做:

import fcntl, os

# Add O_NONBLOCK to the stdin descriptor flags 
flags = fcntl.fcntl(0, fcntl.F_GETFL)
fcntl.fcntl(0, fcntl.F_SETFL, fl | os.O_NONBLOCK)

message = sys.stdin.read().split("\n")  # Read what's waiting, in one go
fd = open('/tmp/testrsyslogomoutput.txt', 'a')
fd.write("Receiving log message : \n%s\n" % ('-'.join(message)))
fd.close()

您可能希望将其与python -u结合使用。希望它有效!