Asterisklogparse.pl

From Federal Burro of Information
Jump to navigationJump to search
#!/usr/bin/perl -w

use strict;
use Data::Dumper;
use Getopt::Long;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
no warnings "uninitialized";

my $cgi = new CGI; 
my $log= "/var/log/asterisk/queue_log";
my $extension_list="/var/www/html/perl/extension.list";

# command line options:
my ($c, $q, $h, $a , $dcl, $queryqueue, $html); 
# call option
# queues option,
# help option,
# detailed call log option
# queryqueue if you want to narrow the view to one queue
# html output

(my $version) = '$Revision: 1.7 $' =~ /([\d\.]+)/;
my %calls;
my %queues;
my %events ;

# from http://www.voip-info.org/wiki/view/Asterisk+log+queue_log
# not used reference only.
#$events{'RINGNOANSWER'} =0;   # agent did not pick up phone.
#$events{'REMOVEMEMBER'} =0;   # admin funtion, on a schedule I think, for the various shifts.
#$events{'ENTERQUEUE'} =0;     # call came in
#$events{'CONNECT'} =0;        # called was connected to and agent
#$events{'CONFIGRELOAD'} =0;   # admin ignore
#$events{'COMPLETECALLER'} =0; # caller hung up
#$events{'COMPLETEAGENT'} =0;  # agent hung up.
#$events{'ADDMEMBER'} =0;      # admin funtion, on a schedule I think, for the various shifts.
#$events{'ABANDON'} =0;        # Zoe noe!
#$events{EXITWITHKEY} = 0;     # Called press a key and went somewhere else. Ignored

my $oldestlog = time;
my $newestlog = 0;

my %qnames;
$qnames{4000} = "Main GTS Queue for Level One";
$qnames{4001} = "SCT Level 2 Queue\'s";
$qnames{4020} = "General Support";
$qnames{4021} = "WSS";
$qnames{4022} = "Archiving";
$qnames{4023} = "Email";
$qnames{4024} = "SPN/SHEP";
$qnames{5000} = "All SCT phones";
$qnames{5001} = "Static for SCT Members";
$qnames{6000} = "SPN Overflow";

my %extensions;

if( -f "$extension_list") {
    open(EXT, "$extension_list" ) || warn "failed to open extension_list $!\n";
} else {
    warn "extension_list file $extension_list not a file.\n";
}
while (<EXT>) {
    chomp;
    my ($ext , $person ) = split ( /: / , $_ );
    $extensions{$ext} = $person;
}


my $GetOptresult = GetOptions (
    "dcl" => \$dcl,
    "c" => \$c,
    "q" => \$q,
    "h" => \$h,
    "a" => \$a,
    "queryqueue=s" => \$queryqueue,
    "html" => \$html
);

# set html for now
if ( $cgi->param('q') ) {
    $html = 1;
    $q = 1;
}
if ( $cgi->param('c') ) {
    $html = 1;
    $c = 1;
}
if ( $cgi->param('a') ) {
    $html = 1;
    $a = 1;
}
if ( $cgi->param('queryqueue') ) {
    if ( $cgi->param('queryqueue') =~ /(\w+)/ ) {
        $queryqueue = $1;
    }else {
        die "queryqueue must be a word, stop faffing about";
    }
}

if ( $h ) {
    print "$0, version $version

usage: $0 [-q] [-a] [-c] [-dcl] [-h] [-queryqueue=<queue>]

  q   : queue stats
  a   : show agents details in queue stats
  c   : calls log
  dcl : detailed call log
  h   : print this help message
  html: output to html

using queue log: $log
using extention list: $extension_list
";
exit 1;
}

