Skip to content
qstream-sipp-check 8.32 KiB
Newer Older
Olav Kvittem's avatar
Olav Kvittem committed
#!/usr/bin/perl
#
# process sip log files from sipp-responder and sipp-test and report to Xymon
# the task.log file gives meta-info

use XML::Simple;
use Data::Dumper;
use Socket;
use IO::Select;
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
Olav Kvittem's avatar
Olav Kvittem committed
require "newgetopt.pl";

@opts=( 'f', 'die=s', 'timeout=s', 'bb=s', 'xml', 'remote', 'debug', 'dump', 'v', 'h', 'help' );
Olav Kvittem's avatar
Olav Kvittem committed

my $usage="Usage $0 [-debug] [-die mins] [-remote] [-f]
-bb <hostname> - XYMON/BB host to receive reports
-xml  - leave an xml-file for each flow in the current directory
Olav Kvittem's avatar
Olav Kvittem committed
-remote - this is remote sipp (not used)
-f - wait for results like tail -f
-die <minutes> - end after <minutes>
";
Olav Kvittem's avatar
Olav Kvittem committed
my $rc=&NGetOpt(@opts);
die $usage if not $rc or $opt_h or $opt_help;

my $bb_host = $opt_bb   || `hostname -f`; 

$mos_limit=[0,3.2,3.9]; # mos values
$bb_color=["red", "yellow", "green"];
$call_limit=[0,70,90]; # call succes in percent

Olav Kvittem's avatar
Olav Kvittem committed
our $tz=DateTime::TimeZone->new( name => 'local' );

Olav Kvittem's avatar
Olav Kvittem committed
# check results from sipp-initated calls with tcpdumps in sipp-test

$tmp="/tmp/qstream-sipp-$$.xml";

my $at_end_of_file=0; # is at end of TASKLOG
Olav Kvittem's avatar
Olav Kvittem committed
my $endooflife=0;

if ($opt_die){
    $endoflife=time+$opt_die*60;
}

my $timeout= $opt_timeout || 1; # wait n seconds for file too be updated

