#!/usr/bin/env python
#from optparse import OptionParser, Option
import time, sys, os, glob
import getopt
#__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 host_class:
def __init__(self):
self.logs = []
self.log_idx = 0 # first log
self.log_ptr = 0 # first char
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):
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 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 == "":
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 readmsg(self):
toret = self.readline()
if toret:
return toret[18:]
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 parse(self):
self.seek(0)
while not self.eof:
self.readline()
self.parse_line()
self.seek(0)
def parse_line(self):
# is valid log line ?
if not self.time_current():
return
# store hostname, if we don't already have it
if len(self.hostname) == 0:
self.curline.split()[3]
# system is booting
if self.curmessage().startswith("kernel: Linux version"):
self.add_event("system boot")
# hostname has changed
if len(self.hostname) and self.hostname != self.curline.split()[3]:
self.add_event("hostname changed")
self.hostname = self.curline.split()[3]
# the clock is wrong wrong
if self.prevline and time.strptime(self.prevline[0:15], "%b %d %H:%M:%S") > self.time_current():
self.add_event("clock is messed up")
def add_event(self, message):
self.events.append( (self.curline_pos,len(self.curline),message) )
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 hosts["moka"].readline()
#print hosts["moka"].readline()
#print "DIRECT", hosts["moka"].fp().fp.tell()
#print "HOST TELL", hosts["moka"].tell()
#print hosts["moka"].readline()
#print hosts["moka"].time()
#print hosts["moka"].readline()
#print hosts["moka"].time()
#print hosts["moka"].readline()
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<style type="text/css">
<!--
body {
font: normal 11px auto "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
color: #4f6b72;
background: #E6EAE9;
}
a {
color: #c75f3e;
}
#mytable {
width: 97%;
padding: 0;
margin: 0;
}
caption {
padding: 0 0 5px 0;
width: 97%;
font: italic 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
text-align: right;
}
th {
font: bold 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
color: #4f6b72;
letter-spacing: 2px;
text-transform: uppercase;
text-align: left;
padding: 6px 6px 6px 12px;
background: #a50000 url(images/bg_header.jpg) no-repeat;
color: white;
}
th.nobg {
border-top: 0;
border-left: 0;
border-right: 1px solid #C1DAD7;
background: none;
color: black;
}
td {
border-right: 1px solid #C1DAD7;
border-bottom: 1px solid #C1DAD7;
background: #fff;
padding: 6px 6px 6px 12px;
color: #4f6b72;
letter-spacing: -1px;
white-space:pre-wrap;
font-family: monospace;
}
pre {
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
td.alt {
background: #ffbaba;
color: #797268;
}
th.newday {
text-align: right;
padding: 2px;
}
th.spec {
border-left: 1px solid #C1DAD7;
border-right: 1px solid #C1DAD7;
border-top: 0;
background: #fff url(images/bullet1.gif) no-repeat;
font: bold 10px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
color: #797268;
}
th.specalt {
border-left: 1px solid #C1DAD7;
border-right: 1px solid #C1DAD7;
border-top: 0;
background: #cecfce url(images/bullet2.gif) no-repeat;
font: bold 10px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
color: #797268;
}
-->
</style>
</head>
<body>
"""
#print '<ul id="toc">'
#for log in logs:
# print logs[idx].fname, logs[idx].events
# for line, msglen, event in log.events:
# print ' <li><span>%s</span> <a href="#">Link</a><br /></li>' % event
print '</ul>'
print """
<table id="mytable" cellspacing="0" summary="The technical specifications of the Apple PowerMac G5 series">
<caption>Generated by SOS htmlogger 1.0 on March 16th 2008</caption>
"""
previous_date = None
inc = 0
while True:
# who is next ?
lowest_date = None
for host in hosts:
if hosts[host].eof():
continue
if lowest_date == None or hosts[host].time() < lowest_date:
lowest_date = hosts[host].time()
if lowest_date == None:
# all logs are EOF
break
if inc == 0 or inc % 200 == 0:
print """<tr><th scope="col" abbr="Date/Time" class="nobg">Time</th><th scope="col" abbr="node-1">node-1</th><th scope="col" abbr="node-2">node-2</th><th scope="col" abbr="node-3">node-3</th></tr>"""
if not previous_date or time.strftime("%b %d", previous_date) != time.strftime("%b %d", lowest_date):
print """<tr><th scope="row" class="newday" colspan=4>%s</th></tr>""" % time.strftime("%A, %B %d", lowest_date)
if inc % 2 == 0: row_class = "spec"
else: row_class = "specalt"
# FIXME: if this tick has an event, add <a name="...">
if not previous_date or previous_date != lowest_date:
print """<TR><th scope="row" class="%s">%s</th>""" % (row_class, time.strftime("%H:%M:%S", lowest_date) )
else:
print """<TR><th scope="row" class="%s" style="color: #cacaca">%s</th>""" % (row_class, time.strftime("%H:%M:%S", lowest_date) )
for host in hosts:
if hosts[host].time() == lowest_date:
# print " <TD>%d</TD>" % hosts[host].tell()
print " <TD>" + hosts[host].readmsg() + "</TD>"
# print " <TD>%d</TD>" % hosts[host].tell()
else:
print " <TD></TD>"
print " </TR>"
previous_date = lowest_date
inc += 1
print "</table>"