if( -f "$log") {
    open(LOG, "$log" ) || warn "failed to open log $!\n";
} else {
	warn "log file $log not a file.\n";
}
while (<LOG>) {

    #Fields in queue_log
    # epoch timestamp of listed action
    # uniqueid of call
    # queue name
    # bridged channel
    # event
    # event parameter 1
    # event parameter 2
    # event parameter 3 

	chomp;
	my ($epoch,$callid,$queueid,$channel,$event,$var1,$var2,$var3)= split /\|/;
	# note that at ML one agent is sat at one channel, channel = agent.
	# print "Parsed line: $epoch,$callid,$queueid,$channel,$event,$var1,$var2,$var3\n";

    # if queryqueue is set then drop all others.
    next if ( $queryqueue && ( $queueid ne $queryqueue ) ) ;

    # some stuff we don't track
    # this would skew numbers otherwise.
    next if ( $_ =~ /REMOVEMEMBER/ ) ;

    if ( $dcl ) {
	    $calls{$callid}->{LOG} .= $_ . "\n";
    }

	# global stats
	( $epoch < $oldestlog )? ($oldestlog = $epoch) : 1 ;
	( $epoch > $newestlog )? ($newestlog = $epoch) : 1 ;

    ############
	# call data
    ############
    $calls{$callid}->{QUEUE} = $queueid;

    # turn channel into agent
    # SIP/<number> into <number>
    $channel =~ /(\d+)/;
    my $agent = $1;

	if ( $_ =~ /COMPLETECALLER/ ) {
        $calls{$callid}->{COMPLETEWHO} = "CALLER";
        $calls{$callid}->{COMPLETE} = $epoch;
        $calls{$callid}->{HOLDTIME} = $var1;
        $calls{$callid}->{CALLTIME} = $var2;
    }
	if ( $_ =~ /COMPLETEAGENT/ ) {
        $calls{$callid}->{COMPLETEWHO} = "AGENT";
        $calls{$callid}->{COMPLETE} = $epoch;
        $calls{$callid}->{HOLDTIME} = $var1;
        $calls{$callid}->{CALLTIME} = $var2;
    }
    if ( $_ =~ /ENTERQUEUE/ ) {
        $calls{$callid}->{ENTERQUEUE} = $epoch;
    }
    if ( $_ =~ /ABANDON/ ) {
        $calls{$callid}->{ABANDON} = $epoch;
        $calls{$callid}->{HOLDTIME_CALC} = $calls{$callid}->{ABANDON} - $calls{$callid}->{ENTERQUEUE};
        $calls{$callid}->{HOLDTIME} = $var3;
        $calls{$callid}->{MSG} .= "Call abandoned\n";
    }
    if ( $_ =~ /CONNECT/ ) {
        $calls{$callid}->{CONNECT} = $epoch;
        if ( $calls{$callid}->{ENTERQUEUE} ) {
            $calls{$callid}->{HOLDTIME_CALC} = $calls{$callid}->{CONNECT} - $calls{$callid}->{ENTERQUEUE};
            $calls{$callid}->{HOLDTIME} = $var1;
            $calls{$callid}->{AGENT} = $agent;
        } else {
            $calls{$callid}->{MSG} .= "Call entered queue before log\n";
        }
    }

    if ( $_ =~ /EXITWITHKEY/ ) {
        # commented out for now, do not track
        # $calls{$callid}->{COMPLETE} = $epoch;
        # $calls{$callid}->{COMPLETEWHO} = "KEY";
        # $calls{$callid}->{HOLDTIME} = $epoch - $calls{$callid}->{ENTERQUEUE};
        delete ( $calls{$callid} );
    }
    if ( $_ =~ /CONFIGRELOAD/ ) {
        delete ( $calls{$callid} );
    }

    ############
	# queue data
    ############
	if ( $_ =~ /COMPLETECALLER/ ) {
        $queues{$queueid}->{COMPLETECALLER}++;
        $queues{$queueid}->{agent}->{$agent}->{COMPLETE}++;
	}
	if ( $_ =~ /COMPLETEAGENT/  ) { 
        $queues{$queueid}->{COMPLETEAGENT}++; 
        $queues{$queueid}->{agent}->{$agent}->{COMPLETE}++;
	}
	if ( $_ =~ /ABANDON/        ) {
        $queues{$queueid}->{ABANDON}++;
    }
	if ( $_ =~ /RINGNOANSWER/   ) {
		# only count the ring no answer if the time was more than zero.
		if ( $var1 != 0 ) {	$queues{$queueid}->{agent}->{$agent}->{RINGNOANSWER}++ }
	}
	
}

#############
# Calculate derived data.
#############

while ( my ($callid, $value) = each(%calls) ) {
    my $queueid = $calls{$callid}->{QUEUE};

    # agregate holdtime , for calculating average later.
    if ( $calls{$callid}->{HOLDTIME} ) {
        if ( ! $calls{$callid}->{ABANDON} ) {
            $queues{$queueid}->{AGHOLDTIME} += $calls{$callid}->{HOLDTIME}; # picked up calls
        } else {
            $queues{$queueid}->{AGABHOLDTIME} += $calls{$callid}->{HOLDTIME};   # not picked up calls
        }
    }

    if ( $calls{$callid}->{ENTERQUEUE} ) {
        if ( ! $calls{$callid}->{ABANDON} && ! $calls{$callid}->{COMPLETE} && ! $calls{$callid}->{EXITWITHKEY}) {
            $queues{$queueid}->{INPROGRESS}++;
        }
    }
}

while ( my ($queueid, $value) = each(%queues) ) {
    $queues{$queueid}->{TOTALPICKEDUP} = $queues{$queueid}->{COMPLETECALLER}+$queues{$queueid}->{COMPLETEAGENT};

    # Average holdtime for picked up calls.
    if ( $queues{$queueid}->{TOTALPICKEDUP} != 0 ) {
        $queues{$queueid}->{AVERAGEHOLDTIME} = int($queues{$queueid}->{AGHOLDTIME} / $queues{$queueid}->{TOTALPICKEDUP}) ;
    } else {
        $queues{$queueid}->{AVERAGEHOLDTIME} = 0;
    }

    if ( $queues{$queueid}->{ABANDON} != 0 ) {
        $queues{$queueid}->{AVERAGEABHOLDTIME} = int ($queues{$queueid}->{AGABHOLDTIME} / $queues{$queueid}->{ABANDON} );
    } else {
        $queues{$queueid}->{AVERAGEABHOLDTIME} = 0;
    }
}

