Linux: rsyslogd, MySQL (ommysql) и фильтры (RainerScript и Property-Based).

Автор: | 04/04/2014
 

linux_logoТут мы рассмотрим примеры настройки rsyslog и его настройку для сбора логов с нескольких хостов. Далее – эти логи будут выводится в веб-интерфейсе с помощью утилиты LogAnalizer.

Для начала – определим, чем именно является rsyslog:

rsyslogd – reliable and extended syslogd

Т.е. по сути rsyslog = syslog. Мало того, он даже использует те же конфигурационные файлы, которые использует syslog:

# vim /usr/include/sys/syslog.h
...
#ifdef SYSLOG_NAMES
CODE facilitynames[] =
{
{ "auth", LOG_AUTH },
{ "authpriv", LOG_AUTHPRIV },
{ "cron", LOG_CRON },
{ "daemon", LOG_DAEMON },
{ "ftp", LOG_FTP },
{ "kern", LOG_KERN },
{ "lpr", LOG_LPR },
{ "mail", LOG_MAIL },
{ "mark", INTERNAL_MARK },          /* INTERNAL */
{ "news", LOG_NEWS },
{ "security", LOG_AUTH },           /* DEPRECATED */
{ "syslog", LOG_SYSLOG },
{ "user", LOG_USER },
{ "uucp", LOG_UUCP },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
{ "local2", LOG_LOCAL2 },
{ "local3", LOG_LOCAL3 },
{ "local4", LOG_LOCAL4 },
{ "local5", LOG_LOCAL5 },
{ "local6", LOG_LOCAL6 },
{ "local7", LOG_LOCAL7 },
{ NULL, -1 }
};
#endif
...

В ОС FreeBSD по-умолчанию исползуется syslogd:

# ps aux | grep syslog
root          898   0.0  0.1   9612    664  ??  Ss   31Jan14     1:07.60 /usr/sbin/syslogd -s

Тогда как в CentOSrsyslogd:

# ps aux | grep syslog
root     22962  0.0  0.0 309024  3600 ?        Ssl  Apr04   1:04 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5

Важна и версия, в данном случае рассматривается:

# rsyslogd -v
rsyslogd 5.8.10, compiled with:
FEATURE_REGEXP:                         Yes
FEATURE_LARGEFILE:                      No
GSSAPI Kerberos 5 support:              Yes
FEATURE_DEBUG (debug build, slow code): No
32bit Atomic operations supported:      Yes
64bit Atomic operations supported:      Yes
Runtime Instrumentation (slow code):    No

И операционная система:

# cat /etc/redhat-release
CentOS release 6.4 (Final)

Обратите внимание – что rsyslogd использует PID-файл syslogd.pid.

Основной конифгурационный файл демона rsyslogd - /etc/rsyslog.conf, синтаксис которого весьма схож с файлом /etc/syslog.conf:

rsyslog.conf:

...
# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
...

syslog.conf:

...
auth.info;authpriv.info                         /var/log/auth.log
...

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

Наша задача – настроить пересылку логов с нескольких хостов – на один, который будет играть роль логгер-сервера, и записывать их в базу данных MySQL для последующего вывода наиболее важных (т.е. тех, у которых уровень “приоритет” (severity) будет WARNING или выше) в веб-интерфейсе LogAnalizer.

Для того, что бы это корректно настроить – давайте посмотрим на общие источники данных для логгирования и их уровни (или устройства)  (имя – числовой номер – описание):

