python:使用python分析大日志文件思路及過程


  1.做服務器開發的經常會遇到要分析大量的日志,統計大量數據;這里介紹幾種統計日志數據的方法和思路

  之前有遇到過要統計幾天內的url出現次數的事情,一天有24個gz壓縮文件,每個文件大概6G左右,URL的不重復率也很高

  使用方法:

  1.用shell 解壓然后在統計,shell腳本寫起來麻煩,統計那一塊很多人也不是很熟悉(不也不咋熟悉),sort又很慢,用下面的方法進行md5轉換就更慢了

  while read line

  do

  # 將字符串使用md5sum轉換然后截取有用的部分

  m5=$(echo $line |md5sum | awk '{print $1}')

  echo $m5 >> ./1/$filename"_txt"

  done < ./$filename"_txt"

  2.使用lua(這個因為是本人最熟悉的腳本,所以先考慮的這個),在分析小數據的時候還是挺快的,數據量大了之后可能會產生內存分配失敗的異常,32位下最大是2G,64位下理論上是可以達到2的64次方的,但是只要內有多余的內存分配就是拋出內存異常;而且在windows和linux下都需要獨立安裝,公司的有些服務器不提供安裝許可,所以就不能用了

  3.第三種使用python就行分片處理,python的問題和上面的lua一樣,32位下允許2G,64位下允許2的64次方;linux系統基本都自帶的有;但是即使是64位下加載數據大了之后也是會各種問題;

  問題: 1.空閑可用內存用完后python就會很卡着不動,或者拋出MemoryErr的異樣,這個可以用try -catch處理,也可以分段處理

  2. python在讀取文件的時候readline如果遇到無法識別的結束符eof的時候會報錯(在gzip的部分版本是會出現的),可以使用try-catch處理或者更新gzip的庫

  4.第四種思路也是用python,就是將數據存入數據庫就行處理,可以存入python自帶的sqlite數據庫(試過解析插入會比較慢);也可以存入redis這樣的存儲數據庫會比較快

  下面提供第三種的切片代碼:

  切片的思路有兩種:

  第一種是橫向切片:就是按照常規的邏輯,每個文件的url就行合並統計,然后再就行一層一層的文件合並;這個的問題是如果url的重復率很低的話,后面的合並文件會越來越大,最終都會出現memoryErr的情況,好處是當URL重復率較高的話掃描一遍文件就可能可並完畢。

  第二種是縱向切片:就是按照數據就行分片,區url轉換成md5之后的兩個值就行取模,然后按照模的大小一遍一遍的掃描所有文件就行統計,可以根據分片的數據量調整模的大小,就不會出現內存不夠的情況了,不足之處是要掃描好多次。

  # -*- coding: utf-8 -*-

  import os, sys

  import hashlib

  import gzip

  import threading

  from array import *

  import gc

  md=hashlib.md5()

  # do file

  class DoFile:

  #

  def __init__(self):

  self.LineList={}

  self.max=0

  self.all_num_array=[0,0,0,0,0,0,0,0,0,0,0]

  self.out_file_num=1

  self.all_max=0

  self.file_num=0

  self.one_max=0

  self.one_file_num=0

  #輸出dic中的數據到文件

  def putOut(self, file_name):

  print(file_name)

  dirfile_f=open(file_name, "w")

  for key, value in self.LineList.items() :

  str_1=key+" "+str(value)+"

  "

  dirfile_f.write(str_1)

  dirfile_f.close()

  self.max=0

  self.LineList.clear()

  gc.collect()

  # 掃描統計,比較耗時

  def getTongJi(self, fen_duan):

  all_sum=0

  file_num=0

  max_1=0

  max_1_file_num=0

  for key, value in self.LineList.items():

  all_sum=all_sum + value

  file_num=file_num + 1

  if value > 1 :

  max_1=max_1 + value

  max_1_file_num=max_1_file_num + 1

  print(fen_duan,all_sum,file_num,max_1,max_1_file_num)

  self.LineList.clear()

  self.max=0

  gc.collect()

  #輸出統計內容

  def getTongjiAll(self, num):

  print(num, self.all_max, self.file_num, self.one_max, self.one_file_num)

  self.all_max=0

  self.file_num=0

  self.one_max=0

  self.one_file_num=0

  self.LineList.clear()

  self.max=0

  gc.collect()

  def GetTowInfo(self, file_name) :

  f_handl=open(file_name, "r")

  while f_handl !=None:

  line=f_handl.readline()

  if not line:

  break;

  line=line.replace("

  ","")

  line=line.replace("\r","")

  key, value=line.split(' ')

  #print(key, value)

  if self.LineList.get(key)==None:

  self.LineList[key]=int(value)

  else:

  self.LineList[key]=self.LineList[key] + int(value)

  self.max=self.max + 1

  f_handl.close()

  return self.max

  #統計解析后的文件(k v格式)的數據

  def GetModeInf(self,file_name, mode, mode_to):

  f_handl=open(file_name, "r")

  for line in f_handl.readlines():

  if not line:

  break;

  #line=line.replace("

  ","")

  #line=line.replace("\r","")

  line=line.strip()

  #print(line)

  key, value=line.split(' ')

  if int(key[len(key)-2], 16) % mode==mode_to:

  #print(key, value)

  if self.LineList.get(key)==None:

  self.LineList[key]=int(value)

  self.file_num=self.file_num + 1

  if int(value) > 1:

  self.one_max=self.one_max + int(value)

  self.one_file_num=self.one_file_num + 1

  else:

  if self.LineList[key]==1 :

  self.one_max=self.one_max + int(value) + 1

  self.one_file_num=self.one_file_num + 1

  else :

  self.one_max=self.one_max + int(value)

  self.LineList[key]=self.LineList[key] + int(value)

  self.all_max=self.all_max + int(value)

  f_handl.close()

  return self.max

  def SetOutFileNum(self,out_num):

  self.out_file_num=out_num

  # 當符合輸出條件時就將dic中的數據輸出到文件

  def MarkOutPutFile(self, max_num):

  if max_num > 10000000:

  out_file="./1/uzip_txt_"+str(self.out_file_num)

  self.out_file_num=self.out_file_num + 1

  self.putOut(out_file)

  #解析gz壓縮文件,存入dic中

  def GetZipFile(self, file_name):

  print("zip",file_name)

  f=gzip.open(file_name, 'rb')

  #for t_line in f.readlines():

  while 1:

  t_line=None

  try:

  t_line=f.readline()

  if not t_line:

  break

  except Exception, err:

  print(Exception, ":",err)

  return 30000000

  #print(t_line)

  t_value=t_line.split(' ')

  #print(t_value[6])

  line=t_value[6]

  #line=line.replace("

  ","")

  #line=line.replace("\r","")

  #line=line.replace(" ","")

  line=line.strip()

  md=hashlib.md5()

  md.update(line)

  key=md.hexdigest()

  mark=int(key[len(key)-2], 16)%10

  #self.all_num_array[mark]=self.all_num_array[mark]+1

  #print(key)

  if self.LineList.get(key)==None:

  self.LineList[key]=1

  self.all_num_array[mark]=self.all_num_array[mark]+1

  self.max=self.max + 1

  else:

  self.LineList[key]=self.LineList[key] + 1

  #MarkOutPutFile(self.max,None)

  f.close()

  print("array_info:",self.all_num_array)

  return self.max

  def GetCountNum(self):

  max_sum_all=0

  max_one=0

  for i in range(0, 10):

  max_sum_all=max_sum_all + self.all_num_array[i]

  max_one=max_one + self.all_num_array[i]/20000000

  print("splite",max_sum_all, max_one)

  return max_one

  def GetCountFileNum(self):

  return self.out_file_num

  dofile=DoFile()

  #unzgrep file

  def UnZgrepFile(out_file_num, zipfile_s, zipfile_e):

  dofile.SetOutFileNum(out_file_num)

  for i in range(zipfile_s, zipfile_e):

  str_k="image_"+str(i)+ ".gz"

  if i < 10:

  str_k="image_0"+str(i)+".gz"

  max_num=dofile.GetZipFile(str_k)

  dofile.MarkOutPutFile(max_num)

  #count

  def CountFile(c_s, c_max, file_num):

  for j in range(c_s, c_max):

  print("count",c_max, j)

  for k in range(1, file_num):

  file_k="./1/uzip_txt_"+str(k)

  print(file_k)

  dofile.GetModeInf(file_k, c_max, j)

  dofile.getTongjiAll(j)

  if __name__=='__main__' :

  #unzgrep file

  UnZgrepFile(1, 0, 24)

  #get count num

  split_num=dofile.GetCountNum()

  out_file_num=dofile.GetCountFileNum()

  #count

  CountFile(0, split_num, out_file_num)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM