13. wsymon — Web-based "Dashboard"

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.

13.1. wsymon.expect.cosmos

#!/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

13.2. wsymon.pl

#!/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);
          }
      }
  }

# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------


...previousup (conts)next...



About this document:

Produced from the SGML: /home/isd/public_html/_unix_sys_mon/_reml_grp/index.reml
On: 15/3/2006 at 11:33:6
Options: reml2 -i noindex -l long -o html -p multiple