The WSymon "dashboard" is a simple, proof-of-concept "application" which summaries information from the ticker, warning and trouble output-streams as a set of automatically-updated HTML frames for viewing in a Web-browser.
WSymon consists of wsymon.pl and some Expect helper-scripts. wsymon.pl is designed to be called by Cron at frequent intervals (e.g., every 10 minutes). It generates a set of HTML frames:
In addition to the frames, a frame-container page is output which is intended to be loaded in (viewed via) any Web-browser. The frames are output with a META refresh tag, so that updates are automatic.
#!/usr/local/bin/expect -- # -- prevent an untimely end. If you have a command that takes a # time, adjust this set timeout 10 spawn /usr/local/bin/scp [email protected]:/export/u03/wsymon/_symon/_var/_diskbuffs/symon.trouble tmp/symon.trouble.cosmos expect timeout { exit 0 } 100% spawn /usr/local/bin/scp [email protected]:/export/u03/wsymon/_symon/_var/_diskbuffs/symon.warning tmp/symon.warning.cosmos expect timeout { exit 0 } 100% spawn /usr/local/bin/scp [email protected]:/export/u03/wsymon/_symon/_var/_diskbuffs/symon.ticker tmp/symon.ticker.cosmos expect timeout { exit 0 } 100% send "exit \r" exit 1
#!/usr/bin/perl use strict; # ----------------------------------------------------------------------------- # -- we expect to get some data from the systems we are monitoring : my $flag_c = system("/export/home/simonh/wsymon.expect.cosmos > /dev/null"); my $flag_e = system("/export/home/simonh/wsymon.expect.eric > /dev/null"); my $flag_d = system("/export/home/simonh/wsymon.expect.dominion > /dev/null"); unless ($flag_c) { &oh_fuck("cosmos", "Could not scp to cosmos " . localtime()); } unless ($flag_e) { &oh_fuck("eric", "Could not scp to eric " . localtime()); } unless ($flag_d) { &oh_fuck("dominion", "Could not scp to dominion " . localtime()); } # ----------------------------------------------------------------------------- # -- parse each file to produce "column" files : my @machines = ("cosmos", "eric", "dominion1"); my @streams = ("warning", "trouble"); my $mons = { }; foreach my $m (@machines) { foreach my $s (@streams) { ###&parse_symon_output_file("tmp/symon.$s.$m", $m, $s); print "\n Gonna parse last bit of tmp/symon.$s.$m"; &parse_last_bit_of_symon_output_file("tmp/symon.$s.$m", $m, $s); print "\n ...parsed"; } } print "\n Gonna build ticker..."; &build_ticker("tmp/symon.ticker", "tmp", \@machines); print "\n ...built"; print "\n Gonna output stuff..."; &output_stuff("tmp"); print "\n ...output"; print "\n\n"; # ----------------------------------------------------------------------------- # -- produce index.html containing divs of each "column" file just produced : my $width = 200; my @f = (); my @tf = (); open (HTML, ">tmp/index.html"); print HTML "<HTML>\n<HEAD>\n<TITLE>SyMon</TITLE>"; print HTML "\n</HEAD>\n\n"; opendir(TMPD, "tmp"); foreach my $f (readdir(TMPD)) { unless ($f =~ m/\.col.html$/) { next; } if ($f =~ m/trouble/) { push (@tf, $f); } elsif ($f =~ m/ticker/) {} else { push (@f, $f); } } close(TMPD); my $width = int 100/scalar(@f); my $vwidth = int 100/scalar(@tf); print HTML "\n<FRAMESET ROWS=\"67%, 33%\">"; print HTML "\n <FRAMESET COLS=\"67%, 33%\">"; print HTML "\n <FRAMESET COLS=\""; foreach (@f) { print HTML "$width%, "; } print HTML "\">"; foreach (@f) { print HTML "\n <FRAME SRC=\"$_\">"; } print HTML "\n </FRAMESET>"; print HTML "\n <FRAMESET ROWS=\""; foreach (@tf) { print HTML "$vwidth%, "; } print HTML "\">"; foreach (@tf) { print HTML "\n <FRAME SRC=\"$_\">"; } print HTML "\n </FRAMESET>"; print HTML "\n </FRAMESET>"; print HTML "\n <FRAMESET ROWS=\"33%, 67%\">"; print HTML "\n <FRAME SRC=\"tickers.html\">"; print HTML "\n <FRAME NAME=\"bottom\" SRC=\"test.html\">"; print HTML "\n </FRAMESET>"; print HTML "\n</FRAMESET>"; print HTML "\n\n</HTML>\n"; close (HTML); # ----------------------------------------------------------------------------- # -- SUBS : # ----------------------------------------------------------------------------- # -- #sub parse_symon_output_file() { # my $source = shift; # my $machine = shift; # my $stream = shift; # # open (SRC, $source) || die "\n\n Can't open: $source \n\n"; # my @source = <SRC>; # close (SRC); # # @{$mons->{$machine}->{$stream}} = (); # # foreach my $s (@source) { # # unless ($s =~ m/\S/) { next; } # # # -- three bits: date-time stamp, monitoring module, message : # my ($dt, undef) = split(/\s\:\s/, $s); # my (undef, $mess) = split(/\:\:\:/, $s); # # # -- eliminate year/month and seconds from date-time stamp : # $dt =~ s/\s*\d\d\/\d\d\/(\d\d)\s+(\d\d\:\d\d):\d\d/$1\/$2/; # # # -- # push(@{$mons->{$machine}->{$stream}}, $dt . "\n" . $mess); # } # } sub parse_last_bit_of_symon_output_file() { my $source = shift; my $machine = shift; my $stream = shift; my @source = (); my $srcline = ""; open (SRC, $source) || die "\n\n Can't open: $source \n\n"; while (defined ($srcline = <SRC>)) { push(@source, $srcline); # -- limit length of said array (for memory reasons) and because we don't # want more than the last few hundred lines anyway : print "\n source $machine size: " . scalar @source; if (scalar @source > 200) { shift @source; } } close (SRC); @{$mons->{$machine}->{$stream}} = (); foreach my $s (@source) { unless ($s =~ m/\S/) { next; } # -- three bits: date-time stamp, monitoring module, message : my ($dt, undef) = split(/\s\:\s/, $s); my (undef, $mess) = split(/\:\:\:/, $s); # -- eliminate year/month and seconds from date-time stamp : $dt =~ s/\s*\d\d\/\d\d\/(\d\d)\s+(\d\d\:\d\d):\d\d/$1\/$2/; # -- push shortened line onto array in $mons : push(@{$mons->{$machine}->{$stream}}, $dt . "\n" . $mess); } } sub build_ticker() { my $prefix = shift; my $out_dir = shift; my $machines = shift; my $tickers = { }; foreach my $m (@$machines) { my @m = (); my $srcline = ""; open (TICK, "$prefix.$m") || die "\n\n Can't open: $prefix.$m \n\n"; while (defined ($srcline = <TICK>)) { push(@m, $srcline); # -- limit size of array to conserve memory and because we just # aren't interested in the rest : print "\n ticker $m size: " . scalar @m; if (scalar @m > 200) { shift @m } } $tickers->{$m} = \@m; close (TICK); } open (TICKS, ">$out_dir/tickers.html"); print TICKS "<HTML>\n<HEAD>\n<TITLE></TITLE>\n"; print TICKS "<META HTTP-EQUIV=\"refresh\" CONTENT=\"60\">"; print TICKS "<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"tickers.css\">"; print TICKS "\n</HEAD>\n<BODY>\n<PRE>\n"; my $i = 0; while (1) { my $m = $machines->[$i % 3]; my $m_ = $m . (" " x (15 - length($m))); print TICKS "<B>$m_:</B>"; my $l = pop @{$tickers->{$m}}; if (defined $l) { chomp($l); print TICKS $l; } my $l = pop @{$tickers->{$m}}; if (defined $l) { chomp($l); print TICKS " && " . $l; } my $l = pop @{$tickers->{$m}}; if (defined $l) { print TICKS " && " . $l; } else { last; } $i++; if ($i >= 300) { last; } } print TICKS "\n</PRE>\n</BODY>\n</HTML>\n"; close (TICKS); } sub output_stuff() { my $out_dir = shift; foreach my $machine (sort keys %$mons) { foreach my $stream (sort keys %{$mons->{$machine}}) { open (COL, ">$out_dir/$machine.$stream.col.html") || die "\n\n Can't open out: $out_dir/$machine.$stream.col.html\n\n"; print COL "<HTML>\n<HEAD>\n<TITLE></TITLE>\n"; print COL "<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"col.css\">"; print COL "<META HTTP-EQUIV=\"refresh\" CONTENT=\"60\">"; print COL "</HEAD><BODY>"; print COL "<B><A HREF=\"symon.$stream.$machine\" TARGET=\"bottom\">$machine.$stream</A></B>"; print COL "<PRE>\n"; ## my $i = 0; foreach (reverse @{$mons->{$machine}->{$stream}}) { ## $i++; print COL $_; ## if ($i > 300) { last; } } print COL "\n</PRE></BODY></HTML>\n"; close (COL); } } } # ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
...previous | up (conts) | next... |