aboutsummaryrefslogblamecommitdiffstats
path: root/src/extras/htmlog
blob: d81483150a2825a99adb67ff58743dff9d1fce40 (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("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

logs = []

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

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 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

   if inc == 0 or inc % 200 == 0:
      print """<tr><th scope="col" abbr="Date/Time" class="nobg">Time of Event</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 = "altspec"

   # 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="spec">""" + time.strftime("%H:%M:%S", lowest_date) + """</th>"""
   else:
      print """<TR><th scope="row" class="spec" style="color: #cacaca">""" + time.strftime("%H:%M:%S", lowest_date) + """</th>"""

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

   previous_date = lowest_date
   inc += 1

print "</table>"