mirror of
https://github.com/munin-monitoring/contrib.git
synced 2018-11-08 00:59:34 +01:00
330 lines
9.8 KiB
Perl
Executable File
330 lines
9.8 KiB
Perl
Executable File
#!/usr/bin/perl
|
||
# -*- cperl -*-
|
||
|
||
=head1 NAME
|
||
|
||
zenus_ - Munin plugin to monitor the usage of a Zen Internet Broadband account
|
||
|
||
=head1 APPLICABLE SYSTEMS
|
||
|
||
Any (Though most likely those connected to a Zen Internet Broadband connection)
|
||
|
||
=head1 CONFIGURATION
|
||
|
||
This plugin requires the C<zenus> module to be installed. This can be fetched
|
||
from L<http://www.rachaelandtom.info/zenus>.
|
||
|
||
Tip: To see if it's already setup correctly, just run this plugin
|
||
with the parameter 'autoconf'. If you get a "yes", everything should
|
||
work like a charm already.
|
||
|
||
This configuration section shows the defaults of the plugin:
|
||
|
||
[zenus_*]
|
||
env.user
|
||
env.pass
|
||
env.account
|
||
env.tick 60
|
||
|
||
You must supply C<env.user> and C<env.pass>. These will be your PORTAL username and password, NOT your ADSL account details.
|
||
|
||
You may either specify the account to report through C<env.account> (e.g. zen12345@zen) or by naming the symlink in your plugins directory (e.g. zenus_zen12345_zen). If no account is specified, the default account will be chosen.
|
||
|
||
C<env.tick> specifies how often (in minutes) the data will be refreshed from upstream. This is to avoid hitting the Zen servers every five minutes. Data is cached between runs.
|
||
|
||
=head1 INTERPRETATION
|
||
|
||
The plugin shows the amount of data downloaded and uploaded since the beginning of the chargable period (i.e. the calendar month). A thick line shows the current download allowance (planned plus banked). A thinner line shows the estimated amount remaining at the end of the month. If you are estimated to exceed your allowance before the end of the month, a second line appears showing the rate at which you're downloading beyond the sustainable rate.
|
||
|
||
Warnings are sent if your estimated allowance drops below 25% of your cap and if the overspeed rate rises above zero. Critical warnings are sent if your estimated allowance drops below 10% of your cap.
|
||
|
||
=head1 MAGIC MARKERS
|
||
|
||
#%# family=auto contrib
|
||
#%# capabilities=autoconf suggest
|
||
|
||
=head1 AUTHOR
|
||
|
||
Paul Saunders L<darac+munin@darac.org.uk>
|
||
|
||
=cut
|
||
|
||
use strict;
|
||
use warnings;
|
||
|
||
use lib $ENV{'MUNIN_LIBDIR'};
|
||
use Munin::Plugin;
|
||
use Data::Dump qw(pp);
|
||
use Time::Local;
|
||
|
||
my $ret = undef;
|
||
|
||
# Load modules like so
|
||
if ( !eval "require zenus;" ) {
|
||
$ret =
|
||
"Could not load zenus. Get it from http://www.rachaelandtom.info/zenus\n";
|
||
$ret .= "(BTW, \@INC is: " . join( ', ', @INC ) . ")\n";
|
||
}
|
||
|
||
my $CAN_LOG = 1;
|
||
if ( !eval "require Log::Log4perl;" ) {
|
||
$CAN_LOG = 0;
|
||
}
|
||
elsif ( !eval "require Log::Dispatch::FileRotate;" ) {
|
||
$CAN_LOG = 0;
|
||
}
|
||
|
||
my $USER = $ENV{user};
|
||
my $PASS = $ENV{pass};
|
||
my $ACCT = $ENV{account} || "";
|
||
my $TICK = $ENV{tick} || 60; # minutes
|
||
|
||
my @name_fields = split /_/, $0;
|
||
if ( scalar @name_fields == 3 ) {
|
||
if ( $name_fields[1] eq '' or $name_fields[2] eq '' ) {
|
||
print "Misconfigured symlink. See Documentation\n";
|
||
exit 1;
|
||
}
|
||
else {
|
||
$ACCT = $name_fields[1] . '@' . $name_fields[2];
|
||
}
|
||
}
|
||
|
||
# If there are more or less than 3 components to the filename,
|
||
# we just carry on with the default account
|
||
|
||
if ($CAN_LOG) {
|
||
my $loggerconf = q(
|
||
log4perl.rootLogger = DEBUG, LOG1
|
||
log4perl.appender.LOG1 = Log::Dispatch::FileRotate
|
||
log4perl.appender.LOG1.filename = /var/log/munin/zenus.log
|
||
log4perl.appender.LOG1.mode = append
|
||
log4perl.appender.LOG1.DatePattern = yyyy-ww
|
||
log4perl.appender.LOG1.layout = Log::Log4perl::Layout::PatternLayout
|
||
log4perl.appender.LOG1.layout.ConversionPattern = %d %p %c: %m%n
|
||
);
|
||
Log::Log4perl::init( \$loggerconf );
|
||
our $logger = Log::Log4perl->get_logger($ACCT);
|
||
} else {
|
||
our $logger = "";
|
||
}
|
||
|
||
my $lastread;
|
||
|
||
sub save_data {
|
||
my $hashref = shift;
|
||
my $update_lastread = shift || 1;
|
||
|
||
# Do we need to save this info
|
||
if ( !defined $lastread or time > $lastread + ( $TICK * 60 ) ) {
|
||
|
||
$lastread = time if $update_lastread;
|
||
print "# Updating LastRead to " . localtime($lastread) . "\n";
|
||
|
||
my @save_vector;
|
||
push @save_vector, $lastread;
|
||
|
||
# Push the hash values on to the array
|
||
foreach ( keys %$hashref ) {
|
||
push @save_vector, $_ . '<27>' . $hashref->{$_};
|
||
}
|
||
|
||
$::logger->info(
|
||
"Saving Data (LastRead is " . localtime($lastread) . "\n" )
|
||
if $CAN_LOG;
|
||
|
||
#Go!
|
||
save_state(@save_vector);
|
||
}
|
||
}
|
||
|
||
sub load_data {
|
||
|
||
# Bring the data back in
|
||
my @save_vector = restore_state();
|
||
|
||
# Read the timestamp. Do we need to refresh the data?
|
||
$lastread = shift @save_vector;
|
||
|
||
my $hashref;
|
||
foreach (@save_vector) {
|
||
my ( $key, $value ) = split /<2F>/;
|
||
$hashref->{$key} = $value;
|
||
}
|
||
my $force_save = 0;
|
||
if ( !defined $lastread or time >= ( $lastread + ( $TICK * 60 ) ) ) {
|
||
|
||
# Data is stale
|
||
print "# Data is " . ( time - $lastread ) . " seconds old\n";
|
||
$::logger->info( "Data is " . ( time - $lastread ) . " seconds old\n" )
|
||
if $CAN_LOG;
|
||
|
||
if ( exists $hashref->{backoff} ) {
|
||
if ( time <= $hashref->{backoff} ) {
|
||
|
||
# We're in a back-off period
|
||
print "# Back-off in effect\n";
|
||
$::logger->info("Back-off in effect\n") if $CAN_LOG;
|
||
exit 0;
|
||
}
|
||
else {
|
||
# We've just come out of a back-off period
|
||
print "# Back-off ends\n";
|
||
$::logger->info("Back-off ends\n") if $CAN_LOG;
|
||
delete $hashref->{backoff};
|
||
}
|
||
}
|
||
elsif ( !defined $lastread ) {
|
||
|
||
# Initial run. Carry on
|
||
print "# Initial Run\n";
|
||
my $force_save = 1;
|
||
}
|
||
elsif ( time >= ( $lastread + ( 120 * 60 ) ) ) {
|
||
|
||
# Data is VERY Stale. Assume a login issue and
|
||
# back-off for 24 hours.
|
||
print "# Starting Back-Off\n";
|
||
$hashref->{backoff} = time + ( 24 * 60 * 60 );
|
||
$::logger->info(
|
||
"Backing off until " . localtime( $hashref->{backoff} ) . "\n" )
|
||
if $CAN_LOG;
|
||
save_data( $hashref, 0 );
|
||
exit 1;
|
||
}
|
||
|
||
print "# REFRESHING DATA\n";
|
||
$::logger->info("Refreshing Data\n") if $CAN_LOG;
|
||
my $temphash;
|
||
eval {
|
||
zenus::login( $USER, $PASS );
|
||
|
||
(
|
||
$temphash->{name}, $temphash->{used},
|
||
$temphash->{avail}, $temphash->{per},
|
||
$temphash->{uploadAmount}
|
||
) = zenus::getUsage($ACCT);
|
||
(
|
||
$temphash->{dayofmonth}, $temphash->{permonth},
|
||
$temphash->{avedaily}, $temphash->{maxdaily},
|
||
$temphash->{daysremain}, $temphash->{estusage},
|
||
$temphash->{daysinmonth}
|
||
)
|
||
= zenus::estimateRemaining( $temphash->{used},
|
||
$temphash->{avail} );
|
||
$hashref = $temphash;
|
||
1;
|
||
|
||
# If zenus threw an error we won't copy the data over,
|
||
# so we still use the cached data.
|
||
} or do {
|
||
print "# Zenus Error $@\n";
|
||
};
|
||
}
|
||
else {
|
||
print "# Using existing data\n";
|
||
$::logger->info("Using existing data\n") if $CAN_LOG;
|
||
}
|
||
save_data( $hashref, 1 ) if $force_save;
|
||
return $hashref;
|
||
|
||
}
|
||
|
||
if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) {
|
||
if ($ret) {
|
||
print "no ($ret)\n";
|
||
} else {
|
||
print "yes\n";
|
||
}
|
||
exit 0;
|
||
}
|
||
|
||
if ( defined $ARGV[0] and $ARGV[0] eq "suggest" ) {
|
||
if ( defined $USER and defined $PASS ) {
|
||
zenus::login( $USER, $PASS );
|
||
for my $account ( zenus::getAccounts() ) {
|
||
if ( defined $account ) {
|
||
$account =~ s/\@/_/g;
|
||
print "$account\n";
|
||
}
|
||
}
|
||
}
|
||
exit 0;
|
||
}
|
||
|
||
if ( defined $ARGV[0] and $ARGV[0] eq "config" ) {
|
||
if ($ret) {
|
||
print $ret;
|
||
exit 1;
|
||
}
|
||
my $data = load_data();
|
||
my $datestr = scalar( localtime($lastread) );
|
||
print <<EOF;
|
||
graph_args --base 1000
|
||
graph_vlabel GBytes out (-) / in (+)
|
||
graph_category network
|
||
graph_title Zen Broadband Usage ($ACCT)
|
||
graph_info Usage of your Zen Broadband account: $data->{name}
|
||
upload.label Uploaded
|
||
upload.type GAUGE
|
||
upload.info Amount of data uploaded (No upper limit)
|
||
upload.draw AREA
|
||
upload.graph no
|
||
upload.colour 00CC00EE
|
||
download.label Transfer
|
||
download.type GAUGE
|
||
download.draw AREA
|
||
download.extinfo Last Read was $datestr
|
||
download.negative upload
|
||
download.colour 00CC00EE
|
||
EOF
|
||
if ( defined $data->{avail} and $data->{avail} != 0 ) {
|
||
my $cap = sprintf( "%.3f", $data->{avail} );
|
||
my $warn = sprintf( "%.3f", $cap * 0.25 );
|
||
my $crit = sprintf( "%.3f", $cap * 0.1 );
|
||
print <<EOF;
|
||
download.info Amount of data downloaded (Limit is $cap GB)
|
||
allowance.label Allowance
|
||
allowance.type GAUGE
|
||
allowance.info Amount of data you are allowed to download this month
|
||
allowance.draw LINE2
|
||
remaining.label Est'd Remaining
|
||
remaining.type GAUGE
|
||
remaining.info Estimated amount of data transfer remaining at the end of the month
|
||
remaining.draw LINE1
|
||
remaining.min 0
|
||
remaining.max $cap
|
||
remaining.warning $warn:
|
||
remaining.critical $crit:
|
||
overrate.label Overspeed Rate
|
||
overrate.type GAUGE
|
||
overrate.info Rate at which you're downloading beyond the sustainable rate
|
||
overrate.draw LINE1
|
||
overrate.min 0
|
||
overrate.warning 0:
|
||
EOF
|
||
}
|
||
else {
|
||
# Probably an unlimited contract
|
||
print "download.info Amount of data downloaded\n";
|
||
}
|
||
|
||
save_data($data);
|
||
exit 0;
|
||
}
|
||
|
||
my $data = load_data();
|
||
print "upload.value " . $data->{uploadAmount} . "\n";
|
||
print "download.value " . $data->{used} . "\n";
|
||
if ( defined $data->{avail} and $data->{avail} != 0 ) {
|
||
print "allowance.value " . $data->{avail} . "\n";
|
||
my $remain = $data->{avail} - $data->{estusage};
|
||
$remain = 0 if $remain < 0;
|
||
print "remaining.value " . $remain . "\n";
|
||
my $overrate = $data->{avedaily} - $data->{maxdaily};
|
||
$overrate = 0 if $overrate < 0;
|
||
print "overrate.value " . $overrate . "\n";
|
||
}
|
||
save_data($data);
|
||
exit 0;
|