среда, 10 октября 2012 г.

В сотый раз rsyslog...

    В стопиццотый раз хотелось бы затронуть тему централизованного ведения логов.
Рано или поздно, любой системный администратор,  задается вопросом "Как бы сделать так что бы еще больше ничего не делать...?" И тут уже начинается и полет фантазии, и автоматизация, и изучение языков программирования и так далее. Прилагаются титанические усилия в кратчайшие сроки, что в переводе на "работо-часы" означает что проделанной работы хватило бы на целый квартал, но нет же !!! Нужно обязательно поделить работу на 0 - иначе это будет не True....
    Размышляя в данном направлении можно прийти к мысли что просматривать логи на серверах (и прочих железяках) вещь конечно нужная, и часто много легче предупредить беду обнаружив, что на сервере начал сыпаться винт, чем придя на работу получать суть накала быстро соображая как теперь восстановить работоспособность груды железа и понять причины выхода его из строя. Но здесь мы натыкаемся на несколько неприятных моментов, потому что нужно каждый день тратить какое-то время что бы "зайти" на все важные сервера,
просмотреть логи, проанализировать ошибки, и так далее. Занятие монотонное и утомительное, и как правило на него ложат уже через неделю. Да, можно настроить сервер логов, на котором собирать логи со всех устройств. Но опять же, нужно кому то сидеть и смотреть эти логи - что в разрезе айтишника не имеет ничего общего. Исходя из таких вот негативных мыслей, Мы попытаемся сегодня настроить свой сервер централизованного хранения логов с блекджеком и шлюхами. И так подытожим, мы хотим что бы:

1. Сервер собирал логи на себя со всевозможных устройств (включая никрасофт)
2. Был бесплатен
3. Был гибок в настройке
4. Фильтровал сообщения
5. Мог отправлять админу почту с указанием источника и ошибки
6. Хранил логи в БД (мало ли, придет начальство а ты такой "ОППА" и хмуря брови смотришь лог....) --- ну вообще много для чего нужно на самом деле...

Итого, порывшись в тырнете и опробовав несколько вариантов сделал такие выводы:
Стандартный syslog - хорошо что везде есть, плохо что ограничен во всем.
syslog-ng (типа нью генерайшен) - уже много луче, но есть грабли с фильтрами и не поддерживает отправку писем из коробки.
Rsyslog - жуткий демон, может все что нужно, все в комплекте, но дурацкий синтаксис конфига и, к тому же, отличающийся в разных версиях !!! Эврика ! Это же то что нам нужно, и мозги размять и дело сделать и медаль на грудь себе потом повесить!!!
Итого, берем какое-то железяко или виртуалку, ставим на нее любую любимую вами *nix систему и принимаемся за настройку. Моей любимой системой в данный час оказалась 
FreeBSD Logs 9.0-RELEASE-p4 (Logs - имя машинки)
Итак , предположим что у нас чистая, только что установленная система
установим необходимое из портов (на линуксе ставим своим методом):
cd /usr/ports/sysutils/rsyslog6 && make install clean 
cd /usr/ports/sysutils/rsyslog6-mysql && make install clean
(обратите внимание я взял 6 версию, и мой конфиг на 5 работать не будет, на счет 7 не знаю)
cd /usr/ports/databases/mysql55-server && make install clean
cd /usr/ports/databases/mysql55-client && make install clean
Для начала вроде как хватит, теперь лезем в rc.conf  и добавляем правила:
mysql_enable="YES"
syslogd_enable="NO"
rsyslogd_enable="YES"
rsyslogd_pidfile="/var/run/syslog.pid"
rsyslogd_flags="-c4"
Далее нам необходимо настроить rsyslog.conf - в мануале написанно что он у вас появится там-то и там-то, но у меня фокус не сработал и потому создаем его сами:
# touch /usr/local/etc/rsyslog.conf
Ниже я приведу свой конфиг, и постараюсь по максимуму его прокомментировать. В конфиге я   старался затронуть основные моменты нужные нам для работы, хотя возможности самого  rsyslog выходят далеко за рамки этой статьи и натворить в нем реально можно что угодно.
Некоторые моменты в конфиге вам будут не понятны, но по мере прочтения все станет на свои места...
Итак:
# cat /usr/local/etc/rsyslog.conf

