

SYS.net.ruЗаписки системного администратора
|
|
Аккаунт |
Главная »
Документы »
SQUID-STAT in DB
Как заносить стастику Squid в базу данныхПривет !!! Решил я тут статейку написать, как считать трафик сквида и заносить все это в базу данных. Имеено такая схема работает у меня уже долго (пару лет) и особых пролем я с этим не испытываю. У меня в сквиде используется NTLM аутентификация, но подробно на этом вопросе я подробно останавливаться не буду, так как подобных док в интернете кучи, остановлюсь на вопросе занесения данных в базу... Когда мне потребовалось реализовать статистику я написал небольшой скриптик складывающий данные в MySQL, скрипт я написал на Python (кстати, до сих пор на нем пишу). Все анализаторы лога делятся на 2 вида: 1. Прямые - те когда любая информация поступающая в лог, сразу заносится в базу Ессно я пошел по первому пути. Формат базы для MySQL: CREATE TABLE `traf` ( `ip` decimal(10,0) default NULL, `username` varchar(35) default NULL, `hostname` varchar(40) default NULL, `dt` datetime default NULL, `size` bigint(20) default NULL, `out` bigint(20) default NULL, `query` bigint(20) default NULL, KEY `ip_idx` (`ip`,`dt`), KEY `dt_idx` (`dt`), KEY `username` (`username`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 1. Вырубаем сквида Ну как из базы составить отчет я думаю Вы догадаетесь :) У меня (правда) был раньше скрипт, но сейчас только еженочная почтовая рассылка о дневном трафике. Теперь сам скрипт: #!/usr/bin/python import sys,string,time,fileinput,_mysql,socket db = _mysql.connect(db='traf',host='127.0.0.1',user='traf',passwd='пароля')# Если 1, до добавляется к трафику пользователя, если 0 - просто к трафику ACTION_LIST={'TCP_HIT':0, 'TCP_MISS':1, 'TCP_REFRESH_HIT':0, 'TCP_REFRESH_FAIL_HIT':0, 'TCP_REFRESH_MISS':1, 'TCP_NEGATIVE_HIT':1, 'TCP_MEM_HIT':1, 'TCP_CLIENT_REFRESH':1, 'TCP_CLIENT_REFRESH_MISS':1, 'TCP_IMS_HIT':0, 'TCP_IMS_MISS':1, 'TCP_SWAPFAIL_MISS':1, 'TCP_DENIED':0, 'UDP_HIT':0, 'UDP_HIT_OBJ':1, 'UDP_MISS':1, 'UDP_DENIED':0, 'UDP_INVALID':0, 'UDP_RELOADING':1, 'NONE':0, 'ERR_READ_TIMEOUT':0, 'ERR_LIFETIME_EXP':1, 'ERR_NO_CLIENTS_BIG_OBJ':1, 'ERR_READ_ERROR':0, 'ERR_CLIENT_ABORT':1, 'ERR_CONNECT_FAIL':0, 'ERR_INVALID_REQ':1, 'ERR_UNSUP_REQ':0, 'ERR_INVALID_URL':0, 'ERR_NO_FDS':0, 'ERR_DNS_FAIL':0, 'ERR_NOT_IMPLEMENTED':0, 'ERR_CANNOT_FETCH':1, 'ERR_NO_RELAY':1, 'ERR_DISK_IO':0, 'ERR_ZERO_SIZE_OBJECT':0, 'ERR_FTP_DISABLED':0, 'ERR_PROXY_DENIED':0, } if len(sys.argv)<2: raise NameError('Command string is necompatable,')filelog=sys.argv[1] # Это лог файл от сквида или fifo от него же outlog=sys.argv[2] # Это директория, куда складываем дополнительные sel = 0 def ip2i(s): ''' Переводит IP адрес в число ''' x = 0 for i in s.split('.'):x = ( x << 8 ) + int(i) return str(x) def i2ip(i_ip): ''' Переводит число в IP адрес ''' return '.'.join( [str( (i_ip >> (i*8)) & 0xFF ) for i in (3,2,1,0)] ) def nint(a): ''' Нормально округляет переменную''' try: result = int(a) except ValueError: result = -1 return result def nindex(g,x): ''' Если индекса нет - возвращает пустоту''' try: result = g[x] except IndexError: result = '' return result def nact(a): ''' Возвращает резуьтать акции или -1, если не найдено''' try: result = ACTION_LIST[a] except KeyError: result = -1 return result class tm: 'Класс вовзращает с учетом кеширования ип из имени' __ip2name__={}__elapsed__ = 100 # Время устаревания значения в кеше, в секундах def ip2name(self,x): 'Переводит ip в имя' try: return socket.gethostbyaddr(x)[0].lower() except: return x def __getitem__(self,x): ct = time.time() if self.__ip2name__.has_key(x): t,name = self.__ip2name__[x] if t+self.__elapsed__>ct: # Неустарело return name del self.__ip2name__[x] name = self.ip2name(x) self.__ip2name__[x]=(ct,name) return name ip2name = tm() def insDB(x): ''' Функция автоматически обрабатывает и добавляет в базу входную строку''' # Раньше была ошибка при увеличении на 1 цифру, теперь не повторится..:) g1 = x.split('.')[0] g2 = x.split(' ',1)[1]g = g2.strip() g=g.split(' ')if len(g)==9: # - Получаем параметры timestamp=nint(g1) # - TimeStamp - юниксовое врямя запроса elapsed=nint(g[0]) # - Длительность запроса ip=g[1] # - IP адрес клиента hostname = ip2name[ip] # Получим имя хоста type_reply=g[2] # - Тип/код ответа на запрос action=g[2].split('/')[0] # - Тип ответа на запросsize=g[3] # - Размер ответа method=g[4] # - Метод запроса url=g[5] # - URL запроса ident=g[6].replace(chr(92),chr(92)+chr(92)) # - ident пользователя hierarhy=g[7] # - Тип иерархического запроса mime=g[8] # - MIME типа ответа Eact=nact(action) # - Если есть код ответа, то 1 или 0 (-1 если нету) if Eact == 1: out=size # - Это взято из интернета else: out='0' # - Это взято из кеша ####################### gt=time.gmtime(timestamp) # Получим время запроса t = str(gt[0])+'-'+str(gt[1])+'-'+str(gt[2]) h = str(gt[3]) if ip.count('.')==3:#print sel if Eact == -1: print 'Error ',sel,' string ACTION_TYPE: ',action else: qq = "update traf set size=size+%s,out=out+%s,query=query+1 where ip=inet_aton('%s') and dt='%s %s' and username='%s' and traf.hostname='%s'" % (size,out,ip,t,h,ident,hostname) db.query(qq) if db.affected_rows()==0: qq = "insert into traf (ip,username,traf.hostname,dt,size,out,query) values(inet_aton('%s'),'%s','%s','%s %s',%s,%s,1)" % (ip,ident,hostname,t,h,size,out)db.query(qq) db.query('commit') else: # А сюда сваливаемся по ошибке print 'Error ',sel,' string log file ->',x def xxx(): sel=0 CurName='' fl=open('/dev/null','a') # Это чтобы его с нуля закрыть можно было...:)for x in fileinput.input(filelog): gm=time.gmtime(nint(x.split('.')[0]))LogName=str(gm[0])+'_'+string.zfill(gm[1],2)+'_'+string.zfill(gm[2],2)+'.access.log' if LogName <> CurName: print 'New Log Created:',outlog+'/'+LogName fl.close CurName=LogName fl=open(outlog+'/'+CurName,'a') fl.write(x) sel=sel+1 try: insDB(x) except: print 'Error insert to db' while 1: xxx() db.close fl.close print 'Stop. ',sel,' string parsed.' Вот в принципе и все, если есть какие замечания - пишите, обязательно статью изменю :) С Уважением, Алексей. |
Copyright © 1999-2010 by SYS.NET.RU | История изменений | |