#!/usr/bin/env python
#from optparse import OptionParser, Option
import time, sys, os, glob
import getopt, re
#__cmdParser__ = OptionParser()
#__cmdParser__.add_option("-i", "--input", action="append",
# dest="logfiles", type="string", metavar = "FILE",
# help="system log to parse")
#__cmdParser__.add_option("-v", "--verbose", action="count",
# dest="verbosity",
# help="How obnoxious we're being about telling the user what we're doing.")
#(__cmdLineOpts__, __cmdLineArgs__)=__cmdParser__.parse_args()
class htmlgen_class:
def __init__(self):
self.html_fname_base = "/tmp/something"
self.page_num = 0
self.page_line = 0
self.page_fp = None
self.cur_time = None
self.old_time = None
self.summary_fp = open(self.html_fname_base + ".html", "w")
self.summary_fp.write("
")
def new_page(self):
# close previous page
if self.page_fp:
self.close_page()
self.page_fp = open( "%s_%d.html" % (self.html_fname_base, self.page_num), "w")
self.page_num += 1
self.page_line = 0
self.page_fp.write("""
Generated by SOS htmlogger 1.0 on March 16th 2008
""")
def new_line(self, new_time, events = []):
self.old_time = self.cur_time
self.cur_time = new_time
# close previous line
if self.page_line > 0:
self.page_fp.write("")
if self.page_line == 0 or self.page_line % 200 == 0:
self.page_fp.write("""Time | node-1 | node-2 | node-3 |
""")
if self.page_line == 0 or self.page_line % 200 == 0 or time.strftime("%b %d", self.old_time) != time.strftime("%b %d", new_time):
self.page_fp.write("""%s |
""" % time.strftime("%A, %B %d", new_time))
if self.page_line % 2 == 0: row_class = "spec"
else: row_class = "specalt"
if len(events) > 0:
stime = """%s""" % (self.page_line, time.strftime("%H:%M:%S", new_time))
for event in events:
self.summary_fp.write('- %s' % (self.page_num-1,self.page_line,event) )
else:
stime = time.strftime("%H:%M:%S", new_time)
if not self.old_time or self.old_time != new_time:
self.page_fp.write("""
%s | """ % (row_class, stime))
else:
self.page_fp.write("""
---|
%s | """ % (row_class, stime))
self.page_line+=1
def new_tab(self,msg):
self.page_fp.write(" " + msg + " | \n")
def close_page(self):
self.page_fp.write("
---|
\n")
self.page_fp.close()
def finish(self):
self.close_page()
class host_class:
def __init__(self):
self.logs = []
self.log_idx = 0 # first log
self.log_ptr = 0 # first char
self.cur_line = None
def add_log(self, logfile):
# if not logfile == logfile_class:
# raise "InvalidLogfile"
for inc in range(0,len(self.logs)):
if logfile.time_end() < self.logs[inc].time_begin():
self.logs.insert(inc, logfile)
break
else:
self.logs.append(logfile)
def hostname(self):
try: return self.logs[0].hostname()
except: return None
def tell(self):
sumsize = 0
if self.log_idx > 0:
for inc in range(0, self.log_idx):
sumsize += self.logs[inc].size()
try:
sumsize += self.fp().tell()
except TypeError:
pass
return sumsize
def size(self):
sumsize = 0
for inc in range(0, len(self.logs)):
sumsize += self.logs[inc].size()
return sumsize
def eof(self):
if self.tell() >= self.size():
return True
return False
def seek(self, offset, whence = 0):
if whence == 1: offset = self.tell() + offset
elif whence == 2: offset = self.size() + offset
sumsize = 0
for inc in range(0, len(self.logs)):
if offset <= sumsize + self.logs[inc].size():
offset -= sumsize
self.log_idx = inc
self.log_ptr = offset
self.logs[inc].seek(offset)
return True
sumsize += self.logs[inc].size()
raise "Off_Boundaries"
def time(self):
return time.strptime(self.cur_line[0:15], "%b %d %H:%M:%S")
pos = self.tell()
try:
toret = time.strptime(self.readline()[0:15], "%b %d %H:%M:%S")
except ValueError:
toret = None
self.seek(pos)
return toret
def fp(self):
return self.logs[self.log_idx]
def backline(self):
self.seek(-len(self.cur_line), 1)
def readline(self):
if self.eof():
return ""
while True:
toret = self.fp().readline()
if len(toret) == 0:
if self.log_idx < len(self.logs):
self.log_idx += 1
self.fp().seek(0)
continue
else:
return ""
if self.validate_line(toret) or toret == "":
self.cur_line = toret
return toret
else:
print "invalid line"
def validate_line(self, line):
try:
time.strptime(line[0:15], "%b %d %H:%M:%S")
except:
return False
return True
def cur_msg(self):
if not hasattr(self,"_regex_cur_msg"):
self._regex_cur_msg = re.compile(r"""^.* %s (\S+:.*)$""" % self.hostname())
try: return self._regex_cur_msg.findall(self.cur_line)[0]
except: return self.cur_line
class logfile_class:
def __init__(self,fname):
self.events = []
self.fname = fname
self.fp = open(fname)
def hostname(self):
pos = self.fp.tell()
toret = self.fp.readline()[16:].split(" ")[0]
self.fp.seek(pos)
return toret
def time_begin(self):
pos = self.fp.tell()
self.fp.seek(0)
toret = time.strptime(self.fp.readline()[0:15], "%b %d %H:%M:%S")
self.fp.seek(pos)
return toret
def time_end(self):
pos = self.fp.tell()
bs = 1024
if self.size() < bs: bs = self.size()
self.fp.seek(-bs, 2)
line = self.fp.read(bs)
toret = time.strptime(line[line.rfind("\n", 0, bs - 1) + 1:][0:15], "%b %d %H:%M:%S")
self.fp.seek(pos)
return toret
def size(self):
return os.path.getsize(self.fname)
def eof(self):
return self.fp.tell() > self.size()
def readline(self):
return self.fp.readline()
def seek(self,pos):
self.fp.seek(pos)
def tell(self):
return self.fp.tell()
def validate_line(self):
return self.time_current(self.curmessage())
def time_current(self):
if len(self.curline) == 0: return None
try:
return time.strptime(self.curline[0:15], "%b %d %H:%M:%S")
except ValueError:
print "could not parse time", self.curline
return False
def usage():
print "ciao"
try:
opts, args = getopt.getopt(sys.argv[1:], "hi:v", ["help", "input="])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
cmdline = {}
cmdline["logfiles"] = []
for o, a in opts:
if o == "-v":
verbose = True
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-i", "--input"):
print o,a
for fname in sys.argv[2:]:
cmdline["logfiles"].append(fname)
sys.stderr.write("adding log %s\n" % fname)
hosts = {}
for logname in cmdline["logfiles"]:
log = logfile_class(logname)
hostname = log.hostname()
sys.stderr.write("log %s for host %s\n" % (logname, hostname))
if not hosts.has_key(hostname):
hosts[hostname] = host_class()
hosts[hostname].add_log(log)
sys.stderr.write("finished adding logs\n")
#print ''
#for log in logs:
# print logs[idx].fname, logs[idx].events
# for line, msglen, event in log.events:
# print ' - %s Link
' % event
htmlgen = htmlgen_class()
previous_date = None
while True:
# who is next ?
lowest_date = None
for host in hosts:
if hosts[host].eof():
continue
hosts[host].readline()
if lowest_date == None or hosts[host].time() < lowest_date:
lowest_date = hosts[host].time()
if lowest_date == None:
# all logs are EOF
break
events = []
for host in hosts:
if hosts[host].time() == lowest_date:
if re.match(r'^kernel: Linux version', hosts[host].cur_msg()):
events.append("%s rebooted" % host)
elif re.match(r'^.*fencing node', hosts[host].cur_msg()):
events.append(host + " " + hosts[host].cur_msg())
elif re.match(r'.*fence ".*" success', hosts[host].cur_msg()):
events.append(host + " " + hosts[host].cur_msg())
elif re.match(r'.*fence ".*" failed', hosts[host].cur_msg()):
events.append(host + " " + hosts[host].cur_msg())
elif re.match(r'.*quorum lost, blocking activity', hosts[host].cur_msg()):
events.append(host + " " + hosts[host].cur_msg())
elif re.match(r'.*quorum regained, resuming activity', hosts[host].cur_msg()):
events.append(host + " " + hosts[host].cur_msg())
elif re.match(r'.*segfault at', hosts[host].cur_msg()):
events.append(host + " " + hosts[host].cur_msg())
elif not hosts[host].eof():
hosts[host].backline()
if len(events): print time.strftime("%A %B %d %H:%M:%S", lowest_date), events
if htmlgen.page_line == 0 or htmlgen.page_line > 10000:
print "creating new page #%d" % htmlgen.page_num
htmlgen.new_page()
htmlgen.new_line(lowest_date, events)
for host in hosts:
if hosts[host].time() == lowest_date:
htmlgen.new_tab(hosts[host].cur_msg())
else:
htmlgen.new_tab("")
htmlgen.close_page()