Bashsams+локальные домены

Sams представляет из себя хороший анализатор логов squid, но в текущей стабильной версии есть некоторая недоработка — нормально не работает список локальных доменов. Тоесть можно, конечно, забить в него список подсетей, по которым не нужно вести подсчет трафика, и поставить галочку «преобразовывать днс имена», но после этого он начинает работать весьма нестабильно. Так как «с/c++» програмист из меня никакой, то для решения данной проблемы родилась следующая связка bash скриптов. Это первая более-менее «нормально» работающая версия.
Скрипты нужно запускать в последний день месяца. Смысл работы в том, что делается выборка из всех урлов, по которым был совершен переход за месяц — проверка их на принадлежность к сети, по которой не нужно считать трафик, составления из них нового списка локальных доменов и персчет статистики за текущий месяц.
Первый скирпт делает выборку, проверку, составляет новый список локальных доменов и очищает статистику за текущий месяц.

Скрипт urls
#!/bin/bash
#Берем данные с базы за текущий месяц
start_date="`date +%Y`-`date +%m`-01"
#Последняя дата месяца
#end_date="`date +%Y`-`date +%m`-`cal|xargs|awk '{print $NF}'`"
end_date="`date +%Y-%m-%d`"
#нужно инициализировать для возврата из функции больших значений
bin=
home="/root/test"
cd $home
rm -f tmp/*
#Функция для перевода десятичных чисел в двоичный вид
dec_bin(){
        bin=
        for i in 1 2 3 4
        do
                octet="`echo $1|cut -d. -f$i`"
                bin_oc="`echo "obase=2;$octet" |bc`"
                n="${#bin_oc}"
                if [ "$n" != 8 ]
                then
                        while [ "${#bin_oc}" -lt 8 ]
                        do
                                bin_oc='0'${bin_oc}
                        done
                fi
                bin=${bin}${bin_oc}
        done
}
#Функция для определения принадлежности ip-адреса внутренней сети

localdomain(){
for url in $1;
do
        ip_addr="`host -t a $url|grep "\([0-9]\{1,3\}\.\)\{3\}"|cut -d' ' -f4|tail -n1`"
        if [  -z "$ip_addr" ]
        then
                continue
        fi
        dec_bin "$ip_addr"
        bin_ip_addr=$bin
        cat  subnet_addres | while read subnet
        do
                bin_net_addr="`echo $subnet|cut -d/ -f1`"
                mask="`echo $subnet|cut -d/ -f2`"
                if [ "`echo $bin_ip_addr|cut -c1-$mask`" = "`echo $bin_net_addr|cut -c1-$mask`" ]
                then
                        echo $url>>$2
                fi
        done
done
}
start(){
        MYSQL_RESULT=`mysql -sse "select substring_index(trim(leading \"ftp://\" from trim(leading \"http://\" from substring_index(url,'/',3))),':',1) as norm_url from cache where date between '$start_date' and '$end_date' group by norm_url"|grep -E -v "([0-9]{1,3}.){3}|yandex.(ru|net)|mail.ru|rambler.ru|vkontakte.ru|narod.ru|list.ru|odnokla(ss|s)niki.ru|google.(com|ru)|imageshack.us|yahoo.com|eset.com|spylog.com|googlevideo.com|youtube.com|vkadre.ru"|cut -d'@' -f2`

        localdomain "$MYSQL_RESULT" "tmp/ixnn"
}

new_local(){
        mysql -sse  "select url from urls where type = \"local\"" --database=squidctrl|grep -v "\([0-9]\{1,3\}\.\)\{3\}"|sort>tmp/loc_old
        cat tmp/ixnn|sort>tmp/ixnn_sort
        new="`comm -13  tmp/ixnn_sort tmp/loc_old`"
        localdomain "$new" "tmp/ixnn_old"
        cat ixnet tmp/ixnn >tmp/local
        cat tmp/ixnn_old|grep -E -v "^nnov.ru|^nn.ru|^$">>tmp/local
        mysql -sse  "delete from urls where type = \"local\"" --database=squidctrl
        cat tmp/local|while read locurl
        do
                mysql -sse "INSERT INTO urls SET url=\"$locurl\",type=\"local\"" --database=squidctrl
        done
}
clear_table(){
        mysql -sse "DELETE FROM cache WHERE date between \"$start_date\" and \"$end_date\""
        mysql -sse "DELETE FROM cachesum WHERE date between \"$start_date\" and \"$end_date\""
        mysql -sse "OPTIMIZE TABLE cache"
        mysql -sse "OPTIMIZE TABLE cachesum"
#Эти  mysql запросы делают тоже самое что и sams -c
#       mysql -sse "update squidusers SET size=\"0\"" --database=squidctrl
#       mysql -sse "update squidusers SET hit=\"0\"" --database=squidctrl
#       mysql -sse "update squidusers SET enabled=\"1\" where enabled=\"0\"" --database=squidctrl
        sams -c
        mysql -sse "update sams SET endvalue=\"0\"" --database=squidctrl

}

start
new_local
clear_table

Задача следующего скрипта — сливать все логи сквида за текущий месяц в один лог (оформлено с учетом ротации логов в CentOS, тоесть хранить 5 последних, ротация раз в неделю)
Скрипт logaccess
#!/bin/bash
#Путь к папке с логами squid
squd_log="/var/log/squid"
month="`date +%m`"
home="/root/test"
rm -f $home/tmp/*

start_log(){
        #первое число текущего месяца
        ymd="`date +%Y%m01`"
        start_date="`date +%s -d$ymd`"
        #Общее число строк в файле access.log.* содержащем лог за первые числа месяца
        n_end="`cat $1|wc -l`"
        cat $1|cut -d. -f1|while read i
        do
                n=$((n+1))
                if [ $start_date -le $i ]
                then
                count_strings=$((n_end-n+1))
                tail -n$count_strings $1 >$home/tmp/access.log_month
                break
                fi
        done
}

start(){
        cd $squd_log
        echo "`ls --full-time access.log*|awk '{print($6,$9)}'|tac`"|while read file
        do
                if [ "`echo $file|cut -d'-' -f2`" -ge "$month" ]
                then
                        loggz="`echo $file|awk '{print($2)}'`"
                        log="`basename $loggz .gz`"
                        cp $loggz $home/tmp
                        if [ -f "$home/tmp/access.log_month" ]
                        then
                                gzip -dq $home/tmp/$loggz
                                cat $home/tmp/$log >> $home/tmp/access.log_month
                        else
                                gzip -dq $home/tmp/$loggz
                                start_log $home/tmp/$log
                        fi
                fi
        done
}
start
rm -f $squd_log/access.log
cp $home/tmp/access.log_month $squd_log/access.log
chown squid:squid $squd_log/access.log


И управляющий скрипт, который все это дело запускает (для CentOS)
#!/bin/bash
service squid stop
service sams stop
./urls
./logaccess
service squid start
service sams start


Все скрипты должны лежать в одной папке, в ней же должна быть подпапка tmp и лежать файл subnet_addres, где в двоичном виде записаны подсети, по которым трафик считать не следует, а через слеш — маска подсети (используется для проверки урла на принадлежность локальным доменам, сделано для того чтобы не переводить каждый раз в двоичный вид; долго — bash все-таки;)
*Этот список для нижегородского адс
subnet_addres
11000011011000100010000000000000/19
11010100010111001000000000000000/18
01011001101111010000000000000000/19
01011100111100100100000000000000/19
11000011011110101110000000000000/19
11000010101111101011000000000000/20
11000001011111010100011000000000/23
00111110110111000010000000000000/20
01001110001010001011100000000000/21
11011001000101110001000000000000/20
01010101100011110000000000000000/20
01011001000111001100011100000000/24
01011110000110010100111000000000/24
11010100010000110000000000000000/19
01011100111101101000000000000000/19
01010010110100000100000000000000/18
11010101101100010110000000000000/19
01011001011011010000000000000000/18
01001111011111100000000000000000/17
01011101011110001000000000000000/17
01011111001001010000000000000000/16
11010101101111101110000000000000/19


Также со скриптами должен лежать файл ixnet, в котором записано то же самое, только в нормальном виде (список пересоздается по-новой, полностью сети добавляются на случай — если кто-нибудь будет использовать ip вместо доменного имени).
ixnet
195.98.32.0/19
212.92.128.0/18
89.189.0.0/19
92.242.64.0/19
195.122.224.0/19
194.190.176.0/20
193.125.70.0/23
62.220.32.0/20
78.40.184.0/21
217.23.16.0/20
85.143.0.0/20
89.28.199.0/24
94.25.78.0/24
212.67.0.0/19
92.246.128.0/19
82.208.64.0/18
213.177.96.0/19
89.109.0.0/18
79.126.0.0/17
93.120.128.0/17
95.37.0.0/16
213.190.224.0/19


Доступ к mysql базе осуществляеться через .my.cnf
[client]
user = sams
password = пароль
#socket=/var/lib/mysql/mysql.sock
[mysql]
database = squidlog


Что касается времени работы — то скрипт urls у меня отрабатывает примерно час: идет обработка всех уникальных урлов за месяц, минус yandex и прочее, что точно не входит в нижегородское кольцо; всего обрабатывается порядка 8000-12000 доменов.
Остальное зависит от мощности вашего компьютера)

PS: на кроссплатформенность не тестировалось.
  • +3
  • CraDem
  • 19 сентября 2009, 00:58

Комментарии (1)

Может скажу немного не по теме, но правила русского языка ещё никто не отменял. Пожалуйста исправьте грамматические ошибки в статье.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.