diff options
author | navid <navid@ef72aa8b-4018-0410-8976-d6e080ef94d8> | 2007-09-04 08:27:59 +0000 |
---|---|---|
committer | navid <navid@ef72aa8b-4018-0410-8976-d6e080ef94d8> | 2007-09-04 08:27:59 +0000 |
commit | 92bf7d380893d3e376a5e358f3d7fe03fec80aae (patch) | |
tree | 54b3457d1a525ffc5f6bb0da7ec8b3bd1d8a410d /src/extras | |
parent | 347c67b5d8fd925216eebda502182b3d69094090 (diff) | |
download | sos-92bf7d380893d3e376a5e358f3d7fe03fec80aae.tar.gz |
Merged branch navid-dev r372:389 into the trunk.
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/sos/trunk@390 ef72aa8b-4018-0410-8976-d6e080ef94d8
Diffstat (limited to 'src/extras')
-rwxr-xr-x | src/extras/htmlog | 407 |
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() |