kern - 0 –  сообщения ядра;
user - 1 –  сообщения пользовательских программ;
mail - 2 –  сообщения от почтовой системы;
daemon - 3 – сообщения от тех системных демонов, которые в отличие от FTP или LPR не имеют выделенных специально для них категорий;
auth - 4 – все что связано с авторизацией пользователей, вроде login и su (безопасность/права доступа);
syslog - 5 – система протоколирования может протоколировать сообщения от самой себя;
lpr - 6 – сообщения от системы печати;
news - 7 – сообщения от сервера новостей. (в настоящее время не используется);
uucp - 8 – сообщения от UNIX-to-UNIX Copy Protocol. Это часть истории UNIX и вероятнее всего она вам никогда не понадобится (хотя до сих пор определенная часть почтовых сообщений доставляется через UUCP);
cron - 9 – сообщения от системного планировщика;
authpriv - 10 – то же самое, что и auth, однако сообщения этой категории записываются в файл, который могут читать лишь некоторые пользователи (возможно, эта категория выделена потому, что принадлежащие ей сообщения могут содержать открытые пароли пользователей, которые не должны попадать на глаза посторонним людям, и следовательно файлы протоколов должны иметь соответствующие права доступа);
ftp - 11 – при помощи этой категории вы сможете сконфигурировать ваш FTP сервер, что бы он записывал свои действия;
NTP - 12 – сообщения сервера времени;
(?) - 13log audit (?);
(?) - 14 log alert (?);
clock daemon - 15 – сообщения демона времени;
local0 - local7 (local0 = 16 => local7 = 23) – зарезервированные категории для использования администратором системы. Категория local7 обычно используется для сообщений, генерируемых на этапе загрузки системы;
mark - 1 – присваивается отдельным сообщениям, формируемым самим демоном syslogd;

Далее – сообщения делятся по уровням их важности, т.е. – по “приоритету” (имя – числовой номер – описание):

emerg - 0 – (старое название PANIC) чрезвычайная ситуация, система неработоспособна;
alert - 1 – тревога;
crit - 2 – критическая ошибка (критическое состояние);
err (старое название ERROR) - 3 – сообщение об ошибке;
warning (старое название WARN) - 4 – предупреждение;
notice - 5 – информация о каком-то нормальном, но важном событии;
info - 6 – информационное сообщение;
debug - 7 – сообщения, формируемые в процессе отладки.

Перейдём непосредственно к настройке rsyslogd на “клиентских” серверах, т.е. – машинах, которые будут отсылать логи на “логгер-сервер”, который будет их хранить в базе MySQL.

По-умолчанию конфигурация rsyslog в ОС CentOS 6.4 выглядите так:

