Ivanovo Linux Users Group - Not logged in
Forum Help Search Login
Previous Next Up Topic Администрирование / Общее администрирование / Как посчитать почту ? (8845 hits)
- By slam Date 21.07.08 07:03
Суть проблемы - нужно выполнить подсчет почтового трафика для определенных почтовых ящиков. На сервере стоит postfix, почту раздает dovecot. У клиентов за кем закреплен ящик постоянно разные ip (динамически выданные или просто проверяют почту из разных мест). Первым делом я кинулся парсить лог dovecot-a, т.к. в нем содержится поле с указанием размера письма, но шеф сказал - фигня это все, т.к. нужно посчитать письма которые получили reject от спамассассина, но трафик на них был потрачен. Вообщем маразм... но передо мной поставил задачу. Тогда решил работать с логом postfix-a и написал скрипт на перле, но в нем получилась куча циклов, в результате скрипт работает долго (в дальнейшем я уже знаю что меня попросят написать скрипт который будет закрывать ящик пользователя если у него кончились деньги), пришлось сначала очищать лог файл от мусора и формировать новый файл с двумя полями - id письма и размер. Есть ли методы более удобнее, ведь чувствую что изобретаю велосипед?
Parent - By LOE (Site/forum admin) Date 21.07.08 07:29
А откуда в скрипте получилась куча циклов?
Даже если на одно письмо приходится несколько строк логов, все это можно распарсить за один проход.
Приведи пример строк логов (желательно с разными вариантами: доставка пользователю в ящик, отлуп от спамассасина и т.п.).

PS. не знаю как в postfix'е, но в exim'е я сделал чтобы сразу по приходу письма он сам (exim) кидал в mysql базу данные в табличку логов.
"No! Try not! Do. Or do not. There is no try." -- Yoda
Parent - By slam Date 21.07.08 08:48 Edited 21.07.08 08:52
Пример log файла postfix

Jul 21 12:33:27 web postfix/pickup[27071]: 012AC8C03: uid=8 from=<test@mail.ru>
Jul 21 12:33:27 web postfix/cleanup[25813]: 012AC8C03: message-id=<E1KKqpe-000Csh-00.test-mail-ru@f170.mail.ru>
Jul 21 12:33:27 web postfix/pickup[27071]: 044AC8C55: uid=8 from=<test2@mail.ru>
Jul 21 12:33:27 web postfix/cleanup[25813]: 044AC8C55: message-id=<E1KKqpe-000Csh-00.test2-mail-ru@f170.mail.ru>
Jul 21 12:33:27 web postfix/qmgr[5267]: 044AC8C55: from=<test2@mail.ru>, size=1685, nrcpt=1 (queue active)
Jul 21 12:33:27 web postfix/qmgr[5267]: 012AC8C03: from=<test@mail.ru>, size=1085, nrcpt=1 (queue active)
Jul 21 12:33:27 web postfix/pipe[26789]: 012AC8C03: to=<slam@literline.ru>, relay=procmail, delay=0.09, delays=0.04/0/0/0.04, dsn=2.0.0, status=sent (delivered via procmail service)
Jul 21 12:33:27 web postfix/qmgr[5267]: 012AC8C03: removed
Jul 21 12:33:27 web postfix/pipe[26789]: 044AC8C55: to=<slam@literline.ru>, relay=procmail, delay=0.09, delays=0.04/0/0/0.04, dsn=2.0.0, status=sent (delivered via procmail service)
Jul 21 12:33:27 web postfix/qmgr[5267]: 044AC8C55: removed

log файл я сам дополнил еще одним получением, т.к. письма обрабатываються не по порядку - отправленно 2а письма с ящиков test@mail.ru и test2@mail.ru на ящик slam@literline.ru

Например нужно посчитать размер писем отправленных на ящик  slam@interline.ru, примерно делаю это следующим образом:
1) фильтрую log файл и очищаю его от ненужного мусора (размер log файла порядка 600Mb в день)
2) ищу письма с to=<slam@literline.ru> и заношу в массив его id (первый цикл)
2) беру первый элемент массива, т.е. id первого найденного письма
3) по id ищу строку где есть id и size=.... (второй цикл)
4) запоминаю размер и суммируе его с текущим ($total_size = $total_size + $size)
5) следущее письмо

