mirror of
https://github.com/munin-monitoring/contrib.git
synced 2018-11-08 00:59:34 +01:00
381 lines
9.6 KiB
Perl
Executable File
381 lines
9.6 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
# -*- cperl -*-
|
|
|
|
=head1 NAME
|
|
|
|
asterisk - Multigraph-capable plugin to monitor Asterisk
|
|
|
|
=head1 NOTES
|
|
|
|
This plugin will produce multiple graphs showing:
|
|
|
|
- total number of active channels (replaces asterisk_channels),
|
|
together with breakdown of specific channel types (replaces
|
|
asterisk_channelstypes);
|
|
|
|
- the number of messages in all voicemail boxes (replaces
|
|
asterisk_voicemail);
|
|
|
|
- the number of active MeetMe conferences and users connected to them
|
|
(replace asterisk_meetme and asterisk_meetmeusers, respectively);
|
|
|
|
- the number of active channels for a given codec, for both SIP and
|
|
IAX2 channels (replaces asterisk_sipchannels and asterisk_codecs).
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
The following configuration parameters are used by this plugin
|
|
|
|
[asterisk]
|
|
env.host - hostname to connect to
|
|
env.port - port number to connect to
|
|
env.username - username used for authentication
|
|
env.secret - secret used for authentication
|
|
env.channels - The channel types to look for
|
|
env.codecsx - List of codec IDs (hexadecimal values)
|
|
env.codecs - List of codecs names, matching codecsx order
|
|
|
|
The "username" and "secret" parameters are mandatory, and have no
|
|
defaults.
|
|
|
|
=head2 DEFAULT CONFIGURATION
|
|
|
|
[asterisk]
|
|
env.host 127.0.0.1
|
|
env.port 5038
|
|
env.channels Zap IAX2 SIP
|
|
env.codecsx 0x2 0x4 0x8
|
|
env.codecs gsm ulaw alaw
|
|
|
|
=head2 WILDCARD CONFIGURATION
|
|
|
|
It's possible to use the plugin in a virtual-node capacity, in which
|
|
case the host configuration will default to the hostname following the
|
|
underscore:
|
|
|
|
[asterisk_someserver]
|
|
env.host someserver
|
|
env.port 5038
|
|
|
|
=head1 AUTHOR
|
|
|
|
Copyright (C) 2005-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
|
Copyright (C) 2012 Diego Elio Pettenò <flameeyes@flameeyes.eu>
|
|
|
|
=head1 LICENSE
|
|
|
|
GPLv2
|
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
#%# family=auto
|
|
#%# capabilities=autoconf
|
|
|
|
=cut
|
|
|
|
use strict;
|
|
use Munin::Plugin;
|
|
use IO::Socket;
|
|
|
|
sub asterisk_command {
|
|
my ($socket, $command) = @_;
|
|
my $line, my $reply;
|
|
|
|
$socket->print("Action: command\nCommand: $command\n\n");
|
|
|
|
# Response: (Error|Follows|???)
|
|
$line = $socket->getline;
|
|
if ($line !~ /^Response: Follows\r?\n$/) {
|
|
while ( $line = $socket->getline and $line !~ /^\r?\n$/ ) {}
|
|
return undef;
|
|
}
|
|
|
|
# Privilege: Command
|
|
$line = $socket->getline;
|
|
|
|
# Until we get the --END COMMAND-- marker, it's the command's output.
|
|
while ( $line = $socket->getline and $line !~ /^--END COMMAND--\r?\n$/ ) {
|
|
$reply .= $line;
|
|
}
|
|
|
|
# And then wait for the empty line that says we're done
|
|
while ( $line = $socket->getline and $line !~ /^\r?\n$/ ) {}
|
|
|
|
return $reply;
|
|
}
|
|
|
|
$0 =~ /asterisk(?:_(.+))$/;
|
|
my $hostname = $1;
|
|
|
|
my $peeraddr = $ENV{'host'} || $hostname || '127.0.0.1';
|
|
my $peerport = $ENV{'port'} || '5038';
|
|
|
|
my $username = $ENV{'username'};
|
|
my $secret = $ENV{'secret'};
|
|
|
|
my @CHANNELS = exists $ENV{'channels'} ? split ' ',$ENV{'channels'} : qw(Zap IAX2 SIP);
|
|
my @CODECS = exists $ENV{'codecs'} ? split ' ',$ENV{'codecs'} : qw(gsm ulaw alaw);
|
|
my @CODECSX = exists $ENV{'codecsx'} ? split ' ',$ENV{'codecsx'} : qw(0x2 0x4 0x8);
|
|
|
|
my $line, my $error;
|
|
my $socket = new IO::Socket::INET(PeerAddr => $peeraddr,
|
|
PeerPort => $peerport,
|
|
Proto => 'tcp')
|
|
or $error = "Could not create socket: $!";
|
|
|
|
if ( $socket ) {
|
|
# This will consume the "Asterisk Call Manager" welcome line.
|
|
$socket->getline;
|
|
|
|
$socket->print("Action: login\nUsername: $username\nSecret: $secret\nEvents: off\n\n");
|
|
my $response_status = $socket->getline;
|
|
|
|
if ( $response_status !~ /^Response: Success\r?\n$/ ) {
|
|
my $response_message = $socket->getline;
|
|
$response_message =~ s/Message: (.*)\r?\n/$1/;
|
|
$error = "Asterisk authentication error: " . $response_message;
|
|
}
|
|
|
|
while ( $line = $socket->getline and $line !~ /^\r?\n$/ ) {}
|
|
}
|
|
|
|
if ( $ARGV[0] and $ARGV[0] eq 'autoconf' ) {
|
|
if ( $error ) {
|
|
print "no ($error)\n";
|
|
} else {
|
|
print "yes\n";
|
|
}
|
|
|
|
exit 0;
|
|
} elsif ( $ARGV[0] and $ARGV[0] eq 'config' ) {
|
|
print "host_name $hostname" if $hostname;
|
|
|
|
print <<END;
|
|
|
|
multigraph asterisk_channels
|
|
graph_title Asterisk active channels
|
|
graph_args --base 1000 -l 0
|
|
graph_vlabel channels
|
|
graph_category voip
|
|
total.label channels
|
|
END
|
|
|
|
foreach my $channel (@CHANNELS) {
|
|
print <<END;
|
|
$channel.draw AREASTACK
|
|
$channel.label $channel channels
|
|
END
|
|
}
|
|
|
|
print <<END;
|
|
|
|
multigraph asterisk_voicemail
|
|
graph_title Asterisk voicemail messages
|
|
graph_args --base 1000 -l 0
|
|
graph_vlabel messages
|
|
graph_category voip
|
|
total.label Total messages
|
|
END
|
|
|
|
print <<END;
|
|
|
|
multigraph asterisk_meetme
|
|
graph_title Asterisk meetme statistics
|
|
graph_args --base 1000 -l 0
|
|
graph_category voip
|
|
users.label Connected users
|
|
conferences.label Active conferences
|
|
END
|
|
|
|
print <<END;
|
|
|
|
multigraph asterisk_codecs
|
|
graphs_title Asterisk channels per codec
|
|
graph_args --base 1000 -l 0
|
|
graph_vlabel channels
|
|
graph_category voip
|
|
END
|
|
|
|
foreach my $codec (@CODECS) {
|
|
print <<END;
|
|
$codec.draw AREASTACK
|
|
$codec.label $codec channels
|
|
END
|
|
}
|
|
|
|
print <<END;
|
|
other.draw AREASTACK
|
|
other.label Other known codecs
|
|
unknwon.draw AREASTACK
|
|
unknown.label Unknown codec
|
|
END
|
|
|
|
unless ( ($ENV{MUNIN_CAP_DIRTYCONFIG} || 0) == 1 ) {
|
|
exit 0;
|
|
}
|
|
}
|
|
|
|
# if we arrive here and we don't have a socket, it's time to exit.
|
|
die $error if $error;
|
|
|
|
my $channels_response = asterisk_command($socket, "core show channels");
|
|
#Channel Location State Application(Data)
|
|
#Zap/pseudo-198641660 s@frompstn:1 Rsrvd (None)
|
|
#Zap/1-1 4@frompstn:1 Up MeetMe(5500)
|
|
#2 active channels
|
|
#1 active call
|
|
|
|
my $voicemail_response = asterisk_command($socket, "voicemail show users");
|
|
#Context Mbox User Zone NewMsg
|
|
#default 1234 Example Mailbox 1
|
|
#other 1234 Company2 User 0
|
|
#2 voicemail users configured.
|
|
|
|
my $meetme_response = asterisk_command($socket, "meetme list");
|
|
#Conf Num Parties Marked Activity Creation
|
|
#5500 0001 N/A 00:00:03 Static
|
|
#* Total number of MeetMe users: 1
|
|
|
|
my $sipchannels_response = asterisk_command($socket, "sip show channels");
|
|
#Peer User/ANR Call ID Seq (Tx/Rx) Format
|
|
#192.168.1.135 yann 6902112b3e0 00101/00002 g729
|
|
#1 active SIP channel(s)
|
|
|
|
my $iaxchannels_response = asterisk_command($socket, "iax2 show channels");
|
|
#Channel Peer Username ID (Lo/Rem) Seq (Tx/Rx) Lag Jitter JitBuf Format
|
|
#IAX2/rodolphe@rodolp 10.8.53.6 rodolphe 00003/01287 00006/00004 00000ms 0148ms 0000ms gsm
|
|
#1 active IAX channel(s)
|
|
|
|
# After all the data is fetched we can proceed to process it, the
|
|
# connection can be closed as we don't need any more data.
|
|
$socket->close();
|
|
|
|
my $active_channels = 'U';
|
|
$active_channels = $1 if $channels_response =~ /\n([0-9]+) active channels?/;
|
|
|
|
print <<END;
|
|
|
|
multigraph asterisk_channels
|
|
total.value $active_channels
|
|
END
|
|
|
|
my @channels_list = split(/\r?\n/, $channels_response) if $channels_response;
|
|
foreach my $channel (@CHANNELS) {
|
|
print "$channel.value ";
|
|
print $channels_response ? scalar(grep(/^$channel\//, @channels_list)) : "U";
|
|
print "\n";
|
|
}
|
|
|
|
print "\nmultigraph asterisk_voicemail\n";
|
|
if ( !$voicemail_response or $voicemail_response =~ /no voicemail users/ ) {
|
|
print "total.value U\n";
|
|
} else {
|
|
my $messages = 0;
|
|
foreach my $line (split(/\r?\n/, $voicemail_response)) {
|
|
next unless $line =~ / ([0-9]+)$/;
|
|
$messages += $1;
|
|
}
|
|
|
|
print "total.value $messages\n";
|
|
}
|
|
|
|
print "\nmultigraph asterisk_meetme\n";
|
|
if ( !$meetme_response ) {
|
|
print <<END;
|
|
users.value U
|
|
conferences.value U
|
|
END
|
|
} else {
|
|
if ( $meetme_response =~ /No active/ ) {
|
|
print <<END;
|
|
users.value 0
|
|
conferences.value 0
|
|
END
|
|
} else {
|
|
my @meetme_list = split(/\r?\n/, $meetme_response);
|
|
|
|
my $users = pop(@meetme_list);
|
|
$users =~ s/^Total number of MeetMe users: ([0-9]+)$/$1/;
|
|
|
|
print "users.value $users\n";
|
|
print "conferences.value " . (scalar(@meetme_list)-1) . "\n";
|
|
}
|
|
}
|
|
|
|
print "\nmultigraph asterisk_codecs\n";
|
|
if ( !$sipchannels_response and !$iaxchannels_response ) {
|
|
foreach my $codec (@CODECS) {
|
|
print "$codec.value U\n";
|
|
}
|
|
print <<END;
|
|
other.value U
|
|
unknown.valeu U
|
|
END
|
|
} else {
|
|
my @results;
|
|
my ($i, $start, $unknown, $other)=(0,0,0,0);
|
|
foreach my $codec (@CODECS) {
|
|
$results[$i] = 0;
|
|
$i++;
|
|
}
|
|
|
|
# split the channels' listing and drop header and footnotes
|
|
my @sipchannels = $sipchannels_response ? split(/\r?\n/, $sipchannels_response) : ();
|
|
pop(@sipchannels); shift(@sipchannels);
|
|
my @iaxchannels = $iaxchannels_response ? split(/\r?\n/, $iaxchannels_response) : ();
|
|
pop(@iaxchannels); shift(@iaxchannels);
|
|
|
|
$i = 0;
|
|
foreach my $sipchan (@sipchannels) {
|
|
my $found = 0;
|
|
my @fields = split ' ', $sipchan;
|
|
if ($fields[4] eq '0x0') {
|
|
$unknown += 1;
|
|
next;
|
|
}
|
|
foreach my $codec (@CODECSX) {
|
|
if ($fields[4] eq "$codec") {
|
|
$results[$i] = $results[$i] + 1;
|
|
$found = 1;
|
|
last;
|
|
}
|
|
$i++;
|
|
}
|
|
if (! $found) {
|
|
$other += 1;
|
|
print STDERR "CODEC: SIP other format $fields[4]\n" if $Munin::Plugin::DEBUG;
|
|
}
|
|
}
|
|
|
|
$i = 0;
|
|
foreach my $iaxchan (@iaxchannels) {
|
|
my $found = 0;
|
|
my @fields = split ' ', $iaxchan;
|
|
|
|
if ($fields[8] eq '0x0') {
|
|
$unknown += 1;
|
|
next;
|
|
}
|
|
foreach my $codec (@CODECS) {
|
|
if ($fields[8] eq "$codec") {
|
|
$results[$i] = $results[$i] + 1;
|
|
$found = 1;
|
|
last;
|
|
}
|
|
$i++;
|
|
}
|
|
if (! $found) {
|
|
$other += 1;
|
|
print STDERR "CODEC: IAX2 other format: $fields[8]\n" if $Munin::Plugin::DEBUG;
|
|
}
|
|
}
|
|
|
|
$i = 0;
|
|
foreach my $codec (@CODECS) {
|
|
print "$codec.value $results[$i]\n";
|
|
$i++;
|
|
}
|
|
print "other.value $other\n";
|
|
print "unknown.value $unknown\n";
|
|
}
|