#linux #perl #parsing #logging #universal
#linux #perl #синтаксический анализ #ведение журнала #Универсальный
Вопрос:
У меня вопрос об архитектуре программы. Допустим, у вас есть 100 различных файлов журналов в разных форматах, и вам нужно проанализировать и поместить эту информацию в базу данных SQL. Мой взгляд на это как:
-
используйте общий конфигурационный файл типа:
program1->name1("apache",/var/log/apache.log) (modulename,path to logfile1) program2->name2("exim",/var/log/exim.log) (modulename,path to logfile2) .... sqldb->configuration
-
используйте что-то вроде модуля (по 1 файлу на программу) типа 1.module (регулярное выражение, логструктура (некоторые переменные), sql (таблицы и функции))
-
процессы fork или thread (не знаю, что лучше в Linux сейчас) для разных программ.
Итак, вопрос в том, верен ли мой взгляд на это? Я должен использовать один модуль для каждой программы (web / MTA / iptablat) или есть какой-то лучший способ? Я думаю, что некоторые регулярные выражения будут одинаковыми, например, дата / время / ip / url. Что с этим делать? Или что я пропустил?
пример: основной журнал mta exim4
2011-04-28 13:16:24 1QFOGm-0005nQ-Ig <= exim@mydomain.org.ua ** H=localhost (exim.mydomain.org.ua ) [127.0.0.1]:51127 I=[127.0.0.1]:465 P= esmtpsa X=TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32 CV= нет A= plain_server:spam S = 763 id=1303985784.4db93e788cb5c@mydomain.org.ua T=«test» из <exim@exim.mydomain.org.ua > для test@domain.ua
все, что выделено жирным шрифтом, уже проанализировано и будет помещено в таблицу sqldb.incoming. теперь у меня есть структура в perl для хранения каждой анализируемой переменной, например $exim->{timstamp} or $exim->{host}->{ip}
моя программа будет делать что-то вроде tail -f /file
и разбирать это построчно
Гибкость: допустим, я хочу добавить поддержку на сервер apache (просто укажите временную метку userip и загруженный файл). все, что мне нужно знать, какой файл журнала анализировать, каким должно быть регулярное выражение и какой должна быть структура sql. Итак, я планирую использовать это как модуль. просто разветвляйте основной процесс с параметрами (logfile,filetype). Возможно, в дальнейшем я бы добавил некоторые параметры, которые не следует анализировать (возможно, какой-то уровень журнала низкий, и вы просто не видите там mutch)
Комментарии:
1. В конце концов, какие данные вы хотите иметь в базе данных? вы ожидаете, что список приложений будет расти (например, postfix)? Каковы ваши ожидания относительно гибкости?
2. я обновил свой вопрос. теперь это более понятно или я должен добавить что-то еще?
Ответ №1:
Я бы сделал это так:
- Создайте конфигурационный файл в следующем формате: appname:logpath:logformatname
- Создайте коллекцию классов Perl, которые наследуются от базового класса синтаксического анализа.
- Напишите скрипт, который загружает файл конфигурации, а затем перебирает его содержимое, передавая каждую итерацию соответствующему объекту-обработчику.
Если вам нужен пример шагов 1 и 2, у нас есть такой в нашем проекте. Смотрите MT::FileMgr и MT::FileMgr::* здесь.
Комментарии:
1. я забыл о классах. Звучит неплохо. Как вы думаете, драйвер sql тоже должен быть в этом классе?
Ответ №2:
Инструмент для мониторинга журналов wots мог бы выполнить за вас большую часть тяжелой работы. Она запускается как демон, просматривает столько файлов журнала, сколько вы могли бы пожелать, запускает любую комбинацию регулярных выражений perl над ними и выполняет что-то, когда совпадения найдены.
Я был бы склонен модифицировать wots
саму программу (что свободно допускает ее лицензия) для поддержки метода записи в базу данных — взгляните на ее существующие handle_*
методы.
Большая часть тяжелой работы уже выполнена за вас, и вы можете заняться интересными моментами.
Ответ №3:
Я думаю, что File:: Tail отлично подходит. Вы можете создать массив объектов File::Tail и опрашивать их с помощью select следующим образом:
while (1) {
($nfound,$timeleft,@pending)=
File::Tail::select(undef,undef,undef,$timeout,@files);
unless ($nfound) {
# timeout - do something else here, if you need to
} else {
foreach (@pending) {
# here you can handle log messages depending on filename
print $_->{"input"}." (".localtime(time).") ".$_->read;
}
(из файла perl::Tail doc)