2011年1月24日月曜日

topコマンドのログ解析(Python手習い)

topコマンドのログをExcelでグラフ化できるようにCSV形式に変換するPythonスクリプトを書いてみた。とりあえず動いたが、色々知らないまま書いているのでたぶんもっと良い書き方があるはず。

JavaのPID毎に別ファイルに出力するようにしたかったのだが、Windows上では500個ちょっとオープンしたところで"Too Many Open Files"エラーが出たため、500を超えたら一旦すべてクローズするように暫定対処した。できれば参照の少ないファイルから先にクローズしていくようにしたい。Javaで言うところのLinkedHashMapみたいなものは無いのだろうか。

スクリプト言語としてはずいぶん昔にPerlを触った以来だが、やっつけで書きやすい割にPerlよりは可読性が高いように感じる。

import sys
import re
from datetime import datetime, timedelta
from functools import reduce

if len(sys.argv) != 3 :
 print("\nUsage:\npython", sys.argv[0], "logfile yyyy/mm/dd")
 exit()

mydate = datetime.strptime(sys.argv[2], '%Y/%m/%d')
mydateStr = mydate.strftime('%Y/%m/%d ')

try :
 f = open(sys.argv[1])
 mem = open("mem.log", 'w')
 mem.write("time,mem av,mem used,mem free,mem shard,mem buff,mem actv, mem in_d,swap av,swap used,swap free,swap cached\n")
 processes = {}
 maxtime = ""

 for line in f :
  line = line.strip()
  if re.match(r"^\d\d:\d\d:\d\d", line) :
   if line[0:2] == "00" and timestamp[0:2] != "00" :
    mydate = mydate + timedelta(1)
    mydateStr = mydate.strftime('%Y/%m/%d ')
   timestamp = line[0:8]
  elif re.match(r"^Mem", line) :
   data = re.split(r"\s+", line)[1:9:2]
  elif re.match(r"^\d+k", line) :
   data = data + re.split(r"\s+", line)[0:5:2]
  elif re.match(r"^Swap:", line) :
   data = data + re.split(r"\s+", line)[1:8:2]
   prefix = mydateStr + timestamp
   result = reduce((lambda x,y: x + ',' + y.rstrip('k')), data, prefix)
   mem.write(result + "\n")
  elif re.search(r"java", line) :
   data = re.split(r"\s+", line)
   if data[0] not in processes :
    processes[data[0]] = open("Pid-" + data[0] + ".log", 'w')
    processes[data[0]].write("time,PID,USER,PRI,NI,SIZE,RSS,SHARE,STAT,%CPU,%MEM,TIME,CPU,COMMAND\n")
   prefix = mydateStr + timestamp
   result = reduce((lambda x,y: x + ',' + y), data, prefix)
   processes[data[0]].write(result + "\n")
   if data[10] > maxtime :
    maxtime = data[10]
    maxpid = data[0]

  if len(processes) > 500 :
   map(lambda x: x.close(), processes)
   processes = {}

 print("maxpid:", maxpid)

finally :
 if f != None :
  f.close()
 if mem != None :
  mem.close()
 map(lambda x: x.close(), processes)

0 件のコメント:

コメントを投稿