Назад | Перейти на главную страницу

syslog-ng не промывает канал внешней программе

Я написал сценарий 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 может помочь.