#Модули которые нам нужны для работы необходимо явно указывать
#Добавим логирование локалхоста
$ModLoad imuxsock # provides support for local system logging
$ModLoad imklog   # provides kernel logging support (previously done by rklogd)
# Модуль отвечающий за прослушку по  UDP порту
$ModLoad imudp
# Порт сервера на котором слушать логгеров
$UDPServerRun 514
# Если не хотим что бы ломилось все в подряд, ограничим тех кто может ложить логи
$AllowedSender UDP, 127.0.0.1, 192.168.0.9, 192.168.0.141
#Поддержка БД MySQL (вобще ест поддержка и постгреса и т.д.)
$ModLoad ommysql#Настройки для отправки почты
$ModLoad ommail#smtp сервер
$ActionMailSMTPServer my.mail.server
#От кого будем получать логи
$ActionMailFrom report@my.mail.server
#Кому отправлять логи
$ActionMailTo report@my.mail.server
#Интересная штука темплейты. По сути что-то типа переменных но явно указанных.
#Напишем парочку темплейтов. с темой письма и содержимым для двух вариантов
#1 - для отправки сообщений с ошибками и 2 для отправки сообщений о ннедоступности хоста
#1
$template mailSubject,"ServerLog: Warning on %hostname%"
$template mailBody,"SERVERLOG\r\nError on  %hostname%\r\nError  =  '%msg%'"
#2
$template mailBodyPing,"SERVERLOG\r\nThe %hostname% is DOWN"
#Нужно обьявить тему для почты.
$ActionMailSubject mailSubject
#Настройки вида отображения логов оставим по умолчанию, хотя вы можете сделать свои
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
#Ну тут все понятно. Укажем кто хозяин логофайлов на сервере.
$FileOwner root
$FileGroup wheel
$FileCreateMode 0640
#Далее список правил для локалхоста, особо обьяснять не буду так как ето стандартные
#значения из сислога
# Log all kernel messages to the console.
kern.*                                                 /dev/console
# Log anything (except mail) of level info or higher.
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
# The authpriv file has restricted access.
authpriv.*                                              /var/log/security# Log all the mail messages in one place.
mail.*                                                  -/var/log/maillog
# Log cron stuff
cron.*                                                  /var/log/cron# Everybody gets emergency messages
*.emerg                                                 *
# Save news errors of level crit and higher in a special file.
uucp,news.crit                                          /var/log/spooler
# Save boot messages also to boot.log
local7.*                                                /var/log/boot.log
#А вот теперь начинается магия...
#Создадим фильтры.
#Создадим фильтр, который следит за сообщениями в локальном сислоге, и
# если сообщение имеет в себе слово Alarm  то выполняем действие, а именно
# отправляем ошибку в базу данных и отсылаем админу письмо!
# синтаксис почты понятен. А для базы данных (щас создадим) он такой
:ommysql:servernamr,DB_name,username,password
# например у нас сервер локальный, имя базы = LogDB, пользователь = user, пароль =123
# тогда получим :ommysql:localhost,LogDB,user,123
#(Фильтрация по слову в сообщении $msg)
if $msg contains 'Alarm' then {
:ommail:;mailBodyPing :ommysql:localhost,LogDB,user,123
}
#Теперь добавим фильтр который например будет писать в БД все логи
#которые пришли к нам с айпишнека 10.0.0.10 (ну например это точка доступа)
#Filter to 10.0.0.10
if $hostname-ip == '10.0.0.10'  then :ommysql:localhost,LogDB,user,123
# Но возможно вам не нужен весь хлам, тогда добавим условие на вторую точку доступа # с которой будем писать только логи с меткой ERROR
if ($hostname-ip == '10.0.0.10' and $msg contains 'ERROR') then ommysql:localhost,LogDB,user,123
#И пожалуй самый интересный фильр, ето парсить логи от нужного нам виндовго сервера,
# писать их а базу данных, но если сообщение сожерит ошибку - отправлять его на почту.
# По умолчанию у rsyslog есть замечательные фильтры. Воспользуемся ими
# (Очень рекомендую при создании фильтров юзать сей чудо мануал ТЫЦ-ТЫЦ)
#Зафильтруем по имени ПК и типу ошибки, что согласно мануала означает что отправлять на
# почту только логи попадающие в категорию
0KERNЛог сообщения генерируемые ядром
1USERЛог сообщения генерируемые процессами пользователя
2MAILЛог сообщения от почтовой системы
3DAEMONЛог сообщения генерируемые системными демонами

