Функции и утилиты для работы с системным журналом
Под системным журналом в стандарте POSIX-2001 понимается некое средство хранения и/или отображения данных, предназначенных для изучения системным администратором. Средство это, разумеется, зависит от реализации. Это может быть обычный локальный файл (например, /var/log/messages), список рассылки, удаленный сетевой ресурс и т.д.
Для работы с системным журналом стандарт предлагает функции записи сообщений (syslog()), установки фильтра (маски журналируемых сообщений, setlogmask()) и других параметров журналирования (openlog()) и, наконец, завершения работы с системным журналом (closelog()) (см. листинг 9.1). Средства чтения системного журнала, как и все, что связано с администрированием, в стандарт POSIX-2001 не входят.
#include <syslog.h>
void syslog (int priority, const char *message, ... /* аргументы */);
int setlogmask (int maskpri); void openlog (const char *ident, int logopt, int facility);
void closelog (void);
Листинг 9.1. Описание функций для работы с системным журналом. (html, txt)
Сообщение, которое помещает в системный журнал функция syslog(), включает заголовок и тело.
В заголовок входит по крайней мере временной штамп и идентифицирующая цепочка символов.
Тело сообщения формируется из аргумента message, играющего роль формата, и следующих за ним необязательных аргументов аналогично тому, как если бы использовалась функция printf(), только допускается один дополнительный спецификатор преобразования – %m, не требующий аргумента и осуществляющий вывод текущего значения переменной errno.
Значение аргумента priority формируется как побитное ИЛИ флагов двух видов, задающих, соответственно, уровень серьезности и источник сообщения.
Уровень серьезности может принимать следующие значения.
LOG_EMERG
Катастрофическая ситуация.
LOG_ALERT
Ситуация, требующая немедленного вмешательства (например, повреждение системной базы данных).
LOG_CRIT
Опасная ситуация (например, ошибки в работе аппаратуры).
LOG_ERR
Сообщение об ошибке.
LOG_WARNING
Предупреждающее сообщение.
Под системным журналом в стандарте POSIX-2001 понимается некое средство хранения и/или отображения данных, предназначенных для изучения системным администратором. Средство это, разумеется, зависит от реализации. Это может быть обычный локальный файл (например, /var/log/messages), список рассылки, удаленный сетевой ресурс и т.д.
Для работы с системным журналом стандарт предлагает функции записи сообщений (syslog()), установки фильтра (маски журналируемых сообщений, setlogmask()) и других параметров журналирования (openlog()) и, наконец, завершения работы с системным журналом (closelog()) (см. листинг 9.1). Средства чтения системного журнала, как и все, что связано с администрированием, в стандарт POSIX-2001 не входят.
#include <syslog.h>
void syslog (int priority, const char *message, ... /* аргументы */);
int setlogmask (int maskpri); void openlog (const char *ident, int logopt, int facility);
void closelog (void);
Листинг 9.1. Описание функций для работы с системным журналом.
Сообщение, которое помещает в системный журнал функция syslog(), включает заголовок и тело.
В заголовок входит по крайней мере временной штамп и идентифицирующая цепочка символов.
Тело сообщения формируется из аргумента message, играющего роль формата, и следующих за ним необязательных аргументов аналогично тому, как если бы использовалась функция printf(), только допускается один дополнительный спецификатор преобразования – %m, не требующий аргумента и осуществляющий вывод текущего значения переменной errno.
Значение аргумента priority формируется как побитное ИЛИ флагов двух видов, задающих, соответственно, уровень серьезности и источник сообщения.
Уровень серьезности может принимать следующие значения.
LOG_EMERG
Катастрофическая ситуация.
LOG_ALERT
Ситуация, требующая немедленного вмешательства (например, повреждение системной базы данных).
LOG_CRIT
Опасная ситуация (например, ошибки в работе аппаратуры).
LOG_ERR
Сообщение об ошибке.
LOG_WARNING
Предупреждающее сообщение.
LOG_NOTICE
Ситуация, не являющаяся ошибочной, но, возможно, требующая специальных действий.
LOG_INFO
Информационное сообщение.
LOG_DEBUG
Отладочное сообщение.
Из источников сообщений стандартизован только один (естественно, являющийся подразумеваемым) – пользовательский процесс (флаг LOG_USER). Зарезервированы флаги для системных источников, имена которых говорят сами за себя (LOG_KERN, LOG_MAIL, LOG_NEWS, LOG_UUCP, LOG_DAEMON, LOG_AUTH, LOG_CRON, LOG_LPR) и для абстрактных локальных сущностей (LOG_LOCAL0 – LOG_LOCAL7).
Функция setlogmask() в качестве результата возвращает предыдущую и устанавливает новую маску журналируемых сообщений вызывающего процесса. В системный журнал будут помещаться только те сообщения, уровень серьезности которых присутствует в маске, заданной аргументом maskpri. Для формирования этого аргумента по одному уровню серьезности стандартом предусмотрен макрос LOG_MASK (pri). Для задания маски, включающей несколько уровней, нужно взять побитное ИЛИ подобных выражений.
Если значение maskpri равно нулю, текущая маска остается неизменной. Подразумевая маска является "полной", она специфицирует журналирование всех событий.
Функция openlog() устанавливает значения атрибутов журналирования вызывающего процесса, влияющие на последующие обращения к syslog(). Аргумент ident задает идентифицирующую цепочку, фигурирующую в заголовках всех сообщений. Аргумент logopt специфицирует опции журналирования. Он формируется как побитное ИЛИ следующих флагов.
LOG_PID
Записывать вместе с сообщением идентификатор процесса.
LOG_CONS
Выдавать сообщение на системную консоль, если его не удается поместить в журнал.
LOG_NDELAY
Немедленно открыть системный журнал (обычно открытие откладывается до записи первого сообщения).
LOG_ODELAY
Отложить открытие системного журнала до первого вызова syslog() (выбор между немедленным или отложенным открытием способен повлиять на распределение файловых дескрипторов).
LOG_NOWAIT
Не ждать завершения процессов, которые могли быть порождены в ходе журналирования сообщения.
Эту опцию следует использовать в процессах, которые уведомляются о завершении потомков сигналом SIGCHLD.
Аргумент facility устанавливает подразумеваемое значение для источника тех сообщений, где он (источник) не указан явным образом.
Функции openlog() и syslog() могут открывать (расходовать) файловые дескрипторы. Функция closelog() закроет их.
Вообще говоря, вызывать openlog() до syslog() и setlogmask() не обязательно.
К рассматриваемой прикладной области можно отнести служебную программу logger:
logger цепочка_символов ...
которая неким неспецифицированным образом сохраняет сообщение, содержащее заданные аргументы – цепочки символов. Предполагается, что со временем это сообщение прочитает системный администратор.
Подобная возможность полезна для выдачи диагностических сообщений неинтерактивными приложениями. Например, программа, запущенная в пакетном режиме, может уведомить системного администратора об отсутствии какого-либо файла:
logger $LOGNAME $(date) : не удалось прочитать файл report.txt
Рассмотрим пример применения функций для работы с системным журналом (см. листинг 9.2).
Листинг 9.2. Пример применения функций для работы с системным журналом. (html, txt)
Результатом работы этой программы может быть строка, показанная на листинге 9.3.
Подразумеваемая маска журналирования: ff
Листинг 9.3. Возможные результаты применения функций для работы с системным журналом. (html, txt)
LOG_NOTICE
Ситуация, не являющаяся ошибочной, но, возможно, требующая специальных действий.
LOG_INFO
Информационное сообщение.
LOG_DEBUG
Отладочное сообщение.
Из источников сообщений стандартизован только один (естественно, являющийся подразумеваемым) – пользовательский процесс (флаг LOG_USER). Зарезервированы флаги для системных источников, имена которых говорят сами за себя (LOG_KERN, LOG_MAIL, LOG_NEWS, LOG_UUCP, LOG_DAEMON, LOG_AUTH, LOG_CRON, LOG_LPR) и для абстрактных локальных сущностей (LOG_LOCAL0 – LOG_LOCAL7).
Функция setlogmask() в качестве результата возвращает предыдущую и устанавливает новую маску журналируемых сообщений вызывающего процесса. В системный журнал будут помещаться только те сообщения, уровень серьезности которых присутствует в маске, заданной аргументом maskpri. Для формирования этого аргумента по одному уровню серьезности стандартом предусмотрен макрос LOG_MASK (pri). Для задания маски, включающей несколько уровней, нужно взять побитное ИЛИ подобных выражений.
Если значение maskpri равно нулю, текущая маска остается неизменной. Подразумевая маска является "полной", она специфицирует журналирование всех событий.
Функция openlog() устанавливает значения атрибутов журналирования вызывающего процесса, влияющие на последующие обращения к syslog(). Аргумент ident задает идентифицирующую цепочку, фигурирующую в заголовках всех сообщений. Аргумент logopt специфицирует опции журналирования. Он формируется как побитное ИЛИ следующих флагов.
LOG_PID
Записывать вместе с сообщением идентификатор процесса.
LOG_CONS
Выдавать сообщение на системную консоль, если его не удается поместить в журнал.
LOG_NDELAY
Немедленно открыть системный журнал (обычно открытие откладывается до записи первого сообщения).
LOG_ODELAY
Отложить открытие системного журнала до первого вызова syslog() (выбор между немедленным или отложенным открытием способен повлиять на распределение файловых дескрипторов).
LOG_NOWAIT
Не ждать завершения процессов, которые могли быть порождены в ходе журналирования сообщения.
Эту опцию следует использовать в процессах, которые уведомляются о завершении потомков сигналом SIGCHLD.
Аргумент facility устанавливает подразумеваемое значение для источника тех сообщений, где он (источник) не указан явным образом.
Функции openlog() и syslog() могут открывать (расходовать) файловые дескрипторы. Функция closelog() закроет их.
Вообще говоря, вызывать openlog() до syslog() и setlogmask() не обязательно.
К рассматриваемой прикладной области можно отнести служебную программу logger:
logger цепочка_символов ...
которая неким неспецифицированным образом сохраняет сообщение, содержащее заданные аргументы – цепочки символов. Предполагается, что со временем это сообщение прочитает системный администратор.
Подобная возможность полезна для выдачи диагностических сообщений неинтерактивными приложениями. Например, программа, запущенная в пакетном режиме, может уведомить системного администратора об отсутствии какого-либо файла:
logger $LOGNAME $(date) : не удалось прочитать файл report.txt
Рассмотрим пример применения функций для работы с системным журналом (см. листинг 9.2).
/* * * * * * * * * * * * * * * * * */ /* Пример использования функций */ /* для работы с системным журналом */ /* * * * * * * * * * * * * * * * * */
#include <stdio.h> #include <syslog.h>
int main (void) { int logmask; /* Прежняя маска журналирования */ /* Будем включать в журналируемые сообщения */ /* идентификатор процесса и выдавать их при */ /* возникновении проблем на системную консоль */ openlog ("Intuit syslog test", LOG_PID | LOG_CONS, LOG_USER);
/* Пренебрежем предупреждениями и менее серьезными сообщениями */ logmask = setlogmask (LOG_MASK (LOG_EMERG) | LOG_MASK (LOG_ALERT) | LOG_MASK (LOG_CRIT) | LOG_MASK (LOG_ERR));
printf ("Подразумеваемая маска журналирования: %x\n", logmask);
/* Поместим сообщение в журнал */ syslog (LOG_ALERT | LOG_USER, "Как читать системный журнал?");
/* Восстановим прежнюю маску журналирования */ (void) setlogmask (logmask);
closelog ();
return 0; }
Листинг 9.2. Пример применения функций для работы с системным журналом.
Результатом работы этой программы может быть строка, показанная на листинге 9.3.
Подразумеваемая маска журналирования: ff
Листинг 9.3. Возможные результаты применения функций для работы с системным журналом.
Привлечь внимание системного администратора к возникшим проблемам можно не только помещая сообщения в системный журнал, но и выдавая их в стандартный протокол и/или на системную консоль. Для этого служит функция fmtmsg() (см. листинг 9.4).
#include <fmtmsg.h> int fmtmsg (long classification, const char *label, int severity, const char *text, const char *action, const char *tag);
Листинг 9.4. Описание функции fmtmsg().
Функция fmtmsg() конструирует отформатированное сообщение, включая в него все аргументы, кроме первого.
Аргумент classification определяет источник и способ отображения сообщения. Он формируется как сумма констант, по одной из каждого класса. Классификация верхнего уровня определяет источник проблемы. В этот класс входят константы MM_HARD (аппаратура), MM_SOFT (программное обеспечение), MM_FIRM (программно-аппаратные средства). Сообщения, порожденные программным обеспечением, могут дополнительно классифицироваться константами MM_APPL (приложение), MM_UTIL (служебная программа), MM_OPSYS (операционная система). Проблемы классифицируются также по признаку нейтрализуемости – соответственно, MM_RECOVER и MM_NRECOV.
Если сообщение предполагается направить в стандартный протокол, к значению аргумента classification следует прибавить константу MM_PRINT; вывод на системную консоль задает константа MM_CONSOLE. Возможно одновременное указание обеих констант.
Константа MM_NULLMC означает отсутствие классификационного компонента (естественно, ее значение равно нулю).
Аргумент label специфицирует первый из пяти компонентов выдаваемого сообщения. Он, как и classification, определяет источник сообщения, но делает это по-своему. Указуемая цепочка символов должна состоять из двух полей, разделенных двоеточием.
Первое поле состоит не более чем из десяти байт, второе – из четырнадцати.
Аргумент severity характеризует серьезность проблемы. Стандартом POSIX-2001 предусмотрены следующие уровни серьезности.
MM_HALT
В приложении встретилась серьезная ошибка, его работа остановлена. В выводимую цепочку вставляется текст "HALT".
MM_ERROR
В работе приложения обнаружена ошибка. В выводимую цепочку вставляется текст "ERROR".
MM_WARNING
При работе приложения возникла необычная ситуация, возможно, являющаяся ошибочной и требующая внимания. В выводимую цепочку вставляется текст "WARNING".
MM_INFO
Информация о ситуации, не являющейся ошибочной. В выводимую цепочку вставляется текст "INFO".
MM_NOSEV
Данная константа обозначает отсутствие у сообщения уровня серьезности.
Аргумент text в свободной форме описывает ситуацию, приведшую к генерации сообщения.
Аргумент action также в свободной форме описывает первый шаг по нейтрализации ошибки. Перед цепочкой, на которую указывает action, в сообщение вставляется префикс "TO FIX:".
Аргумент tag служит ссылкой на документацию по выявленной проблеме.
На работу функции fmtmsg() влияет переменная окружения MSGVERB, которая определяет, какие из пяти возможных компонентов сообщения будут выданы в стандартный протокол (на консоль всегда выдается полное сообщение). Значение этой переменной в общем случае состоит из пяти ключевых слов – label, severity, text, action, tag – разделенных двоеточиями. Если какие-то ключевые слова отсутствуют, соответствующие компоненты сообщения в стандартный протокол выданы не будут. Если переменная MSGVERB отсутствует в окружении, имеет пустое или некорректное значение, сообщение выдается целиком.
Возможные результаты функции fmtmsg() устроены необычным образом. Константа MM_OK обозначает полный успех, MM_NOTOK – полную неудачу, MM_NOMSG – невозможность выдать сообщение в стандартный протокол, MM_NOCON – невозможность вывода на консоль.
Приведем не очень серьезный пример применения функции fmtmsg() (см.
листинг 9.5).
#include <stdio.h> #include <fmtmsg.h>
int main (void) { if (fmtmsg (MM_SOFT + MM_OPSYS + MM_RECOVER + MM_PRINT + MM_CONSOLE, "POSIX:fmtmsg", MM_INFO, "Отсутствует функция fmtmsg()", "Установите функцию fmtmsg() или не пользуйтесь ею\n", "См. functions/fmtmsg.html") != MM_OK) { perror ("FMTMSG"); return (1); }
return 0; }
Листинг 9.5. Пример использования функции fmtmsg().
В результате выполнения приведенной программы в стандартный протокол и на системную консоль будет выдано следующее сообщение (см. листинг 9.6).
POSIX:fmtmsg: INFO: Отсутствует функция fmtmsg() TO FIX: Установите функцию fmtmsg() или не пользуйтесь ею См. functions/fmtmsg.html
Листинг 9.6. Возможные результаты выполнения программы, использующей функцию fmtmsg().
Читателю предлагается самостоятельно поэкспериментировать с этой программой, варьируя значение переменной окружения MSGVERB.