12.5. Повторное открытие журнальных файлов

12.5. Повторное открытие журнальных файлов

Большинство системных демонов ведут журнальные файлы, записывая в них все, что они делают. Поскольку многие системы Unix месяцами работают без остановки, эти журнальные файлы могут стать достаточно большими. Простое периодическое удаление (или переименование) журнальных файлов — не самое хорошее решение, потому что демоны будут продолжать записывать в эти файлы, несмотря на их недоступность, а необходимость останавливать и запускать каждый демон для очистки журнальных файлов приводит к недоступности системы (хоть и на незначительное время). Общий способ для демонов справиться с упомянутой ситуацией — перехватывать SIGHUP и повторно открывать журнальные файлы. Это позволяет организовать ротацию журналов (периодическое открытие новых журнальных файлов при сохранении старых), используя простой сценарий вроде приведенного ниже.

dd /var/log

mv messages messages.old

killall -HUP syslogd

Logrotate (ftp://ftp.redhat.com/pub/redhat/code/logrotate/) — одна из программ, которая использует преимущество такого метода для выполнения безопасной ротации журналов.

Включение этой возможности у большинства демонов достаточно просто. Одним их наиболее легких подходов является использование глобальной переменной, которая индицирует необходимость повторного открытия журналов.

Затем обработчик сигнала SIGHUP в своем вызове устанавливает эту переменную, и главная часть программы проверяет эту переменную насколько можно часто. Ниже приведен пример соответствующей программы.

 1: /*sighup.c*/

 2:

 3: #include <errno.h>

 4: #include <signal.h>

 5: #include <stdio.h>

 6: #include <string.h>

 7: #include <unistd.h>

 8:

 9: volatile int reopenLog = 0; /* volatile - поскольку модифицируется

10:                                обработчиком сигнала */

11:

12: /* записать строку в журнал */

13: void logstring(int logfd, char *str) {

14:  write(logfd, str, strlen(str));

15: }

16:

17: /* когда приходит SIGHUP, сделать запись об этом и продолжить */

18: void hupHandler(int signum) {

19:  reopenLog = 1;

20: }

21:

22: int main() {

23:  int done = 0;

24:  struct sigaction sa;

25:  int rc;

26:  int logfd;

27:

28:  logfd = STDOUT_FILENO;

29:

30:  /* Установить обработчик сигнала SIGHUP. Использовать memset() для

31:     инициализации структуры sigaction чтобы обеспечить очистку

32:     всего. */

33:  memset(&sa, 0, sizeof(sa));

34:  sa.sa_handler = hupHandler;

35:

36:  if (sigaction(SIGHUP, &sa, NULL)) perror("sigaction");

37:

38:  /* Записывать сообщение в журнал каждые две секунды, и

39:     повторно открывать журнальный файл по требованию SIGHUP */

40:  while (!done) {

41:   /*sleep() возвращает не ноль, если не спит достаточно долго*/

42:   rc = sleep(2);

43:   if (rc) {

44:    if (reopenLog) {

45:     logstring(logfd,

46:      "* повторное открытие журналов по запросу SIGHUP ");

47:     reopenLog = 0;

48:    } else {

49:     logstring(logfd,

50:      "* sleep прервано неизвестным сигналом "

51:      "--dying ");

52:     done=1;

53:    }

54:   } else {

55:    logstring(logfd, "Периодическое сообщение ");

56:   }

57:  }

58:

59:  return 0;

60: }

Чтобы протестировать эту программу, запустите ее в одном окне xterm и отправьте сигнал SIGHUP из другого. Для каждого сигнала SIGHUP, который принимает программа, она печатает сообщение, когда выполняет нормальную ротацию своих журналов. Помните, что если сигнал поступает в тот момент, когда работает другой экземпляр обработчика, доставляется только один экземпляр сигнала, поэтому не отправляйте их слишком часто.