if ($hostname == 'MOSTDIE' and $syslogseverity <= 3) then {
:ommail:;mailBody }
if ($hostname == 'MOSTDIE') then {
ommysql:localhost,LogDB,user,123
}

Для начала этого более чем достаточно! Сохраняем его !
И как и писалось раньше создадим базу данных и таблицы в ней (подразумевается что вы уже запустили Mysql и назначили пароль на рута)
mysql -u root -p yourpassword
mysql
вводим

mysql>  create database LogDB;
mysql> grant all privileges on LogDB.* to 'user'@'%' identified by '123' with grant option;
и создаем таблицы 
mysql> use LogDB;
mysql>
DROP TABLE IF EXISTS `SystemEvents`;
CREATE TABLE `SystemEvents` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `CustomerID` bigint(20) DEFAULT NULL,
  `ReceivedAt` datetime DEFAULT NULL,
  `DeviceReportedTime` datetime DEFAULT NULL,
  `Facility` smallint(6) DEFAULT NULL,
  `Priority` smallint(6) DEFAULT NULL,
  `FromHost` varchar(60) DEFAULT NULL,
  `Message` text,
  `NTSeverity` int(11) DEFAULT NULL,
  `Importance` int(11) DEFAULT NULL,
  `EventSource` varchar(60) DEFAULT NULL,
  `EventUser` varchar(60) DEFAULT NULL,
  `EventCategory` int(11) DEFAULT NULL,
  `EventID` int(11) DEFAULT NULL,
  `EventBinaryData` text,
  `MaxAvailable` int(11) DEFAULT NULL,
  `CurrUsage` int(11) DEFAULT NULL,
  `MinUsage` int(11) DEFAULT NULL,
  `MaxUsage` int(11) DEFAULT NULL,
  `InfoUnitID` int(11) DEFAULT NULL,
  `SysLogTag` varchar(60) DEFAULT NULL,
  `EventLogType` varchar(60) DEFAULT NULL,
  `GenericFileName` varchar(60) DEFAULT NULL,
  `SystemID` int(11) DEFAULT NULL,
  `processid` varchar(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`ID`)
);
DROP TABLE IF EXISTS `SystemEventsProperties`;
CREATE TABLE `SystemEventsProperties` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `SystemEventID` int(11) DEFAULT NULL,
  `ParamName` varchar(255) DEFAULT NULL,
  `ParamValue` text,
  PRIMARY KEY (`ID`)
);

 Итог, конфиг настроен, база данных создана - перегружаемся и смотрим что получилось.
Если вы ничего не упустили и вдумчиво копировали конфиг, у Вас должен работать лог и rsyslog должен собирать данные с других ресурсов. Настройкой которых мы кстати сейчас и займемся. 
    Для того что бы наш мегаблекджек получал сообщения от серверов в сети, необходимо на этих самых серверах указать пересылать на него логи. Там где у вас установлен *nix проблем вообще никаких не возникает. Все штатно, стандартно и красиво и информации в гугле более достаточно. Но вот касаемо вопроса никрософта - пришлось таки опять читать много букав и подбирать варианты. Методом исключений был выбран победитель 
Инструмент идеально прост, стабилен, удобен - но главное полностью удовлетворяет наши запросы, а именно:
1. Легко устанавливается
2. Имеет встроенный фильтр
3. Устанавливается как служба
4. Отправляет все логи Виндаусов на указанный сервер.
Итого качаем архив под свою платформу. Распаковываем и копируем из него два файла evtsys.dll и evtsys.exe  в c:\windows\system32
Что Вам нужно знать о evtsys ? В целом можете посмотреть хелп и доступные опции. Но на данном этапе ограничимся следующим:
Установим его как службу и укажем куда хранить логи 
cd c:\windows\evtsys.exe -i -h 192.168.0.1  (192.168.0.1 - айпи нашего лог сервера)
после чего перейдем в службы и запустим службу "Event to Syslog"
для проверки создадим батник с таким вот содержимым и выполним его:

EVENTCREATE /T ERROR /ID 100 /L SYSTEM /D "Oshibka type" /SO "CMD file"
EVENTCREATE /T WARNING /ID 111 /L SYSTEM /D "Atention type" /SO "Cmd File"

