The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Обработка log-файла почтового сервера Postfix (postfix log statistic)


<< Предыдущая ИНДЕКС Правка src / Печать Следующая >>
Ключевые слова: postfix, log, statistic,  (найти похожие документы)
From: Вершинин Егор <vershinin.e@gmail.com.> Newsgroups: email Date: Mon, 3 May 2006 14:31:37 +0000 (UTC) Subject: Обработка log-файла почтового сервера Postfix У многих системных администраторов, работающих с почтовыми серверами, рано или поздно возникают различные задачи, связанные с обработкой журнальных файлов. Например: 1) Нужно узнать было ли когда-то в прошлом письмо с определенного почтового адреса? 2) Или нужно посмотреть статистику работы с почтой уволившегося сотрудника? 3) Получить точный размер почтовых сообщений, прошедших через SMTP-сервер. 4) Да мало ли что еще Основные проблемы при таких задачах следующие: 1) При больших объемах почтового трафика журналы растут достаточно быстро; 2) Журналы подвергаются ежедневной ротации; 3) В журналах масса ненужной информации. Конечно, можно подстраховаться, и архивировать все ежедневные журналытолько вот зачем? Если возникнет задача снять статистику за год, то нужно будет выделять нужную информацию из 365 файлов (в случае ежедневной ротации), а нужной информации может быть всего несколько строк. Мною предлагается следующее решение этой проблемы: Ежедневно перед ротацией журнального файла обрабатывать файл Perl-скриптом и помещать нужную нам информацию в СУБД MySQL. Система, на которой решалась эта задача: FreeBSD 5.4, MySQL 4.1.16, Perl 5.8.6, Postfix 2.2.8, также установлен модуль: p5-DBI-1.5. 1) Создаем в СУБД MySQL базу данных maillogs с таблицей mails: Mysql> create database maillogs; Query OK, 1 row affected (0.11 sec) Mysql> create table mails( month varchar(10), day char(2), time time, ip varchar(255) not null default '', mailfrom varchar(255) not null default '', rcptto varchar(255) not null default '', size int, primary key(month,day,time)); Query OK, 0 rows affected (0.04 sec) Наша созданная таблица содержит 7 столбцов: month - Месяц, day - День, time - Время, ip - IP-адрес SMTP-клиента, mailfrom - почтовый адрес отправителя, tcptto - почтовый адрес получателя, size - размер сообщения. Естественно количество полей может меняться в зависимости от того, какие задачи ставит перед собой системный администратор. Для моих задач этих данных более чем достаточно. 2) Создаем пользователя для доступа к созданной базе: Mysql> grant select,insert,update on maillogs.* to mailuser@localhost identified by 'mailuser'; Query OK, 0 rows affected (0.06 sec) Mysql> flush privileges; Query OK, 0 rows affected (0.02 sec) 3) Самое главное - создаем скрипт на Perl, который будет обрабатывать наш журнальный файл, и помещать нужную информацию в СУБД MySQL: #!/usr/local/bin/perl use DBI; $dbh = DBI->connect("DBI:mysql:host=localhost;database=maillogs","mailuser","mailuser") or die "Нет доступа к СУБД!"; $insert = "INSERT INTO mails (month,day,time,ip,mailfrom,rcptto,size) VALUES(?,?,?,?,?,?,?)"; $sth = $dbh->prepare("$insert"); my %rec; open(MAIL, "/var/log/maillog"); while ($line = <MAIL>) { my ($month, $day, $time, $hostname, $servicename, $id, $message) = split /\s+/, $line, 7; if ($id =~ /([a-z0-9]+)\:/i) { $id = $1; $rec{$id} = {} unless ($rec{$id}); if ($message =~ 'removed') { $rec{$id}->{'removed'}++; } else { while ($message =~ /(client|size|from|to)=(\S+?)(\s|,)/g) { if ($1 eq 'client') { $rec{$id}->{'month'} = sprintf "%s", $month; $rec{$id}->{'day'} = sprintf "%d", $day; $rec{$id}->{'time'} = sprintf "%s", $time; } $rec{$id}->{$1} = $2; } } } } close(MAIL); foreach my $id (sort { $rec{$a}->{'time'} cmp $rec{$b}->{'time'} } keys %rec) { $rec{$id}->{'client'} =~ s/(.+)\[(\d+\.\d+\.\d+\.\d+)\]/$2/; $rec{$id}->{'from'} =~ s/<(.+)>/$1/; $rec{$id}->{'to'} =~ s/<(.+)>/$1/; if ( $rec{$id}->{'removed'} && $rec{$id}->{'client'} ne '127.0.0.1' ) { if ($rec{$id}->{'from'} ne 'root@domen.com') { $sth->execute($rec{$id}->{'month'},$rec{$id}->{'day'},$rec{$id}->{'time'},$rec{$id}->{'client'},$rec{$id}->{'from'},$rec{$id}->{'to'},$rec{$id}->{'size'}); } } } $sth->finish; $dbh->disconnect; Вот собственно и вся программа. Принцип обработки такой: 1) Открывается журнальный файл maillog, находящийся в каталоге /var/log/; 2) В скалярную переменную $line последовательно в цикле помещается каждая строка журнала; 3) С помощью функции split строка дробится на составляющие элементы; 4) Выделение нужной информации основано на поиске Message-ID, который уникален для каждого обрабатываемого письма; 5) Попутно исключается учет писем, обрабатываемых различными фильтрами (не ведется учет писем, проходящих через localhost); 6) Также исключается учет писем от различных служб на ящик root@domen.com. Программу легко переписать для собственных нужд, если Вам потребуется дополнительная информация о письмах. После того, как скрипт написан, необходимо в Cron внести запуск этого скрипта за несколько минут до полуночи (т.е. до ротации). Выполняем crontab -e, вносим следующую строчку: 58 23 * * * /root/Scripts/maillog.pl Теперь все. Удачи и спокойной работы!

