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