Получим в журнал ошибок два сообщения, одно со статусом еррор, второе варнинг ! 
(В конфиге вместо MOSTDIE укажите имя машинки на котрой установили evtsys  и перезапустите rsyslog)
Смотрим журнал логов 
# tail -f /var/log/messages
Если все сделано верно вы получите в сислог два сообщения, оба запишутся в базу данных, но на почту прийдет только одно письмо, с темой и содержанием ошибки.
Кстати, интересный вариант. Если вы не планируете писать логи в разные базы данных, или не хотите писать фильтры для всех виндомашин можно воспользоваться специальным фильтром 
Facility - у которого на данный случай есть встроенные локальные переменные (Local0 -local7)
тогда правило в конфиге рсислога выглядело бы так (заюзаем local2)
local2.*  ommysql:localhost,LogDB,user,123  
а при установке evtsys укажем писать все свои логи в локальную переменную этого типа
evtsys.exe -i -f 18 -h 192.168.0.1  (-f 18 как раз наша переменная локал2 - читаем ман)
Ну вот в целом наша система и настроена. Уже можно пользоваться. Так же можно прикрутить к ней какую-то веморду типа loganalyzer и так далее которых в нете так же предостаточно (но я планирую написать свой, так что рассматривать в этой статье установку вебморды не буду). В целом - конфиг получился достаточно большой, и в нем много лишнего - но я постарался описать в нем все необходимые моменты нужные для работы. И очень жаль что я нигде не нашел столько манов в одном месте. Вся эта статья собрана по крупицам, а некоторые моменты пришлось выяснять методом подбора. По этому я надеюсь кому-то мой труд облегчит жизнь...
    Итого, имеем свой блекджек со шлюхами как и хотели. Но девочки у нас не очень - надо бы их еще причесать для порядку. Мы же хотим что бы наш сервер, кроме всего прочего, опрашивал кучу айпишнеков в сети, и если чото не пингонулось - сообщать нам опять же на почту!!! Тут уже вы сами можете выбрать готовое решение или написать скрипт на шеле, но в я лично пошел таким путем:
    Пишем скрипт который опрашивает ойпишнеки и если не пингеует выдает сообщение в сислог (А там у нас в засаде фиильтр который моментально реагирует и шлет письмо в начале конфига мы говорили об этом  
#(Фильтрация по слову в сообщении $msg)
if $msg contains 'Alarm' then {
:ommail:;mailBodyPing :ommysql:localhost,LogDB,user,123
}  )

    Смешно звучит, но я за все время использования *nix систем так и не заставил себя выучить написание скриптов на баше, по сему предлагаю свой скрипт на pythone. В нем есть список айпишнеков которые нужно опрашивать, и в случае ошибки он дает месадж в сислог. Опять же - некоторые скажут а почему список айпишнеков в самом скрипте а не в отдельном файле который можно редактировать - отвечаю - потому что список составляется как правило один раз и весьма редко когда нужно его править, и ради етого добавлять усложнять скрипт чтением файла, и хранить его гдето я не вижу смысла. Если у вас есть такое желание допишите сами, даже не зная языка сделать это очень просто так как в официальных доках есть примеры. Итого сам скрипт (Внимание. Скрипт на питоне - пробелы и переносы сохранять):
# touch /usr/local/bin/checkiplist
chmod +x /usr/local/bin/chekiplist
#cat /usr/local/bin/chekiplist


#!/usr/local/bin/python
import subprocessimport time
import os
"""IP list tu ping"""
iplist = ['192.168.0.9', '192.168.0.141', '192.168.90.141']
"""Chek time. If time from 7 to 18 then chek every minute, else every hour"""
def checkTime():
    cmdtime = int(time.strftime('%H'))
    if (cmdtime >= 7 and cmdtime <= 18):
        return time.sleep(60)
    else:
        return time.sleep(600)

def pingProcess(ip):
    pingTest = "ping -c 1 " + ip    process = subprocess.Popen(        pingTest, shell=True, stdout=subprocess.PIPE)
    process.wait()
    returnCodeTotal = process.returncode    if returnCodeTotal == 0:
        pass    else:
        return os.system('logger "Alarm "' + ip + ' is Down')

def cykle():
    for i in iplist:
        pingProcess(i)
counter = 1
while counter == 1:
    checkTime()
    cykle()


Ну и добавим красивый старт скрипта черег демон rc.d
# touch /usr/local/etc/rc.d/iplist.sh
chmod +x /usr/local/etc/rc.d/iplist.sh

cat /usr/local/etc/rc.d/iplist.sh

