aboutsummaryrefslogblamecommitdiffstats
path: root/src/extras/htmlog
blob: 1fbab8bb9abf6ccd4ce2fe5b513d20246c565736 (plain) (tree)
1
2
3
4
5
6
7


                                         
                    

                              
                                                            






                                                                                               

























                                                             
                                           
                                            




                                    








                                          
                                






















                                                                       
                     







                                    
                  


                                     








                                             

                                                     

                                












                                                    



                            

                           



                                                           
                     











                                                                                           
 

                                        
 

                                         

                      
                               


                       
 


                           






                          










                                                   
                                                               








                                                                                                      
                                             











                                                                        
          


                                        


                                        
 









                                             





                                                          
                       

    
      






                                                                                     

 



                   

 




                                                                                

 








                                                                              

 





                                        

 













































                                                                              


        


       

   

                      
                                           


                                                                           

             







                                                                                                           


                     

                           

                 

                                                                 




                          








                                                                                                                                                                                                                      
                                                         




                                                                                                                                 




                                                         

                            
                 




                              

















   
#!/usr/bin/env python

from optparse import OptionParser, Option
import time, sys, os

__cmdParser__ = OptionParser()
__cmdParser__.add_option("-i", "--input", 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 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():
         sys.exit("HOST IS EOF")
         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:
               sys.exit("HOST IS EOF")
               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)
      self.hostname = self.fp.readline()[16:].split(" ")[0]

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

hosts = {}

for logname in __cmdLineOpts__.logfiles:
   log = logfile_class(logname)
   if not hosts.has_key(log.hostname):
      hosts[log.hostname] = host_class()
   hosts[log.hostname].add_log(log)

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