# cat /etc/rsyslog.conf | egrep -v '^[[:space:]]*$|#'
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$IncludeConfig /etc/rsyslog.d/*.conf
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
authpriv.*                                              /var/log/secure
mail.*                                                  -/var/log/maillog
cron.*                                                  /var/log/cron
*.emerg                                                 *
uucp,news.crit                                          /var/log/spooler
local7.*                                                /var/log/boot.log
local4.*                                                /var/log/ldap.log

Нам необходимо:

а) добавить логгирование kern всех сообщений, кроме сообщений уровня debug,  в локальный файл;
б) добавить пересылку kern сообщений с уровнем важности WARN или выше на сервер логгирования;
в) включить логгирование самого демона логгирования.

Включаем логгирование kern. Для этого – в файле достаточно просто раскомментировать строку:

#kern.*                                                 /dev/console

И изменить вывод данных с /dev/console на /var/log/kern.log.

Создаём файл:

# touch /var/log/kern.log

Редактируем файл /etc/rsyslog.conf:

# записываем всё, кроме "ниже" уровня warning в локальный файл
kern.*;kern.!warning                                      /var/log/kern.log

# хотя, конечно, лучше писать всё - тогда просто создаём строку:
kern.*                                                                /var/log/kern.log

# всё, что выше warning - пересылаем на хост logger.host.com, используйте @@ для TCP и @ - для UDP
kern.warning                                                   @logger.host.com

# записываем всё от самого rsyslog в файл
syslog.*                                                            /var/log/syslog.log

ВАЖНО: для записи сообщений от kern – убедитесь, что в конфигурации раскомментирована строка модуля:

$ModLoad imklog

Проверим файл конфигурации rsyslogd:

# rsyslogd -N1
rsyslogd: version 5.8.10, config validation run (level 1), master config /etc/rsyslog.conf
rsyslogd: WARNING: rsyslogd is running in compatibility mode. Automatically generated config directives may interfer with your rsyslog.conf settings. We suggest upgrading your config and adding -c5 as the first rsyslogd option.
rsyslogd: Warning: backward compatibility layer added to following directive to rsyslog.conf: ModLoad immark
rsyslogd: Warning: backward compatibility layer added to following directive to rsyslog.conf: MarkMessagePeriod 1200
rsyslogd: Warning: backward compatibility layer added to following directive to rsyslog.conf: ModLoad imuxsock
rsyslogd: End of config validation run. Bye.

Предупреждения – хорошо. В случае реальной опечатки – сообщение будет выглядеть так:

# rsyslogd -N1
rsyslogd: version 5.8.10, config validation run (level 1), master config /etc/rsyslog.conf
rsyslogd: WARNING: rsyslogd is running in compatibility mode. Automatically generated config directives may interfer with your rsyslog.conf settings. We suggest upgrading your config and adding -c5 as the first rsyslogd option.
rsyslogd: unknown priority name "" [try http://www.rsyslog.com/e/3000 ]
rsyslogd: the last error occured in /etc/rsyslog.conf, line 41:"aaa"
rsyslogd: warning: selector line without actions will be discarded
rsyslogd: CONFIG ERROR: could not interpret master config file '/etc/rsyslog.conf'. [try http://www.rsyslog.com/e/2124 ]

Если ERROR нет – перезапускаем демон:

# service rsyslog restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]

И смотрим созданный нами файл лога самого rsyslogd:

# tail -f /var/log/syslog.log
Apr  7 15:53:30 senderhostname rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="15278" x-info="http://www.rsyslog.com"] start

Переходим к настройке пересылки логов на удалённй хост.

На “сервере-логгере” редактируем rsyslog.conf, находим и раскомментируем строки:

$ModLoad imudp
$UDPServerRun 514

И строки:

$ModLoad imtcp
$InputTCPServerRun 514

Если хотим, что бы данные передавались по TCP, а не UDP.

Проверим как всё работает.

Т.к. через утилиту logger нельзя передать сообщение “от ядра” – для проверки в rsyslog.conf на хосте-отправителе добавим такие строки:

mail.*;mail.!crit                                      /var/log/maillog
mail.warning                                            @logger.host.com

Т.е. – все сообщения уровнем от facility mail “ниже” crit – мы пишем в локальный файл /var/log/maillog, а “выше” уровня warning – передаём на хост logger.host.com по протоколу UDP.

На нём же с помощью утилиты logger создадим такое сообщение:

# logger -p mail.notice -t TEST "Test warning for remote host MAIL.NOTICE"

Проверяем локальный файл:

# tail -n 1 /var/log/maillog
Apr  7 19:29:55 senderhostname TEST: Test warning for remote host MAIL.NOTICE

А теперь – отправим сообщение с утровнем crit:

# logger -p mail.crit-t TEST "Test warning for remote host MAIL.CRIT"

Смотрим локальный файл на хосте-отправителе:

# tail -n 1 /var/log/maillog
Apr  7 19:29:55 senderhostname TEST: Test warning for remote host MAIL.NOTICE

И на сервере-логгере:

# tail -n 1 /var/log/maillog
Apr  7 19:31:36 senderhostname TEST: Test warning for remote host MAIL.CRIT

Проблема, однако, в том – что в таком случае все данные будут писаться в общий файл /var/log/maillog (или другой, в зависимости от facility).

Что бы этого избежать – rsyslogd имеет набор различных фильтров, которые позволяют перенаправлять данные в зависимости от заданных параметров.

Фильтры в rsyslog

Фильтры в rsyslog бывают трёх типов:

1. RainerScript-based filters
2. “Traditional” severity and facility based selectors
3. Property-based filters

Подробнее о них можно почитать тут>>> или тут>>>.

Нам необходимо создать простое правило, которое будет логи получаемые от определённого хоста направлять в базу данных.

Проверим, что на сервере-логгере раскомментирована строка:

$IncludeConfig /etc/rsyslog.d/*.conf

В каталоге /etc/rsyslog.d/ создадим файл, например – /etc/rsyslog.d/sender.conf с таким содержимым:

# cat /etc/rsyslog.d/sender.conf
$ModLoad ommysql
:fromhost-ip, isequal, "10.***.***.35" :ommysql:localhost,Syslog,rsyslog,megaPassword

Проверяем корректность:

# rsyslogd -N1

И переазпускаем rsyslogd:

# service rsyslog restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]

Тут подразумевается, что rsyslog-mysql установлен и база для него уже создана. Если нет – детали установки описаны в статье Сбор и просмотр логов Syslog в MySQL с помощью LogAnalyzer.

Теперь на сервере-отправителе выполняем:

# logger -p mail.crit -t TEST "Test warning for remote host MAIL.CRIT PropertyBased filter"

И проверяем последнюю запись в базе данных сервера-логгера:

mysql> select ID,Message from SystemEvents order by ID desc limit 1;
+--------+--------------------------------------------------------------+
| ID     | Message                                                      |
+--------+--------------------------------------------------------------+
| 524051 |  Test warning for remote host MAIL.CRIT PropertyBased filter |
+--------+--------------------------------------------------------------+
1 row in set (0.00 sec)

Работает, отлично. Теперь все сообщения с facility mail и уровнем важности warning и выше будут отправляться на сервер logger.host.com и на нём – записываться в базу данных, которую мы указали после модуля ommysql - localhost,Syslog,rsyslog,megaPassword.

В этом примере мы использовали Property-Based Filters. Полный список propname можно найти тут>>> (на удивление – найти его оказалось не такой простой задачей, как думалось поначалу…).

Поддерживаются следующие операции сравнения:

contains — проверка, содержит ли свойство указанное значение;
isequal — сравнивает строку value с содержимым свойства, они должны быть полностью одинаковы;
startswith — проверяет что свойство начинается со строки value;
regex — сравнивает свойство с заданным регулярным выражением.

Давайте попробуем что-то изменить в нашем фильтре.Например – мы хотим изменить фильтр так, что бы записывать только сообщения от facility = mail. Тогда – используем propname syslogfacility а имя устройства – укажем в числовом виде, для mail это будет 2:

# cat /etc/rsyslog.d/sender.conf
$ModLoad ommysql

:syslogfacility, isequal, "2" :ommysql:localhost,Syslog,rsyslog,megaPassword

На удалённом сервере выполняем:

# logger -p mail.crit -t TEST "Test warning for remote host MAIL.CRIT PropertyBased filter with syslogfacility=mail"

И на логгере – проверяем:

+--------+---------------------------------------------------------------------------------------+
| ID     | Message                                                                               |
+--------+---------------------------------------------------------------------------------------+
| 524053 |  Test warning for remote host MAIL.CRIT PropertyBased filter with syslogfacility=mail |
+--------+---------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Другой пример – с фильтрами RainerScript.

Возьмём тот же файл, и изменим его так:

if $fromhost-ip == '10.***.***.35' then /var/log/sender.log

Обратите внимание, что тут 'value' указывается в одинарных кавычках, а не двойных, как в Property-Based Filter.

Не забываем проверять корректность файла конфигурации:

# rsyslogd -N1

Перезапускаем rsyslogd, затем на удалённом сервере выполняем:

# logger -p mail.crit -t TEST "Test warning for remote host MAIL.CRIT RainerScript filter"

На сервере-логгере смотрим файл:

# tail -n 1 /var/log/sender.log
Apr  9 12:30:48 senderhostname TEST: Test warning for remote host MAIL.CRIT RainerScript filter

Или – вариант с использованием модуля MySQL:

if $fromhost == 'senderhostname' then :ommysql:localhost,Syslog,rsyslog,megaPassword

Проверяем:

mysql> select ID,ReceivedAt,Message from SystemEvents order by ID desc limit 1;
+--------+---------------------+----------------------------------------------------------------------+
| ID     | ReceivedAt          | Message                                                              |
+--------+---------------------+----------------------------------------------------------------------+
| 524055 | 2014-04-09 14:15:24 |  Test warning for remote host MAIL.CRIT RainerScript filter to MySQL |
+--------+---------------------+----------------------------------------------------------------------+
1 row in set (0.00 sec)

Другой пример:

if $msg contains 'RainerScript' then :ommysql:localhost,Syslog,rsyslog,megaPassword

Запускаем:

# logger -p mail.crit -t TEST "Test warning for remote host MAIL.CRIT RainerScript filter to MySQL - msg"

Проверяем:

mysql> select ID,ReceivedAt,Message from SystemEvents order by ID desc limit 1;
+--------+---------------------+----------------------------------------------------------------------------+
| ID     | ReceivedAt          | Message                                                                    |
+--------+---------------------+----------------------------------------------------------------------------+
| 524060 | 2014-04-09 14:34:04 |  Test warning for remote host MAIL.CRIT RainerScript filter to MySQL - msg |
+--------+---------------------+----------------------------------------------------------------------------+
1 row in set (0.00 sec)

Достоинство RainerScript в том, что в нём можно использовать селекторы типа “if", "if not", "and", "and not" или "or".

Например – использование селектора “and“:

if $msg contains 'RainerScript' and $fromhost == 'senderhostname' then :ommysql:localhost,Syslog,rsyslog,megaPassword

Запускаем:

# logger -p mail.crit -t TEST "Test warning for remote host MAIL.CRIT RainerScript filter to MySQL - msg and fromhost"

Проверяем:

mysql> select ID,ReceivedAt,Message from SystemEvents order by ID desc limit 1;
+--------+---------------------+-----------------------------------------------------------------------------------------+
| ID     | ReceivedAt          | Message                                                                                 |
+--------+---------------------+-----------------------------------------------------------------------------------------+
| 524062 | 2014-04-09 14:36:58 |  Test warning for remote host MAIL.CRIT RainerScript filter to MySQL - msg and fromhost |
+--------+---------------------+-----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Увы – в Rsyslog v5 судя по всему ещё нет поддержки конструкции else, но можно обойтись и без неё, например:

if ($fromhost == 'senderhostname' or $msg contains 'RainerScript') and not ($msg contains 'Test') then /var/log/1test.log
if ($fromhost == 'senderhostname' or $msg contains 'RainerScript') and ($msg contains 'Test') then /var/log/2test.log

Тут- сообщения, от хоста senderhostname или содержащие в тексте слово RainerScript и НЕ содержащие в тексте слово Test попадут в файл /var/log/1test.log.

Сообщения от хоста senderhostname или содержащие в тексте слово RainerScript и содержащие в тексте слово Test попадут в файл /var/log/2test.log.

Проверяем:

# logger -p mail.crit -t TEST "This message to 1test.log Test"
# logger -p mail.crit -t TEST "This message to 1test.log"
# tail -n1 /var/log/1test.log
Apr  9 17:55:12 senderhostname TEST: This message to 1test.log
# tail -n1 /var/log/2test.log
Apr  9 17:54:57 senderhostname TEST: This message to 1test.log Test

И ещё один пример:

# cat /etc/rsyslog.d/sshd.conf
if $programname == 'sshd' and $msg contains 'Failed' then @logger

Ещё хотелось бы записать использование шаблонов и создание новой базы для rsyslog-mysql и LogAnalizer – но, видимо, это уже будет отдельная статья.

Ссылки по теме

http://wiki.rsyslog.com
http://www.rsyslog.com // примечание – на оф. сайте Rsyslog документация для последней версии, в данном случае – 8, синтаксис может отличаться
http://www.rsyslog.com
http://www.rsyslog.com
http://www.rsyslog.com
http://www.rsyslog.com
http://www.rsyslog.com
http://www.k-max.name
http://www.k-max.name
https://access.redhat.com
http://www.maths.cam.ac.uk