Как узнать, остановит ли syslog-ng ваш прослушивающий демон?

Я написал PHP-программу, которая подключается к syslog-ng (через syslog-ng.conf), и в основном это так:

while (!feof(STDIN)) {
    $input = fgets(STDIN);
    process($input);
}
cleanup();

где process() и cleanup() определяются мной.

Проблема, с которой я столкнулся, заключается в том, что cleanup(2) никогда не вызывается, и мне нужно, чтобы он был выполнен до выхода из программы.

Я пытался поймать SIGTERM, SIGHUP и SIGPIPE, используя pcntl_signal(), и эта часть приложения, кажется, работает нормально (если я использую kill -1 в процессе PHP, мой обработчик сигналов вызывается и он запускает cleanup()), но похоже, что я я не получаю эти сообщения от syslog-ng.

Я попытался установить STDIN на неблокирующий, думая, что PHP не будет вызывать обработчики сигналов, потому что поток блокируется. Это тоже не сработало, мои обработчики сигналов не вызывались.

Как мне узнать, когда syslog-ng собирается остановить мое приложение, чтобы я мог выполнить некоторую очистку?

Спасибо, Том

ОБНОВЛЕНИЕ: я пытался перехватить все сигналы, от 1 до 31, и он по-прежнему ничего не получает, когда syslog-ng перезапускается (или уничтожается с помощью SIGTERM).


person Tom    schedule 30.10.2009    source источник
comment
С измененным тегом, это не связано с обработкой сигналов (не связано с полем обработки сигналов, связано с обработкой сигналов ОС).   -  person Danny Varod    schedule 03.11.2009
comment
Это может быть глупый вопрос, но пробовали ли вы зарегистрировать очистку как функцию выключения? us.php.net/manual/en/function.register- функция отключения.php   -  person Kevin Peno    schedule 03.11.2009
comment
Отредактировал Том. Рад, что это сработало для вас!   -  person Kevin Peno    schedule 09.11.2009


Ответы (5)


Возможно, попробуйте зарегистрировать cleanup() в качестве функции завершения работы PHP, например:

function cleanup(){}
register_shutdown_function("cleanup");

Теоретически это заставит php выполнить функцию перед выходом. Это может не работать при использовании с принудительной остановкой (например, убить), так что это (еще один) выстрел в темноте.

Я надеюсь, что вы найдете что-то, что работает, хотя. Мне тоже было бы интересно узнать о результатах.

Редактировать: я рад, что у вас все получилось!

person Kevin Peno    schedule 05.11.2009
comment
Я думаю, вы имеете в виду register_shutdown_function('cleanup'); Это классная функция, спасибо, что указали на нее! - person memnoch_proxy; 05.11.2009
comment
Я случайно минусовал тебя. Извините, ваш ответ был правильным. Попробуйте отредактировать его, чтобы я мог отменить голосование. - person Tom; 09.11.2009
comment
Пожалуйста, посмотрите на дату этого ответа. Я больше не работаю с php, и за эти годы он сильно изменился. Пожалуйста, не стесняйтесь вносить изменения в ответ, который соответствует сегодняшним требованиям. - person Kevin Peno; 07.04.2019

Это выстрел в темноте, но попробуйте переписать свой цикл следующим образом:

do {
   $input = fgets(STDIN);
   process( $input );
while ( !feof( STDIN ) ) {
cleanup();

Идея состоит в том, что когда syslog-ng закрывает стандартный вывод (при условии, что это так?), fgets попытается прочитать и фактически достичь EOF.

person Phil    schedule 04.11.2009
comment
В упомянутом случае не будет ли ваша логика лучше подходить для do{ }while() ? - person Kevin Peno; 04.11.2009
comment
Я бы, вероятно, добавил if вокруг вызова fgets, так как fgets возвращает false при сбое if( ( $input = fgets(STDIN); ) === FALSE ) break; - person Kevin Peno; 05.11.2009
comment
feof не следует использовать в do/while, так как feof нужно проверять перед чтением из файла. Пустые файлы находятся в EOF при fopen. $ touch testfile $ ls -l testfile -rw-r--r-- 1 clint staff 0 9 ноября 08:43 testfile $ php -r '$x = fopen(testfile, r); var_dump($х); $y = feof($x); var_dump($y);' ресурс(5) типа (поток) bool(false) - person SpamapS; 09.11.2009
comment
Это правда, однако в этом случае fgets также должен возвращать false. - person Kevin Peno; 09.11.2009

Внезапное завершение вашего PHP-скрипта без надлежащей очистки, вероятно, происходит из-за ошибки времени выполнения (например, из-за того, что ваш process() не готов обработать пустую строку, возвращаемую fgets(), когда она достигает EOF).

Включите ведение журнала ошибок PHP, чтобы увидеть, что происходит.

person Alexey Feldgendler    schedule 06.11.2009

Я могу придумать пару вещей, которые вы можете попробовать устранить:

1) Воспользуйтесь функцией PHP set_error_handler(). .

2) Поместите упомянутый выше код в структуру try/catch, чтобы попытаться перехватить любые исключения, которые могут быть сгенерированы.

3) Когда вы запускаете этот скрипт, убедитесь, что вы фиксируете как выходные данные, так и стандартную ошибку. Измените командную строку на что-то вроде:

/path/to/script 2>&1 >> /path/to/logfile.txt

... это поможет вам поймать ошибки.

Наконец, если это действительно тот случай, когда PHP не может перехватывать сигналы, вам придется сделать это с помощью сценария оболочки с помощью команды trap. Что-то типа:

#!/bin/sh
#
# This gets run when the script is hit with a signal
#
trap /path/to/script --cleanup
#
# Run our script
#
/path/to/script 2>&1 >> /path/to/logfile.txt

Если в скрипте есть определенные данные, которые нужны для очистки(), вам нужно будет посмотреть, как сериализовать данные и записать их на диск для чтения скриптом очистки.

Удачи!

person Douglas Muth    schedule 08.11.2009
comment
Это все еще не помогает при работе с SIGTERM, извините. - person Tom; 09.11.2009

Задумчиво ли PHP обрабатывает ваши сигналы? Попробуйте создать прототип на другом языке, которым у вас больше контроля.

person Epsilon Prime    schedule 08.11.2009