foreach $tasklog(@ARGV){
    
    open TASKLOG, "<$tasklog" || die "Could not open $tasklog : $!";
#    my $flags;
#    fcntl(TASKLOG, F_GETFL, $flags) || die $!; # Get the current flags on the filehandle
#    $flags |= O_NONBLOCK; # Add non-blocking to the flags
#    fcntl(TASKLOG, F_SETFL, $flags) || die $!; # Set the flags on the filehandle
#    $rin = $win = $ein = '';
#    vec($rin,fileno(TASKLOG),1) = 1;
 #   $ein = $rin | $win;

#    while( $nfound=select($rout=$rin, $wout=$win, $eout=$ein, $timeout) ){ # read task.log
    while (1){

	if ($line=<TASKLOG>){
	    &process_line($line);
	} else {
	    last if !$opt_f;
	    $at_end_of_file=1 if ! $at_end_of_file; # set true at first eof
	exit(1) if $opt_die && (time > $endoflife); 
Olav Kvittem's avatar
Olav Kvittem committed


#	} elsif (!eof(TASKLOG)) { # line ready
#	} elsif ($opt_die){
#	    last if (time > $endoflife);
#        } else { # probably eof
#	    last if ! $opt_f;  
#	}
Olav Kvittem's avatar
Olav Kvittem committed


exit(0);


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

sub process_line {
    my $line=shift;
    next if $line !~ /[\d-]+ [\d:]+ \d+ \d+/; # invalid line/empty ..Format : date time port port 

    my ($date, $time, $pid, $sip_port, $rtp_port, $id, $function, $machine, $rtt)=split(/\s+/, $line);
    
Olav Kvittem's avatar
Olav Kvittem committed
#	sleep 300; #  minutes to be sure that the forked processes are dead
    # active=1 test $active -gt 0
    until (system("ps -p $pid > /dev/null")){  # wait until process finished
	sleep $timeout;
    }
    
    $src=$id; $src=~ s/.*@//;
    $bb_machine=$machine;
    $bb_machine=$src if $bb_machine eq '';
    $bb_machine=~s/:\d+$//;
    if ($bb_machine=~ /^\d+\.\d+/){ # lookup hostname
	my $iaddr=inet_aton($bb_machine);
	$machine= gethostbyaddr($iaddr, AF_INET);
    }
    $bb_machine=~s/\./,/g;
Olav Kvittem's avatar
Olav Kvittem committed

    my $log='';
    our $stime=$time;  # default time from tasklog, but prefer from call-log csv
    my $sdate=$date; 
 #   my $xml_out="$machine-$function-${stime}_${pid}_sipp.xml" if ($opt_xml);
    my $rtp_xml="$machine-$function-${stime}_${pid}_rtp.xml";
    my $call_xml="$machine-$function-${stime}_${pid}_call.xml";


    if ($opt_remote){
	if ($n > 0){
	    $status=100;
	    $message="Call received successfully";
	    $status=0;
	    $message="No calls received\n";
	}
	&bb_report("C-$function", $bb_machine, &bb_color($call_limit,$bb_color,$status), $message);
    } else {

	open (CSV, "/usr/bin/sipp-print  -f 'CurrentTime|ElapsedTime(C)|OutgoingCall(C)|SuccessfulCall(C)|FailedCall(C)|Retransmissions(C)|ResponseTime1(C)|ResponseTime1StDev(C)|CallLength(C)|CallLengthStDev(C)'  *_${pid}_.csv|");
	while(<CSV>){
	    $log.=$_;
	    if (/^[\d-]+[\d:]+\s+\d+/){  # date time unixtime
		($sdate,$etime,$unixtime,$elapsed, $callsout, $success, $failed, $retrans, $response_t, $response_t_sd, 
		 $call_lth, $call_lth_sd)=split;
		    my $csec=to_sec($call_lth);
		    my $dt=DateTime->from_epoch(epoch => $unixtime, time_zone => $tz);
# elapsed time is from start of sipp ..
		    $dt->subtract(seconds => $csec);  
		    $stime=$dt->hms;
		    $sdate=$dt->ymd;
		    
		    $calls=$success+$failed;
		    $status=100*$success/$calls; # success rate in %
		    $message=sprintf "$sdate $stime - %d percent success (%d/%d)\n%s",$status,$success,$calls,$log;
		} else {
		    $status=0;
		    $message="No successfull calls :\n $log";
		&bb_report("C-$function", $bb_machine, &bb_color($call_limit,$bb_color,$status), $message);

		open XML, ">$call_xml" || die "Could not open $call_xml";
		my $sectime=$etime;
		$sectime=~s/\:\d+$//;  # remove ms
	        print XML &call_xml("$id:$function", $machine_BB, $date, $stime,  $callsout, $success, $failed, $retrans, &to_sec($response_t), &to_sec($call_lth));
		close XML;

    my @f=`ls rtp_*_${pid}_*.pcap* 2>/dev/null`; 
    my $qstream_rep='';

    if($#f >=0){ # yess some files
	chomp(@f);
	my $rtp_files= join(' ', @f);

	$cmd="/usr/bin/qstream -v -name '${id}:$function' -rtp -rtt  '$rtt' -xml $rtp_xml $rtp_files";
	my $T=`date +%T`; chomp($T);
	$qstream_rep=sprintf "%s $pid $port $mport $service@$server   $function $machine ping",$T;
	open QSTREAM, "$cmd|";
	while(<QSTREAM>){ $qstream_rep.=$_}
	close QSTREAM;

	# system($cmd); # || die "command failed : $cmd : $!";
	$xml = XMLin($rtp_xml) || die "Could not analyze XML $rtp_xml : $!";
	print Dumper($xml) if $opt_dump;
	unlink $tmp if -f $tmp;

	
	my @flow=();
	if (ref($xml->{flow}) eq "ARRAY"){
	    @flow= @{$xml->{flow}};
	} else { # just one
	    @flow=($xml->{flow});
Olav Kvittem's avatar
Olav Kvittem committed
	}
	$min_mos=10;
	foreach $flow (@flow){
	    my $mos= $flow->{network_stats}->{MOS};
	    $mossum += $mos;
	    $n++;      
	    $min_mos=$mos if  ($mos < $min_mos) ;
Olav Kvittem's avatar
Olav Kvittem committed
	}
    }
    if ($n >0){
	my $mean_mos=$mossum/$n;
	&bb_report("M-$function", $machine, &bb_color($mos_limit,$bb_color,$min_mos), 
		   sprintf "$sdate $stime - %.1f \n%s\n",$min_mos,$qstream_rep);
Olav Kvittem's avatar
Olav Kvittem committed
	
    } else {
	&bb_report("M-$function", $machine, &bb_color($mos_limit,$bb_color,0), "No RTP files");
Olav Kvittem's avatar
Olav Kvittem committed
    }
    system "ls -l  $rtp_xml  $call_xml" if $opt_debug;

## do not merge because there could be calls without rtp
    if ( 0 && $opt_xml){  
	if ( -s $call_xml){
	    if (-s $rtp_xml ){
		system "sipmerge.php  $rtp_xml  $call_xml > $xml_out";
	    } else {
		rename $call_xml, $xml_out;
	    }
	}		
    }    
 #   unlink $rtp_xml if -f $rtp_xml;
 #   unlink $call_xml if -f $call_xml;
#  /usr/bin/sipp-print -id $src -q -f 'OutgoingCall(C)|SuccessfulCall(C)|FailedCall(C)|Retransmissions(C)|ResponseTime1(C)|ResponseTime1StDev(C)|CallLength(C)|CallLengthStDev(C)'  *_${pid}_.csv
Olav Kvittem's avatar
Olav Kvittem committed

#--------------------------------------------------------------------------------
Olav Kvittem's avatar
Olav Kvittem committed

sub bb_color {
    my ($limit, $color, $value)=@_;

    for ($i=$#$limit;$i>=$[;$i--){
	if ( $value >= @$limit[$i]){ 
	    return @$color[$i];
	}
	
    }

}

sub bb_report {
Olav Kvittem's avatar
Olav Kvittem committed
    my ($bbtest, $machine, $color, $msg)=@_;
#    my $cmd="/usr/lib/hobbit/client/bin/bb $bb_host 'status $machine.$bbtest $color $msg\n'>>$ENV{HOME}/cmd.log 2>&1";
    my $cmd="/usr/lib/hobbit/client/bin/bb $bb_host 'status $machine.$bbtest $color $msg\n'";
#    system($cmd)|| warn "Command failed : $cmd : $!";
    my @cmd=("/usr/lib/hobbit/client/bin/bb", "$bb_host", "status $machine.$bbtest $color $msg\n");
    system(@cmd) if $opt_bb; # || warn "Command failed : @cmd : $!" ;
Olav Kvittem's avatar
Olav Kvittem committed
    print $cmd, "\n" if $opt_v;

}


# hh:mm:ss to seconds

sub to_sec {

    my ($hh, $mm, $ss,$ms)=split(/:/, shift);
    return (3600*$hh+60*$mm+$ss+$ms/1000);


}


# output xml line

sub call_xml {
    my ($id, $bb_machine, $date, $etime, $callsout, $success, $failed, $retrans, $response_t, $call_lth) = @_;

    return "<?xml version=\"1.0\"?>
<qstream version=\"1.0\">
  <flow>
    <flow_name>$id</flow_name>
    <date>$date</date>
    <time>$etime</time>
    <call_stats>
      <calls_out>$callsout</calls_out>
      <calls_ok> $success</calls_ok>
      <calls_fail>$failed</calls_fail>
      <calls_retrans>$retrans</calls_retrans>
      <response_time>$response_t</response_time>
      <call_secs>$call_lth</call_secs>
    </call_stats>
  </flow>
</qstream>
";
   
}