summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbustico2006-07-19 15:04:15 +0000
committerbustico2006-07-19 15:04:15 +0000
commit11c5690a1b58bf7f4c2d9b458c744efac0cdad49 (patch)
treefa393f6375d158087dfb3de59e0f6acad4c9de7a
parente869853549163713adb36212500185ab0672ea39 (diff)
downloadivy-perl-11c5690a1b58bf7f4c2d9b458c744efac0cdad49.zip
ivy-perl-11c5690a1b58bf7f4c2d9b458c744efac0cdad49.tar.gz
ivy-perl-11c5690a1b58bf7f4c2d9b458c744efac0cdad49.tar.bz2
ivy-perl-11c5690a1b58bf7f4c2d9b458c744efac0cdad49.tar.xz
add a monitoring tool which log stats of what agent send to anothers agents
-rwxr-xr-xexample/ivyprobe.pl1
-rwxr-xr-xexample/ivystat.pl287
2 files changed, 288 insertions, 0 deletions
diff --git a/example/ivyprobe.pl b/example/ivyprobe.pl
index d920f24..b229fd6 100755
--- a/example/ivyprobe.pl
+++ b/example/ivyprobe.pl
@@ -43,6 +43,7 @@ my %connected_applications;
my %where_applications;
&check_options;
+$noReadLineMode = 1 unless -t;
if (defined $classes) {
@classes =split(/:/, $classes);
diff --git a/example/ivystat.pl b/example/ivystat.pl
new file mode 100755
index 0000000..f81da88
--- /dev/null
+++ b/example/ivystat.pl
@@ -0,0 +1,287 @@
+#!/usr/bin/perl -w
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU GPL General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA,
+# or refer to http://www.gnu.org/copyleft/gpl.html
+#
+
+#TODO :
+# ° pour les simili rpc : fichier de config avec des templates de question et des templates
+# de réponse pour qu'ivystat mesure les temps entre la question et la réponse
+#
+# ° version multithread pour ne pas ralentir les agents que l'on observe si
+# le traitement est long : pas possible partout car sous mandriva perl est compilé
+# sans support des threads par exemple.
+#
+# ° version avec une interface graphique mise à jour en temps reel ?
+
+
+use strict;
+use IvyN;
+use Getopt::Long;
+use Carp;
+
+
+
+sub usage (;$);
+sub statusFunc ($$$$$$$);
+sub newMessageCb ($$);
+sub writeLogs ();
+sub sigHandler ();
+
+my $appliname = "IVYSTAT.PL";
+my %options;
+
+# my %regexpByApp = (); # $regexpByApp{"app"} = [liste de regexp]
+my %appByRegexp = (); # $appByRegexp{"regexp"} = [{app1=>1 or 0 if unsubscribe, app2=>1or0, ...],
+# \&matchProcedure]
+my %compteurByApp = (); # $compteurByApp{"app from"}->{"app to"}->[nb msg, nb octets]
+my %appNameByhostAndPort = ();
+my $startTime = time();
+my $stopTime;
+
+my $totalMess = 0;
+my $totalBytes = 0;
+my $nbActiveAgent = 0;
+my $nbDeconnecteedAgent = 0;
+
+my %sendMessByApp;
+my %sendBytesByApp;
+my %receiveMessByApp;
+my %receiveBytesByApp;
+my %connectedAppByAppFrom;
+my %connectedAppByAppTo;
+
+
+
+END { writeLogs ();}
+$SIG{'QUIT'} = $SIG{'INT'} = \&sigHandler;
+
+
+# on traite la ligne de commande
+GetOptions(\%options, "help", "bus:s", "file:s", "interval:i", "running:i");
+
+usage () if (defined $options{help});
+usage ("log file name is mandatory") unless defined $options{file};
+
+if ($options{file} eq '-') {
+ open (LOG, ">&", STDOUT) || usage ("cannot output to stdout");
+} elsif (!open (LOG, ">$options{file}")) {
+ usage ("cannot create writable file $options{file}");
+}
+
+Ivy->init (-ivyBus => (defined $options{bus}) ? $options{bus} : undef,
+ -appName => $appliname,
+ -loopMode => 'LOCAL',
+ -messWhenReady => "$appliname READY"
+ );
+
+my $Ivyobj = Ivy->new (-statusFunc => \&statusFunc);
+$Ivyobj->start;
+
+$Ivyobj->bindRegexp ('(.*)', [\&newMessageCb], 1);
+$Ivyobj->repeat ($options{interval}*1000, [\&writeLogs]) if exists $options{interval};
+$Ivyobj->after ($options{running}*1000, sub {exit 0;}) if exists $options{running};
+$Ivyobj->mainLoop();
+
+
+#==========================================================================================
+# _ _ ______
+# | | | | | ____|
+# ___ | |_ __ _ | |_ _ _ ___ | |__ _ _ _ __ ___
+# / __| | __| / _` | | __| | | | | / __| | __| | | | | | '_ \ / __|
+# \__ \ \ |_ | (_| | \ |_ | |_| | \__ \ | | | |_| | | | | | | (__
+# |___/ \__| \__,_| \__| \__,_| |___/ |_| \__,_| |_| |_| \___|
+sub statusFunc ($$$$$$$) {
+ my ($ref_ready, $ref_nonReady, $ref_hashReady, $appname, $status, $host, $regexp) = @_;
+
+ if ($status eq "new") {
+ print "$appname connected from $host\n";
+ $appNameByhostAndPort{$host} = $appname;
+ $nbActiveAgent ++;
+ $sendMessByApp{$host} = 0;
+ $sendBytesByApp{$host} = 0;
+ $receiveMessByApp{$host} = 0;
+ $receiveBytesByApp{$host} = 0;
+ $connectedAppByAppFrom{$host} =0;
+ $receiveMessByApp{$host} =0;
+ # $regexpByApp{$host} = [];
+ } elsif ($status eq "died") {
+ print "$appname disconnected from $host\n";
+ $nbDeconnecteedAgent ++;
+ $nbActiveAgent --;
+ } elsif ($status eq 'subscribing') {
+ print "$appname subscribed to '$regexp'\n";
+ unless (exists $appByRegexp{$regexp}) {
+ $appByRegexp{$regexp} = [{$host => 1},
+ # sub {@{$_[1]} = ${$_[0]} =~ /$regexp/i;}];
+ eval ('sub {@{$_[1]} = ${$_[0]} =~ /$regexp/io;}')];
+ } else {
+ ${$appByRegexp{$regexp}->[0]}{$host} = 1;
+ }
+ } elsif ($status eq 'unsubscribing') {
+ print "$appname unsubscribed to '$regexp'\n";
+ ${$appByRegexp{$regexp}->[0]}{$regexp} = 0;
+ } elsif ($status eq 'filtered') {
+ print "$appname subscribed to *FILTERED* '$regexp'\n";
+ } else {
+ warn "Bug: unkown status; $status in &statusFunc\n";
+ }
+}
+
+
+# __ __ _____ _
+# | \/ | / ____| | |
+# _ __ ___ __ __ | \ / | ___ ___ ___ | | | |__
+# | '_ \ / _ \ \ \ /\ / / | |\/| | / _ \ / __| / __| | | | '_ \
+# | | | | | __/ \ V V / | | | | | __/ \__ \ \__ \ | |____ | |_) |
+# |_| |_| \___| \_/\_/ |_| |_| \___| |___/ |___/ \_____| |_.__/
+sub newMessageCb ($$) {
+ my ($app, $msg) = @_;
+ my ($reg, $func, $hostRef, $appTo, @match, $bytes, $incMess, $incBytes);
+ my $appFrom = "$app->[1]:$app->[2]";
+
+ return unless defined $msg;
+ study ($msg);
+ #print ("DBG> $app->[0] [$app->[1]:$app->[2]] has sent \"$msg\"\n");
+
+ foreach $reg (keys %appByRegexp) {
+ ($hostRef, $func) = @{$appByRegexp{$reg}};
+ &$func(\$msg, \@match) ;
+ if (scalar (@match)) {
+ $bytes = 0;
+ map (($bytes+= length ($_)) && undef, @match);
+ $compteurByApp{$appFrom} = {} unless (exists $compteurByApp{$appFrom});
+
+ foreach $appTo (keys %$hostRef) {
+ next if $appFrom eq $appTo;
+ unless (exists $compteurByApp{$appFrom}->{$appTo}) {
+ $compteurByApp{$appFrom}->{$appTo} = [];
+ $connectedAppByAppTo{$appTo}++;
+ $connectedAppByAppFrom{$appFrom}++;
+ }
+
+ $incMess = $$hostRef{$appTo};
+ $incBytes = $incMess ? $bytes : 0;
+ $compteurByApp{$appFrom}->{$appTo}->[1] += $incBytes;
+ $compteurByApp{$appFrom}->{$appTo}->[0] += $incMess;
+
+ $totalMess += $incMess;
+ $totalBytes += $incBytes;
+
+ $sendMessByApp{$appFrom} += $incMess;
+ $sendBytesByApp{$appFrom}+= $incBytes;
+ $receiveMessByApp{$appTo} += $incMess;
+ $receiveBytesByApp{$appTo} += $incBytes;
+
+ # DEBUG
+# if ($$hostRef{$appTo}) {
+# printf "DBG> %s@%s a envoyé %s [%s] à %s@%s\n",
+# $appNameByhostAndPort{$appFrom}, $appFrom, $msg, $bytes,
+# $appNameByhostAndPort{$appTo}, $appTo;
+# }
+ # END DEBUG
+ }
+ }
+ }
+}
+
+
+# _ _ _ __ _
+# (_) | | | | / _` |
+# __ __ _ __ _ | |_ ___ | | ___ | (_| | ___
+# \ \ /\ / / | '__| | | | __| / _ \ | | / _ \ \__, | / __|
+# \ V V / | | | | \ |_ | __/ | |____ | (_) | __/ | \__ \
+# \_/\_/ |_| |_| \__| \___| |______| \___/ |___/ |___/
+sub writeLogs ()
+{
+ # général :
+ # time, nb agent, nb mess, nb octets
+ # details :
+ # pour chaque agent, par ordre de nb octets envoyés :
+ # total : nb octets envoyés, nb mess envoyés, nb octets reçus, nb mess reçus
+ # pour chaque agents en receptions :
+ # nb octets envoyés, nb mess envoyés,
+ my (@sortedApp, $appf, $appt);
+
+ # il faut que le filehandle LOG soit valide
+ return unless fileno LOG;
+
+ seek (LOG, 0, 0);
+ $stopTime = time();
+ my $stdout = select (LOG);
+ printf "log from %s to %s (%d seconds)\n", localtime ($startTime).'',
+ localtime ($stopTime).'', $stopTime-$startTime;
+ print "active:$nbActiveAgent, disconnected:$nbDeconnecteedAgent, " .
+ "messages:$totalMess, bytes:$totalBytes\n\n";
+
+ goto "EXIT_writeLogs" unless scalar (%appNameByhostAndPort);
+
+ @sortedApp = reverse sort {
+ $sendBytesByApp{$a} <=> $sendBytesByApp{$b}
+ } keys (%appNameByhostAndPort);
+
+ foreach $appf (@sortedApp) {
+ print "----------------------------------------------\n";
+ printf "%s@%s ",$appNameByhostAndPort{$appf}, $appf;
+ printf "has sent %d messages [%d bytes] to %d agents\n", $sendMessByApp{$appf},
+ $sendBytesByApp{$appf}, $connectedAppByAppFrom{$appf}
+ if $sendBytesByApp{$appf};
+ printf "\t\t\ has received %d messages [%d bytes] from %d agents\n",
+ $receiveMessByApp{$appf}, $receiveBytesByApp{$appf}, $connectedAppByAppTo{$appf}
+ if $receiveMessByApp{$appf};
+
+ foreach $appt (keys %{$compteurByApp{$appf}}) {
+ printf "\t\t\t has sent %d messages [%d bytes] to %s@%s\n",
+ $compteurByApp{$appf}->{$appt}->[0], $compteurByApp{$appf}->{$appt}->[1],
+ $appNameByhostAndPort{$appt}, $appt;
+ }
+ print "\n\n";
+ }
+
+ EXIT_writeLogs:
+ select ($stdout);
+}
+
+
+# _ __ _ _ _ _ _
+# (_) / _` | | | | | | | | |
+# ___ _ | (_| | | |__| | __ _ _ __ __| | | | ___ _ __
+# / __| | | \__, | | __ | / _` | | '_ \ / _` | | | / _ \ | '__|
+# \__ \ | | __/ | | | | | | (_| | | | | | | (_| | | | | __/ | |
+# |___/ |_| |___/ |_| |_| \__,_| |_| |_| \__,_| |_| \___| |_|
+sub sigHandler ()
+{
+ # ça parrait servir à rien, mais en fait le fait d'appeler exit dans le handler de signaux
+ # permet d'appeler le bloc END{}, alors que sinon le ctrl C non trappé arrète l'execution sans
+ # appeler le bloc END{}
+ exit (0);
+}
+
+sub usage (;$) {
+ print "error : $_[0]\n" if defined $_[0];
+ print "ivystat [-h] [ -b <network>:<port> ] -i [interval] -r running time -f logfile\n";
+ print " -h print this help\n";
+ print " -b <network>:<port>\n";
+ print " to defined the network adress and the port number\n";
+ print " defaulted to 127:2010\n";
+ print " -i interval\n";
+ print " interval in seconds between regeneration of logfile\n";
+ print " -f logfile\n";
+ print " mandatory filename for the log, use - to dump on stdout\n";
+ print " -r running time\n";
+ print " run 'running time' second, generate log and exit\n";
+ print " \n";
+ exit;
+}