#############
# print Stats
#############

if ( ! $html ) {
    print "#########\n";
    print "# Global Stats\n";
    print "#########\n";
    print "Oldest log entry". localtime($oldestlog) ."\n";
    print "Newest log entry". localtime($newestlog) ."\n";
} else {
    my $title = "Call stats";

    print $cgi->header;
    print   $cgi->start_html(
             # -head=>meta({-http_equiv=>'Refresh', -content=>'30'}),
             -title=>$title,
             -style=>{-src=>'/blueandyellow.css'}),
             # -bgcolor=>'#103B68'),
            $cgi->h1($title);
    print "Options specified: ";
    if ( $q )   { print "queue stats, "; };
    if ( $a )   { print "agent details for queue stats, "; };
    if ( $c )   { print "call stats, "; };
    if ( $dcl ) { print "detailed call log, "; };
    if ( $queryqueue ) { print "specific queue was requested, "; };
    print "<br>\n";
    print "Displaying from ". localtime($oldestlog) . " to ". localtime($newestlog) ."\n";

}

if ( $c ) {
    if ( $html ) { print "<pre>"; }

    while ( my ($callid, $value) = each(%calls) ) {
        print "####\n# callid $callid\n####\n";

        print "QUEUE:         ".$calls{$callid}->{QUEUE}        ."\n";
        print "ENTERQUEUE:    ".$calls{$callid}->{ENTERQUEUE}   ."\n";
        print "HOLDTIME:      ".$calls{$callid}->{HOLDTIME}     ."\n";
        # print "HOLDTIME_CALC: ".$calls{$callid}->{HOLDTIME_CALC}."\n"; # Redundant, was jsut for checking
        print "ABANDON:       ".$calls{$callid}->{ABANDON}      ."\n";
        print "CONNECT:       ".$calls{$callid}->{CONNECT}      ."\n";
        print "AGENT:         ".$extensions{$calls{$callid}->{AGENT}}        ."\n";
        print "CALLTIME:      ".$calls{$callid}->{CALLTIME}     ."\n";
        print "COMPLETE:      ".$calls{$callid}->{COMPLETE}     ."\n";
        print "COMPLETEWHO:   ".$calls{$callid}->{COMPLETEWHO}  ."\n";
        print "MSG:           ".$calls{$callid}->{MSG}          ."\n";

        if ( $dcl ) { # detailed call log
            print $calls{$callid}->{LOG};
        }
    }
    if ( $html ) { print "

"; }

}

if ( $q ) {

   if ( ! $html ) {
       print "#########\n";
       print "Queue Stats:\n";
       print "#########\n";
       while ( my ($queueid, $value) = each(%queues) ) {
           next if $queueid == 'NONE';
           print 'Queue Name: '.$qnames{$queueid}.' ('.$queueid.")\n";
           print "Picked up Calls: ".$queues{$queueid}->{TOTALPICKEDUP}."(".$queues{$queueid}->{COMPLETECALLER}."/".$queues{$queueid}->{COMPLETEAGENT}. ")\n";
           print "ABANDON: " .$queues{$queueid}->{ABANDON}. "\n";
           print "AVERAGE HOLDTIME: ".$queues{$queueid}->{AVERAGEHOLDTIME}." (s)\n";
           print "AVERAGE ABANDONED HOLDTIME: ".$queues{$queueid}->{AVERAGEABHOLDTIME}." (s)\n";
           print "CALL IN PROGRESS: ".$queues{$queueid}->{INPROGRESS}."\n";
           if ( $a ) {my $agents = $queues{$queueid}->{agent};
               print "Agents:\n";
               while ( my ($key, $value) = each(%$agents) ) {
                   print "Agent: ".$extensions{$key}. " Ringnoanswer: ".$$agents{$key}->{RINGNOANSWER}. " Complete: ".$$agents{$key}->{COMPLETE}."\n";
               } 
           }
       }
   } else {

print "

Queue Stats

\n"; print "

"; print "\n"; #while ( my ($queueid,$value) = each(%queues) ) { for my $queueid ( sort keys %queues ) { next if $queueid == 'NONE'; print "\n"; } print "
Queue(id) Calls Completed
(by Caller/by Agent)
Average Hold Time (s)
(for completed calls)
Calls Abandoned Average Abandoned Time (s) Calls In Progress
<a title=\"details\" href=\"/perl/asterisklogparse.pl\?q=1\&queryqueue=$queueid\&c=1\">$qnames{$queueid}</a> ( $queueid ) $queues{$queueid}->{TOTALPICKEDUP} ( $queues{$queueid}->{COMPLETECALLER} / $queues{$queueid}->{COMPLETEAGENT} ) $queues{$queueid}->{AVERAGEHOLDTIME} $queues{$queueid}->{ABANDON} $queues{$queueid}->{AVERAGEABHOLDTIME} $queues{$queueid}->{INPROGRESS}

\n"

   }

}