<< Предыдущая ИНДЕКС Правка src / Печать Следующая >>

Обсуждение [ Линейный режим | Показать все | RSS ]
  • 1.1, Skif (??), 17:50, 04/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Так, мелкие замечания:
    month varchar(10), day char(2) -почему не заменить на тип date имхо, разумнее, тем более парсинг не займет много времени %hash даст спасенье. Да и процес сравнения для MySQL пойдет легче и быстрее.
    При мелкой нагрузке - тоесть редких выборках - такая база нормально дышать будет. При большой - активное составление отчетов и прочая... Касательно ключей - даже не знаю что сказать. Скорее разумнее сделать индексацию по rcpt_to и mail_from + size писем, введя в качестве primary key что-то типа id поля, с auto encrement. Почему так? Потому что ключами(индексами) надо делать поля по которым выбираются данные, а не те которые выбираются. Если педположить, что интересует конкретно время прохождения письма от pupkin@domen к vasia@domen2, тогда это разумно...Но здесь претензии скользки по определению - надо решать на этапе проектирование БД, что с ней делать будут.
    А так в принципе, ничего...
     
  • 1.2, Vershinin Egor (?), 18:37, 04/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Большое спасибо за замечания - учту в будущем!
    Честно говоря это мой первый опыт самостоятельной работы с Perl-ом и MySQL-ем, к чему весьма способствовала Ваша статья:
    https://www.opennet.ru/base/net/ng_billing_letter.txt.html
     
  • 1.3, Algor (??), 07:10, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Чтобы опыту набраться, можно и такие скрипты писать, для реальных же задач даже незнаю.
    У меня на релее около 50к писем в день и около 2к пользователей которые эти письма пишут, но задачи возникают как правило:
    1.) посмотреть доставилось ли письмо от одного пользователя к другому (в основном за сегодняшний день, и раза три было посмотреть за неделю)
    2.) какие письма были от такого то пользователя и кому
    3.) сколько спама и вирусов отсеилось
    4.) какой общий объем почты ушел и пришел.

    1,2,3 решаются с помощью простых sh скриптов (4 строчки скрипт), время выполнения которых до 10 сек
    3,4 решаются с помощью pflogsumm

     
  • 1.4, Сергей (??), 07:33, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Согласен с Algor

    Когда логи сервака занимают по 300-400 метров в день, особо с БД не поработаешь. Plain-text парсить гораздо эффективнее с точки зрения использования ресурсов системы.

    Я даже не представляю, сколько perl отожрет памяти, если ему скормить достаточно большой лог.

     
  • 1.5, Vershinin Egor (?), 08:06, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    А может Вы проверите эту программу на своих логах и сообщите результат?

    У меня такого трафика нет, к сожалению :)

     
  • 1.6, Vershinin Egor (?), 08:11, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Я тестировал эту программу на логах в 2 Мб и 25 Мб. Без записи в БД, со сбросом информации в файл:
    ./maillogs > mail.txt эта программа отрабатывала лог за 2 секунды (увеличение размера лога в 10 раз на скорости не сказалось).

    Был бы очень признателен, если ы кто-нибудь протестировал прогу на больших журналах.

     
  • 1.7, Сергей (??), 08:31, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    to Vershinin Egor

    Прогоню попробую...
    Но смысла в этом нет. Для больших логов гораздо нужнее утилиты выбора конкретной информации (поиск следов конкретного письма).
    Кстати, сколько занимает база для лога в 25 мегабайт?

     
  • 1.8, Vershinin Egor (?), 08:34, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Примерно 450 кб
     
  • 1.9, Kuzmich (??), 08:49, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    1. Интересно как поведет себя скрипт, если в конец файла /var/log/maillog будут дописываться данные, и смогут ли они туда вобще дописываться при открытом файле.
    2. Выполнение скрипта лучше поставить в logrotate, а не в cron, и после того как журнал ротэйтнулся, тогда первый вопрос отпадает сразу.
     
  • 1.10, Сергей (??), 08:56, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    to Vershinin Egor

    ниче он у меня в логах не обнаружил:
    21.03.2006 23:59:59 KRAT xxx.xxx.xxx [info] postfix/qmgr[11146]: [ID 197553 local1.info] 814DB24912: removed

    пробежался по файлу и все

    это все из-за split на самом деле, формат логов может разниться, поэтому нехорошо привязываться к своему логу

     
  • 1.11, Сергей (??), 10:52, 05/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    прогнал я скрипт с большим логом 310Mб памяти сожрал во время выполнения 128Мб... большой текст свёрнут, показать
     
     
  • 2.12, Skif (??), 13:33, 05/05/2006 [^] [^^] [^^^] [ответить]  
  • +/
    Ну зачем же так человека расстраивать Все же вектор напрвлености нужно зада... большой текст свёрнут, показать
     
     
  • 3.13, Skif (??), 13:43, 05/05/2006 [^] [^^] [^^^] [ответить]  
  • +/
    Извини, не Женя, а Егор. :)
     
  • 3.14, Сергей (??), 14:03, 05/05/2006 [^] [^^] [^^^] [ответить]  
  • +/
    >Касательно же сабжа, то здесь гораздо важнее правильно
    >организовать структуру БД и таблиц.
    Всеми руками-ногами присоединяюсь.

    >Еще раз возвращаясь к структуре таблицы primary key(month,day,time) все же выбран неудачно,
    >так как нагрузка у автора явно маленькая и письма ходят редко,
    > то ему оно подойдет, а вот на больших объемах нет
    >- так как очень часто primary key будет повторятся, соответственно в
    >базу данные попадать не будут (дублирование primary невозможно по определению).
    >ТО есть, Женя, Мысль у тебя хорошая. И даже нужная. Только еще
    >сырая. Я сам такую гадость сейчас пишу. Только я пишу не
    >единичную, а суммарную для нескольких серваков. Потому так и разжевываю, что
    >и зачем. Касательно предыдущих ораторов, того же Сергея, могу сказать, что
    >скорее всего статистику они генерят один раз и забывают об этом.
    Конечно, почти так. Точнее, интересующую меня статистику можно получать другим путем. Так,  собрать данные о размерах писем проще в контент фильтре, если он это умеет, а если не умеет, но умеет со внешними модулями работать - то написать такой модуль. На эту тему можно долго говорить, но это будет все же немного офтоп.

    >Для меня такая проблема встала, когда пришлось частенько парсить логи нескольких почтовиков,
    >при чем у каждого он разросся от полутора до 2-х с
    >половиной гигов. И просто статистика типа сколько от и до пользователя
    >прошло писем мне была не нужна. Мне нужны были данные, как
    >прошло конкретное письмо в конкретном интервале времени,возможность вернуть лог полностью и
    >касательно одного письма, и т.д.
    Ага, вот это как "прямое" назначение логов :))) я рад просто, что у меня они не по 2 гига,  и что это требуется не особо часто, иначе пришлось бы так же, как и Вы поступать. А так можно особо не напрягаясь скриптами управится.

    >А это уже слишком специфичные задачи и большинству они нафиг не нужны.
    Золотые слова. На задачу же и решалка :)

     

  • 1.15, Жириновский (?), 20:46, 07/09/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Здравствуйте товарищи!

    а как можно брать каждные 2 минуты и вставлять их в таблицу?

    пример:
    1) открывайт файло логов
    2) блокируем файл для записи других прграмм
    3) переносим в СУБД
    4) очищаем файл
    5) разблориуем файл

    такая схема реализации подойдет?

     
  • 1.16, Жириновский (?), 20:48, 07/09/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    или нужно синхронизировать с помощью XML ?

    или еще как-то можно?

     
  • 1.17, Жириновский (?), 16:26, 08/09/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    синхронизировасть с помощю дампа с Storable наверное надо...
     
  • 1.18, Watcher (??), 08:44, 13/01/2009 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Я у себя сдела primary key
    month  
    day  
    time  
    mailfrom  
    rcptto,
    а то иначе теряются записи,(при вставке указывает на дублирующие записи), так как за секунду может быть несколько писем., Также в таблицу не вносятся записи, если письмо посылалось копией кому-либо еще.
     
  • 1.19, Avolon (?), 13:01, 21/01/2009 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    при обработке выдает
    DBD::mysql::st execute failed: Column 'month' cannot be null at ./log.pl line 55.
    Что делать то???
     
  • 1.20, Серга (?), 20:42, 20/04/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    to Avolon:
    попробуй убери $rec{$id}->{'client'} ne '127.0.0.1'
    вместо етого ип пропиши како-то левый...
     
  • 1.21, Серга (?), 19:00, 19/05/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    подскажите как етот скрипт изменить, что бы можно было и статус письма из логов получить?
     
  • 1.22, Scales (?), 12:24, 20/05/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    mail.log примерно 415 метров
    отработал приблизительно за минуты 3
    Спасибо!
     
  • 1.23, Евгений (??), 14:21, 27/10/2015 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    как добавить год? нужно чтобы в базу писался в отдельную колонку год. Никак не могу разобраться.
     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру