aboutsummaryrefslogblamecommitdiffstats
path: root/src/extras/htmlog
blob: 7765d09f0a3791fd49164a94f735500ff43a1eaf (plain) (tree)





























































































































































































































                                                                                                      
#!/usr/bin/env python

from optparse import OptionParser, Option
import time, sys

__cmdParser__ = OptionParser()
__cmdParser__.add_option("-i", "--logfile", action="append", \
                     dest="logfiles", type="string", \
                     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 logfile_class:

   def __init__(self,fname):
      self.events = []
      self.curline = ""
      self.prevline = ""
      self.eof = False
      self.hostname = ""

      self.fname = fname
      self.fp = open(fname)
      first_line = self.fp.readline().strip()
      multip = 1
      readblock = 64
      while True:
         self.fp.seek(-readblock * multip,2)
         newlnpos = self.fp.read(readblock).find("\n")
         if newlnpos > 0 and newlnpos < readblock - 1:
            self.fp.seek(-readblock * multip + newlnpos +1, 2)
            break
         multip+=1
      last_line = self.fp.readline().strip()
      self.fp.seek(0)

      # let's convert the first and last timestamp to something useful
      # Jul 22 04:48:05
      self.time_begin = time.strptime(first_line[0:15], "%b %d %H:%M:%S")
      self.time_end   = time.strptime( last_line[0:15], "%b %d %H:%M:%S")

      # FIXME: check that first_line < last_line

   def readline(self):
      self.curline_pos = self.fp.tell()
      self.prevline = self.curline
      self.curline = self.fp.readline().strip()
      if len(self.curline) == 0:
         self.eof = True
      return self.curline

   def seek(self,pos):
      self.fp.seek(pos)
      self.eof = False
      self.curline = ""

   def parse(self):
      self.seek(0)
      while not self.eof:
         self.readline()
         self.parse_line()
      self.seek(0)

   def curmessage(self):
      return self.curline[17 + self.curline[16:].find(" "):]

   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("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 fucked 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

logs = []

for logname in __cmdLineOpts__.logfiles:
   log = logfile_class(logname)
   log.parse()
   logs.append(log)

print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>HTMLogs output</TITLE>
<style type="text/css">
body {
	background: #FFF;
	color: #000;
	font: normal normal 12px Verdana, Geneva, Arial, Helvetica, sans-serif;
	margin: 10px;
	padding: 0
}

table, td, a {
	color: #000;
	font: normal normal 12px Verdana, Geneva, Arial, Helvetica, sans-serif
}

/* make the TH elements pretty */
thead.fixedHeader th {
	background: #C96;
	border-left: 1px solid #EB8;
	border-right: 1px solid #B74;
	border-top: 1px solid #EB8;
	font-weight: normal;
	padding: 4px 3px;
	text-align: left
}

/* make the A elements pretty. makes for nice clickable headers                */
thead.fixedHeader a, thead.fixedHeader a:link, thead.fixedHeader a:visited {
	color: #FFF;
	display: block;
	text-decoration: none;
	width: 100%
}

/* make the A elements pretty. makes for nice clickable headers                */
/* WARNING: swapping the background on hover may cause problems in WinIE 6.x   */
thead.fixedHeader a:hover {
	color: #FFF;
	display: block;
	text-decoration: underline;
	width: 100%
}

ul#toc {list-style:none;width:320px;}
#toc li {background:url(dot.gif) repeat-x 0 0.85em;}
#toc li a {float:left;background:#FFF;padding: 0 4px 0 0;}
#toc li span {float:right;background:#FFF; padding 0 0 0 4px;}
#toc li br {clear:both;}

-->
</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>"
while True:
   # who is next ?
   lowest_date = None
   for log in logs:
      if log.eof:
         continue

      if not len(log.curline):
         log.readline()

      if lowest_date == None or log.time_current() < lowest_date:
         lowest_date = log.time_current()

   if lowest_date == None:
      # all logs are EOF
      break

   print " <TR>"
   # FIXME: if this tick has an event, add <a name="...">
   print '  <TD STYLE="white-space:nowrap">' + time.strftime("%b %d %H:%M:%S", lowest_date) + "</TD>"
   for log in logs:
      if log.time_current() == lowest_date:
         print "  <TD>" + log.curmessage() + "</TD>"
         log.curline = ""
      else:
         print "  <TD></TD>"
#      print log.curline_pos, time.strftime("%b %d %H:%M:%S", log.time_current()), log.curmessage()
   print " </TR>"
print "<TABLE>"