2012-02-24 4 views
0

У меня есть странная проблема для чтения из STDIN в скрипте 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 я могу получить "Foo" в целевом файле /tmp/testrsyslogomoutput.txt. Однако, когда я запускаю его в rsyslog, сообщения, кажется, отправляются только тогда, когда я останавливаю/перезапускает rsyslog (я считаю, что некоторый буфер в какой-то момент сбрасывается).

Сначала я подумал, что это проблема с Rsyslog. Поэтому я заменил мою программу python оболочкой, не меняя ничего на конфигурацию rsyslog. Скрипт работает отлично с Rsyslog и как вы можете видеть в коде ниже, сценарий действительно тривиален:

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

Поскольку мой сценарий оболочки работает, но мой Python один не делает, я считаю, что я сделал ошибку где-то в мой код Python, но я не могу найти, где. Если бы вы могли указать мне на мою ошибку (и), это было бы здорово.

Заранее спасибо :)

ответ

0

Я также подозреваю, что причина в том, что Rsyslog не прекращается. readlines() не должен возвращаться, пока не достигнет реального EOF. Но почему сценарий оболочки действует по-другому? Возможно, использование/dev/stdin является причиной. Попробуйте эту версию и посмотреть, если он все еще работает без подвешивания:

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

Если это имеет значение, вы также будете иметь исправление: открытое и чтение/DEV/STDIN из питона, вместо sys.stdin.

Редактировать: cat как-то читает все, что ждет от stdin и возвращает, но python блокирует и ждет, пока stdin не будет исчерпан. Странный. Вы также можете попробовать заменить readlines() на один read(), а затем split("\n"), но на данный момент я сомневаюсь, что это поможет.

Итак, забудьте о диагнозе, и давайте попробуем обход: Force stdin сделать неблокирующий ввод-вывод. Ниже предполагается сделать:

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. Надеюсь, что это работает!

+0

Я пробовал то, что вы предлагали, это не имеет никакого значения. Он по-прежнему отлично работает с этим тривиальным сценарием оболочки. Я также попытался прочитать/dev/stdin в моем скрипте python (без readlines()), и он все еще зависает. –

+0

О, хорошо. Следующая идея: взять буферизацию i/o из python из уравнения, вызвав python с флагом -u. – alexis

+0

Спасибо за поддержку Alexis, я тоже пробовал с python -u и ничего не менял. –

2

readlines не вернется, пока он не закончит чтение файла. Так как подача трубы stdin никогда не заканчивается, readlines никогда не заканчивается. Остановка rsyslog закрывает трубку и завершает работу.

0

Если вы используете readline(), то он вернется на \n, хотя это будет только писать одну строку, а затем выйти.

Если вы хотите, чтобы продолжать писать строки, как долго они там, вы можете использовать простой for:

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

Я пробовал это. Проблема остается прежней. Я попытался перебрать sys.stdin и/dev/stdin, и вход записывается только при отправке \ n.Использование альтернативы readline, как было предложено выше, тоже не работает. –