aboutsummaryrefslogtreecommitdiffstats
path: root/src/extras
diff options
context:
space:
mode:
Diffstat (limited to 'src/extras')
-rwxr-xr-xsrc/extras/htmlog407
1 files changed, 224 insertions, 183 deletions
diff --git a/src/extras/htmlog b/src/extras/htmlog
index 387a5d90..87d9e9c1 100755
--- a/src/extras/htmlog
+++ b/src/extras/htmlog
@@ -2,7 +2,7 @@
#from optparse import OptionParser, Option
import time, sys, os, glob
-import getopt
+import getopt, re
#__cmdParser__ = OptionParser()
#__cmdParser__.add_option("-i", "--input", action="append",
@@ -13,6 +13,178 @@ import getopt
# 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("<html><body><ul>")
+
+ 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("""<!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>
+
+<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>
+""")
+
+ 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("</TR>")
+
+ if self.page_line == 0 or self.page_line % 200 == 0:
+ self.page_fp.write("""<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 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("""<tr><th scope="row" class="newday" colspan=4>%s</th></tr>""" % 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 = """<a name="row_%d">%s</a>""" % (self.page_line, time.strftime("%H:%M:%S", new_time))
+ for event in events:
+ self.summary_fp.write('<li><a href="something_%d.html#row_%s">%s</a>' % (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("""<TR><th scope="row" class="%s">%s</th>""" % (row_class, stime))
+ else:
+ self.page_fp.write("""<TR><th scope="row" class="%s" style="color: #cacaca">%s</th>""" % (row_class, stime))
+
+ self.page_line+=1
+
+ def new_tab(self,msg):
+ self.page_fp.write(" <TD>" + msg + "</TD>\n")
+
+ def close_page(self):
+ self.page_fp.write("</table></html>\n")
+ self.page_fp.close()
+
+ def finish(self):
+ self.close_page()
+
class host_class:
def __init__(self):
@@ -21,6 +193,8 @@ class host_class:
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"
@@ -74,6 +248,7 @@ class host_class:
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")
@@ -85,6 +260,9 @@ class host_class:
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 ""
@@ -100,6 +278,7 @@ class host_class:
return ""
if self.validate_line(toret) or toret == "":
+ self.cur_line = toret
return toret
else:
print "invalid line"
@@ -111,10 +290,12 @@ class host_class:
return False
return True
- def readmsg(self):
- toret = self.readline()
- if toret:
- return toret[18:]
+ 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:
@@ -161,38 +342,8 @@ class logfile_class:
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 validate_line(self):
+ return self.time_current(self.curmessage())
def time_current(self):
if len(self.curline) == 0: return None
@@ -239,136 +390,15 @@ for logname in cmdline["logfiles"]:
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>
-"""
+htmlgen = htmlgen_class()
previous_date = None
-inc = 0
while True:
# who is next ?
@@ -377,6 +407,8 @@ while True:
if hosts[host].eof():
continue
+ hosts[host].readline()
+
if lowest_date == None or hosts[host].time() < lowest_date:
lowest_date = hosts[host].time()
@@ -384,40 +416,49 @@ while True:
# 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>"""
+ events = []
+ for host in hosts:
+ if hosts[host].time() == lowest_date:
- 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 re.match(r'^kernel: Linux version', hosts[host].cur_msg()):
+ events.append("%s rebooted" % host)
- if inc % 2 == 0: row_class = "spec"
- else: row_class = "specalt"
+ elif re.match(r'^.*fencing node', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
- # 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) )
+ elif re.match(r'.*fence ".*" success', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
- 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>"
+ 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())
- previous_date = lowest_date
- inc += 1
+ elif not hosts[host].eof():
+ hosts[host].backline()
-print "</table>"
-
+ 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()