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 wsymon@130.88.99.10:/export/u03/wsymon/_symon/_var/_diskbuffs/symon.trouble tmp/symon.trouble.cosmos
expect timeout {
exit 0
} 100%
spawn /usr/local/bin/scp wsymon@130.88.99.10:/export/u03/wsymon/_symon/_var/_diskbuffs/symon.warning tmp/symon.warning.cosmos
expect timeout {
exit 0
} 100%
spawn /usr/local/bin/scp wsymon@130.88.99.10:/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... |