НО клиентов которых нужно общитывать с десяток - отсюда еще один цикл.
Parent By LOE (Site/forum admin) Date 21.07.08 09:50
Все делается просто, примерно так (черновой вариант):
#!/usr/bin/perl

use strict;

my($F)='/файл/логов';
my(%S,%P);

unless (open(I,"<",$F)) { print "Can't open file $F\n"; exit 1; }
while(<I>) {
   if (/: ([0-9A-Z]+?):.*from=<(.+?)>.*size=(\d+)/) { # ищем первую строку на письмо
       $P{$1}->{from}=$2; $P{$1}->{size}=$3; # временно запоминаем в хэш
       next;
   }
   if (/: ([0-9A-Z]+?):.*to=<(.+?)>/) { # ищем вторую строку на письмо
       if ($P{$1}) { # если есть во временно хэше данные первой строки
           $S{$2}+=$P{$1}->{size}; # суммируем размер по-юзерно по адресу to
           delete $P{$1}; # удаляем временную запись
       }
       next;
   }
}
close I;

foreach my $i (keys %S) {  # печатаем все найденное
     print "user=$i all_size=$S{$i}\n";
}


Разумеется, это набросок. За один проход подсчитается все. Можно расширить на предмет обработки дат, от кого и т.п.
В примере нет образца отработки отлупа от спамассасина, поэтому в скрипте тоже обработчика нет.
Во любом случае, такого рода "разборки" на перле делаются влет.
Можно данные каждого письма закидывать в базу (включая дату-время, от кого, кому, размер и т.п.) и делать выборки простыми sql запросами. Полезно, когда обработку лога сделать один раз, потом только заниматься выборками по разным критериям.
"No! Try not! Do. Or do not. There is no try." -- Yoda
Parent - By LOE (Site/forum admin) Date 21.07.08 09:53
А принципиально, можно научить почтовик (по крайней мере exim), чтобы он закидывал статистику в базу.
При приеме же письма проверял лимиты (выборками из табличек базы) и на основе лимитов вообще не принимал входящее письмо при превышении лимита.
Тогда все будет происходить на лету и не надо напрягаться и обрабатывать лог-файл.
"No! Try not! Do. Or do not. There is no try." -- Yoda
Parent - By slam Date 21.07.08 10:06
Спасибо за помощь, скрипт действительно получился быстрее:

[root@web src]# ls -la /var/log/maillog; time ./mail.pl
-rw-r--r-- 1 postfix mail 50234515 2008-07-21 14:02 /var/log/maillog
....data....
real    0m39.075s
user    0m19.723s
sys     0m0.546s

с sql думаю будет удобнее и эффективней
Parent By LOE (Site/forum admin) Date 21.07.08 10:12
Эффективнее - не то слово. Например так:
mysql> select D,sum(Size) from StatNew where Recipient='user@domain' and D>='2008-07-01' and D<'2008-08-01' group by D order by D;
+------------+-----------+
| D          | sum(Size) |
+------------+-----------+
| 2008-07-01 |    951234 |
| 2008-07-02 |    158415 |
| 2008-07-03 |    303723 |
| 2008-07-04 |    199946 |
| 2008-07-05 |     95788 |
| 2008-07-06 |     23529 |
| 2008-07-07 |    105657 |
| 2008-07-08 |    153257 |
| 2008-07-09 |    231991 |
| 2008-07-10 |    390424 |
| 2008-07-11 |    756091 |
| 2008-07-12 |    401703 |
| 2008-07-13 |    359186 |
| 2008-07-14 |   1273019 |
| 2008-07-15 |    810145 |
| 2008-07-16 |   1048184 |
| 2008-07-17 |   1182512 |
| 2008-07-18 |    510234 |
| 2008-07-19 |    375179 |
| 2008-07-20 |    365642 |
| 2008-07-21 |    326182 |
+------------+-----------+
"No! Try not! Do. Or do not. There is no try." -- Yoda
Parent By Bercut Date 21.07.08 10:14
изначально выбор в сторону постфикса был наверняка изза простоты
но потом за что боролись на то и напоролись
при кажущейся простоте развертывания оказалось недостаточность функционала
это наиболее распространенная ошибка
русский язык подобен искуству кун-фу, и великий мастер никогда не применит его без необходимости...
Previous Next Up Topic Администрирование / Общее администрирование / Как посчитать почту ? (8845 hits)

Powered by mwForum 2.12.0 © 1999-2007 Markus Wichitill

Page created in 0.075s with 10 database queries.