Я написал сценарий Python, который берет записи журнала из syslog-ng
и записывает их в MongoDB (я не мог этого сделать с драйвером afmongodb, потому что мне нужно было выполнить некоторую специальную обработку).
Вот как это выглядит в syslog-ng.conf:
destination d_mongodb_events {
program("/home/test/syslog_piper.py"
template("$UNIXTIME|$PRIORITY|$FACILITY|$SOURCEIP|$SEQNUM|$PID|$PROGRAM|$MSGONLY\n")
flags(no_multi_line)
flush_lines(1)
flush_timeout(1000)
);
};
А вот сценарий: (без логики)
import sys
try:
lines = sys.stdin.readlines()
for line in lines:
# process `line` and save to DB
except Exception, e:
f = open('/tmp/error.txt','ab')
f.write(e)
f.close()
exit(0)
Сценарий работает - то есть, если я запускаю его из командной строки, он ждет ввода и вставляет строки в БД, как только я нажимаю Ctrl+D
- и уходит.
С участием syslog-ng
это отличается. Записи передаются в сценарий, но только после того, как я стоп демон syslog-ng. Кроме того, пока работает syslog-ng, я вижу, что мой скрипт тоже работает (в списке процессов). Я пробовал установить flush_lines()
и flush_timeout()
(см. конфигурацию выше), но я не могу заставить syslog-ng сбрасывать вывод.
Я предполагаю, что что-то не так с тем, как я работаю с конвейерами, но я не могу этого понять. Кто-нибудь может определить проблему?
ОБНОВИТЬ: если я отправлю 1000 сообщений, некоторые из них будут пропущены, поэтому я предполагаю, что происходит некоторая буферизация. Кто-нибудь знает, какой параметр настраивать?
РЕШЕНИЕ: Похоже, Python буферизует большую часть своего ввода / вывода. Это из страниц руководства:
-u Force stdin, stdout and stderr to be totally unbuffered. On
systems where it matters, also put stdin, stdout and stderr in
binary mode. Note that there is internal buffering in xread-
lines(), readlines() and file-object iterators ("for line in
sys.stdin") which is not influenced by this option. To work
around this, you will want to use "sys.stdin.readline()" inside
a "while 1:" loop.
Поэтому в основном мне пришлось изменить программу, чтобы использовать sys.stdin.readline()
. Огромное спасибо Янне.
Я не подключал скрипты Python к syslog-ng, но в скриптах Perl мне приходится отключать буферизацию вывода, прежде чем они будут работать в реальном времени. На языке Perl это $|=1
.
Я не особо разбираюсь в Python, но я думаю, что запускаю ваш скрипт Python с -u
или настройка переменной PYTHONUNBUFFERED
может помочь.