#!/bin/sh
#
# PROVIDE: iplist
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subrname=iplist
command="/usr/local/bin/chekiplist &"
load_rc_config $name
iplist_enable=${iplist_enable-"NO"}
pidfile=${iplist_pidfile-"/var/run/iplist.pid"}
run_rc_command "$1"
 и незабываем добавить в rc.conf строчку
iplist_enable="YES"

Ну вот и все! Теперь мы ленивые админы, все что остается - мониторить одним глазом почту
Удачи!





10 комментариев:

  1. Отличная статья! Спасибо друг выручил! Как всегда нужно на вчера) и еще б не плохо было для ленивых админов описать реализацию с mongodb

    ОтветитьУдалить
  2. Дыг.. уних на офсайте есть описание как дружить с монгодб, да и в педивикии хватает ресурсов - копипаст - и вуаля !

    ОтветитьУдалить
  3. Привет. Статья действительно обьёмная и интересная особенно в разрезе текущей рабочей задачи. Попросило недавно начальство подружить наши циски с заббиксом через syslog. А не будучи программистом perl упёрся в тот момент что отсортировав в темплейте rsyslog'a лог по атправителю и severity , нужно вызывать программку отправляющую наш лог в zabbix.

    Может быть подскажете как обращаться к внешним скриптам\прогр-м из шаблона rsyslog или он может обращаться только к своим модулям ?

    ОтветитьУдалить
  4. File "./chekiplist", line 2
    import subprocessimport time
    ^
    SyntaxError: invalid syntax

    ОтветитьУдалить
  5. гугл покрячил выхлоп
    короче материцца на time

    ОтветитьУдалить
  6. File "/usr/local/bin/chekiplist", line 16
    pingTest = "ping -c 1 " + ip process = subprocess.Popen( pingTest, shell=True, stdout=subprocess.PIPE)

    SyntaxError: invalid syntax

    1 полечил, ты по ходу слепил 2 строчки в одну
    теперь материццо на process

    ОтветитьУдалить
  7. скрипт правильный. просто в питоне отступы имеют значение.
    нужно что бы было именно так как в примере.

    ОтветитьУдалить
  8. Спасибо ))) за статейку, особоенно за дамп таблиц )

    ОтветитьУдалить
  9. Привет1
    спасибо за статью, и заодно у меня вопрос:

    # мой конфиг /etc/rsyslog.d/test-spooling.conf


    $ModLoad imfile # Load the imfile input module
    $ModLoad imklog # for reading kernel log messages
    $ModLoad immark


    $WorkDirectory /var/lib/rsyslog # where to place spool files
    $ActionQueueFileName fwdRule1 # unique name prefix for spool files
    $ActionQueueMaxDiskSpace 10m # 1gb space limit (use as much as possible)
    $ActionQueueSaveOnShutdown on # save messages to disk on shutdown
    $ActionQueueType LinkedList # run asynchronously
    $ActionResumeRetryCount -1 # infinite retries if host is down

    # Watch /var/log/messages
    $InputFileName /var/log/messages
    $InputFileTag system_messages:
    $InputFileStateFile state-system
    $InputRunFileMonitor

    *.* @@192.168.50.5:5544

    -----------------------------------------

    проблема в том что происходит вроде как рекурсиия или что то на подобие потомучто в /var/log/messages да и на удалённый logstash поподает вот такой мусор

    .
    2014-04-03T23:50:42.000+0000 192.168.50.4 Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:22 www system_messages: Apr 3 23:38:53 www kernel: Kernel logging (proc) stopped.
    2014-04-03T23:50:42.000+0000 192.168.50.4 Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:22 www system_messages: Apr 3 23:38:53 www rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="7248" x-info="http://www.rsyslog.com"] exiting on signal 15.
    2014-04-03T23:50:42.000+0000 192.168.50.4 Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:22 www system_messages: Apr 3 23:38:53 www kernel: Kernel logging (proc) stopped.
    2014-04-03T23:50:42.000+0000 192.168.50.4 Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:32 www system_messages: Apr 3 23:50:22 www system_messages: Apr 3 23:38:53 www rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="7248" x-info="http://www.rsyslog.com"] exiting on signal 15.


    и при каждом signal 15 его становится всё больше.

    заранее благодарю за идеи

    кстати если мониторю не /var/log/messages а например /var/log/httpd/apache_log то всё пучком.

    ОтветитьУдалить