mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-22 14:16:00 +00:00
Merge branch 'master' of https://github.com/munin-monitoring/contrib
This commit is contained in:
commit
a2fead05ca
7 changed files with 2136 additions and 454 deletions
234
plugins/other/boinc_credit
Executable file
234
plugins/other/boinc_credit
Executable file
|
@ -0,0 +1,234 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
# -*- cperl -*-
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
boinc_credit - Munin plugin to monitor BOINC credit for a user
|
||||||
|
|
||||||
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
|
Any
|
||||||
|
|
||||||
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
|
All that should be needed is to add the following to your config:
|
||||||
|
|
||||||
|
[boinc_credit]
|
||||||
|
env.cpid 1234abcd....
|
||||||
|
|
||||||
|
Where the value is your Cross Project ID (CPID).
|
||||||
|
|
||||||
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
|
#%# family=auto contrib
|
||||||
|
#%# capabilities=autoconf
|
||||||
|
|
||||||
|
=head1 VERSION
|
||||||
|
|
||||||
|
1.0
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Paul Saunders <darac+munin@darac.org.uk>
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use lib $ENV{'MUNIN_LIBDIR'};
|
||||||
|
use Munin::Plugin;
|
||||||
|
|
||||||
|
my $CPID = $ENV{cpid};
|
||||||
|
my $STATSURL = $ENV{statsurl}
|
||||||
|
|| "http://boinc.netsoft-online.com/get_user.php?cpid=$CPID";
|
||||||
|
my $TICK = $ENV{tick} || 60; # minutes
|
||||||
|
|
||||||
|
my $ret;
|
||||||
|
if ( !eval "require XML::Simple;" ) {
|
||||||
|
$ret += "Could not load XML::Simple; ";
|
||||||
|
}
|
||||||
|
if ( !eval "require LWP::Simple;" ) {
|
||||||
|
$ret += "Could not load LWP::Simple; ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined $ARGV[0] and $ARGV[0] eq 'autoconf' ) {
|
||||||
|
|
||||||
|
# Can't auto configure at the moment.
|
||||||
|
# At least, until we can calculate CPID
|
||||||
|
print "no\n";
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $lastread;
|
||||||
|
|
||||||
|
sub save_data {
|
||||||
|
my @projdata = @_;
|
||||||
|
|
||||||
|
# Do we need to save this data?
|
||||||
|
if ( !defined $lastread or time >= $lastread + ( $TICK * 60 ) ) {
|
||||||
|
$lastread = time;
|
||||||
|
|
||||||
|
my @save_vector;
|
||||||
|
push @save_vector, $lastread;
|
||||||
|
foreach (@projdata) {
|
||||||
|
|
||||||
|
# Serialise the hash
|
||||||
|
my @tempbuf;
|
||||||
|
foreach my $key ( keys %{$_} ) {
|
||||||
|
push @tempbuf, $key . '¬' . $_->{$key};
|
||||||
|
}
|
||||||
|
push @save_vector, join( '^^', @tempbuf );
|
||||||
|
}
|
||||||
|
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 @projarray;
|
||||||
|
foreach (@save_vector) {
|
||||||
|
my $hashref;
|
||||||
|
foreach ( split /\^\^/ ) {
|
||||||
|
my ( $key, $value ) = split /¬/;
|
||||||
|
$hashref->{$key} = $value;
|
||||||
|
}
|
||||||
|
push @projarray, $hashref;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !defined $lastread or time >= ( $lastread + ( $TICK * 60 ) ) ) {
|
||||||
|
|
||||||
|
# Data is stale
|
||||||
|
|
||||||
|
eval {
|
||||||
|
|
||||||
|
# Fetch the XML
|
||||||
|
my $content;
|
||||||
|
unless ( defined( $content = LWP::Simple::get $STATSURL) ) {
|
||||||
|
die "Could not get $STATSURL";
|
||||||
|
}
|
||||||
|
my $xmlref = XML::Simple::XMLin( $content, ForceArray => 1 );
|
||||||
|
|
||||||
|
my @temparray;
|
||||||
|
foreach ( @{ $xmlref->{project} } ) {
|
||||||
|
my $temphash;
|
||||||
|
$temphash->{name} = $_->{name}[0];
|
||||||
|
$temphash->{id} = $_->{project_id}[0];
|
||||||
|
$temphash->{credit} = $_->{total_credit}[0];
|
||||||
|
$temphash->{creditfract} =
|
||||||
|
$_->{total_credit}[0] / $xmlref->{total_credit}[0];
|
||||||
|
$temphash->{totalcredit} = $xmlref->{total_credit}[0];
|
||||||
|
$temphash->{rank} = $_->{project_rank_total_credit}[0];
|
||||||
|
|
||||||
|
push @temparray, $temphash;
|
||||||
|
}
|
||||||
|
|
||||||
|
# If the above threw an error, we won't overwrite the old data
|
||||||
|
@projarray = @temparray;
|
||||||
|
|
||||||
|
1;
|
||||||
|
} or do {
|
||||||
|
print $@;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @projarray;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Project Colours from http://boinc.netsoft-online.com/e107_plugins/forum/forum_viewtopic.php?3
|
||||||
|
sub rgb($$$) {
|
||||||
|
return sprintf( '%02x%02x%02x', shift, shift, shift );
|
||||||
|
}
|
||||||
|
my %project_colour = (
|
||||||
|
'climatepredition.net' => rgb( 0, 139, 69 ),
|
||||||
|
'Predictor@Home' => rgb( 135, 206, 235 ),
|
||||||
|
'SETI@home' => rgb( 65, 105, 225 ),
|
||||||
|
'Einstein@Home' => rgb( 255, 165, 0 ),
|
||||||
|
'Rosetta@home' => rgb( 238, 130, 238 ),
|
||||||
|
'PrimeGrid' => rgb( 205, 197, 191 ),
|
||||||
|
'LHC@home' => rgb( 255, 127, 80 ),
|
||||||
|
'World Community Grid' => rgb( 250, 128, 114 ),
|
||||||
|
'BURP' => rgb( 0, 255, 127 ),
|
||||||
|
'SZTAKI Desktop Grid' => rgb( 205, 79, 57 ),
|
||||||
|
'uFluids' => rgb( 0, 0, 0 ),
|
||||||
|
'SIMAP' => rgb( 143, 188, 143 ),
|
||||||
|
'Folding@Home' => rgb( 153, 50, 204 ),
|
||||||
|
'MalariaControl' => rgb( 30, 144, 255 ),
|
||||||
|
'The Lattice Project' => rgb( 0, 100, 0 ),
|
||||||
|
'Pirates@Home' => rgb( 127, 255, 0 ),
|
||||||
|
'BBC Climate Change Experiment' => rgb( 205, 173, 0 ),
|
||||||
|
'Leiden Classical' => rgb( 140, 34, 34 ),
|
||||||
|
'SETI@home Beta' => rgb( 152, 245, 255 ),
|
||||||
|
'RALPH@Home' => rgb( 250, 240, 230 ),
|
||||||
|
'QMC@HOME' => rgb( 144, 238, 144 ),
|
||||||
|
'XtremLab' => rgb( 130, 130, 130 ),
|
||||||
|
'HashClash' => rgb( 255, 105, 180 ),
|
||||||
|
'cpdn seasonal' => rgb( 255, 255, 255 ),
|
||||||
|
'Chess960@Home Alpha' => rgb( 165, 42, 42 ),
|
||||||
|
'vtu@home' => rgb( 255, 0, 0 ),
|
||||||
|
'LHC@home alpha' => rgb( 205, 133, 63 ),
|
||||||
|
'TANPAKU' => rgb( 189, 183, 107 ),
|
||||||
|
'other' => rgb( 255, 193, 37 ),
|
||||||
|
'Rectilinear Crossing Number' => rgb( 83, 134, 139 ),
|
||||||
|
'Nano-Hive@Home' => rgb( 193, 205, 193 ),
|
||||||
|
'Spinhenge@home' => rgb( 255, 240, 245 ),
|
||||||
|
'RieselSieve' => rgb( 205, 183, 158 ),
|
||||||
|
'Project Neuron' => rgb( 139, 58, 98 ),
|
||||||
|
'RenderFarm@Home' => rgb( 210, 105, 30 ),
|
||||||
|
'Docking@Home' => rgb( 178, 223, 238 ),
|
||||||
|
'proteins@home' => rgb( 0, 0, 255 ),
|
||||||
|
'DepSpid' => rgb( 139, 90, 43 ),
|
||||||
|
'ABC@home' => rgb( 222, 184, 135 ),
|
||||||
|
'BOINC alpha test' => rgb( 245, 245, 220 ),
|
||||||
|
'WEP-M+2' => rgb( 0, 250, 154 ),
|
||||||
|
'Zivis Superordenador Ciudadano' => rgb( 255, 239, 219 ),
|
||||||
|
'SciLINC' => rgb( 240, 248, 255 ),
|
||||||
|
'APS@Home' => rgb( 205, 91, 69 ),
|
||||||
|
'PS3GRID' => rgb( 0, 139, 139 ),
|
||||||
|
'Superlink@Technion' => rgb( 202, 255, 112 ),
|
||||||
|
'BRaTS@Home' => rgb( 255, 106, 106 ),
|
||||||
|
'Cosmology@Home' => rgb( 240, 230, 140 ),
|
||||||
|
'SHA 1 Collision Search' => rgb( 255, 250, 205 ),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( defined $ARGV[0] and $ARGV[0] eq 'config' ) {
|
||||||
|
if ($ret) {
|
||||||
|
print $ret;
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
my @projdata = load_data();
|
||||||
|
print <<EOF;
|
||||||
|
graph_args --base 1000 --logarithmic
|
||||||
|
graph_vlabel Cobblestones
|
||||||
|
graph_category boinc
|
||||||
|
graph_title BOINC Total Credit
|
||||||
|
EOF
|
||||||
|
foreach ( sort { $a->{id} <=> $b->{id} } @projdata ) {
|
||||||
|
my $fieldname = 'proj' . $_->{id};
|
||||||
|
print <<EOF;
|
||||||
|
$fieldname.label $_->{name}
|
||||||
|
$fieldname.type GAUGE
|
||||||
|
$fieldname.info Total Credit for project $_->{name}
|
||||||
|
EOF
|
||||||
|
if ( exists $project_colour{ $_->{name} } ) {
|
||||||
|
print "$fieldname.colour $project_colour{$_->{name}}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save_data(@projdata);
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @projdata = load_data();
|
||||||
|
foreach ( sort { $a->{id} <=> $b->{id} } @projdata ) {
|
||||||
|
my $fieldname = 'proj' . $_->{id};
|
||||||
|
print "$fieldname.value $_->{credit}\n";
|
||||||
|
printf "$fieldname.extinfo %.2f%% of Total Credit (%.2f out of %.2f)\n",
|
||||||
|
$_->{creditfract} * 100, $_->{credit}, $_->{totalcredit};
|
||||||
|
}
|
||||||
|
save_data(@projdata);
|
||||||
|
exit 0;
|
|
@ -226,6 +226,7 @@ if ( (defined $ARGV[0]) && ($ARGV[0] eq "config") ) {
|
||||||
print "graph_category BOINC\n";
|
print "graph_category BOINC\n";
|
||||||
print "graph_args --base 1000 -l 0\n";
|
print "graph_args --base 1000 -l 0\n";
|
||||||
print "graph_vlabel BOINC applications\n";
|
print "graph_vlabel BOINC applications\n";
|
||||||
|
print "graph_total Total\n";
|
||||||
|
|
||||||
# First project is AREA, next are STACK
|
# First project is AREA, next are STACK
|
||||||
# Not nice, but fast:
|
# Not nice, but fast:
|
||||||
|
|
|
@ -37,17 +37,18 @@ Time::Local
|
||||||
|
|
||||||
This configuration section shows the defaults of the plugin:
|
This configuration section shows the defaults of the plugin:
|
||||||
|
|
||||||
[currentcost]
|
[currentcost]
|
||||||
env.device /dev/ttyUSB0
|
env.device /dev/ttyUSB0
|
||||||
env.baud 2400
|
env.baud 2400
|
||||||
env.tick 6
|
env.tick 6
|
||||||
env.currency £
|
env.currency £
|
||||||
env.rate1 13.9
|
env.rate1 13.9
|
||||||
env.rate1qty 900
|
nenv.rate1qty 900
|
||||||
env.rate2 8.2
|
env.rate2 8.2
|
||||||
env.nightrate 0
|
env.nightrate 0
|
||||||
env.nighthours 23:30-06:30
|
env.nighthours 23:30-06:30
|
||||||
env.standingcharge 0.0
|
env.standingcharge 0.0
|
||||||
|
env.metertype CC128
|
||||||
|
|
||||||
The configuration can be broken down into the following subsections:
|
The configuration can be broken down into the following subsections:
|
||||||
|
|
||||||
|
@ -101,16 +102,20 @@ The time period for which C<env.nightrate> applies. This should be of the form C
|
||||||
|
|
||||||
The standing charge in hundreths of a C<env.currency> per month. If you do not have a standing charge, set this to 0.
|
The standing charge in hundreths of a C<env.currency> per month. If you do not have a standing charge, set this to 0.
|
||||||
|
|
||||||
|
=item env.metertype
|
||||||
|
|
||||||
|
The type of the meter. Currently "CC128" and "CC02" are supported.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 MAGIC MARKERS
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
#%# family=manual contrib
|
#%# family=auto contrib
|
||||||
#%# capabilities=multigraph
|
#%# capabilities=multigraph autoconf
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
Paul Saunders L<darac@darac.org.uk>
|
Paul Saunders L<darac+munin@darac.org.uk>
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
@ -118,24 +123,25 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use utf8;
|
use utf8;
|
||||||
use Munin::Plugin;
|
use Munin::Plugin;
|
||||||
use Data::Dump qw{pp};
|
|
||||||
|
|
||||||
need_multigraph();
|
need_multigraph();
|
||||||
|
|
||||||
my $device_node = $ENV{device} || "/dev/ttyUSB0";
|
my $device_node = $ENV{device} || "/dev/ttyUSB0";
|
||||||
my $baud_rate = $ENV{baud} || "2400"; # or 9600 or 57600
|
my $baud_rate = $ENV{baud} || "2400"; # or 9600 or 57600
|
||||||
my $tick_rate = $ENV{tick} || "6";
|
my $tick_rate = $ENV{tick} || "6";
|
||||||
|
|
||||||
# Tick_Rate is how long to consider data valid for (in seconds)
|
# Tick_Rate is how long to consider data valid for (in seconds)
|
||||||
|
|
||||||
# Costs
|
# Costs
|
||||||
my $currency = $ENV{currency} || "£"; # £ or €
|
my $currency = $ENV{currency} || "£"; # £ or €
|
||||||
my $rate1 = $ENV{rate1} || "13.9"; # in pence/cents
|
my $rate1 = $ENV{rate1} || "13.9"; # in pence/cents
|
||||||
my $rate1qty = $ENV{rate1qty} || "900"; # in kWh, 0 to use fixed rate2
|
my $rate1qty = $ENV{rate1qty} || "900"; # in kWh, 0 to use fixed rate2
|
||||||
my $rate2 = $ENV{rate2} || "8.2"; # in pence/cents
|
my $rate2 = $ENV{rate2} || "8.2"; # in pence/cents
|
||||||
my $nightrate = $ENV{nightrate} || "0"; # 0 = disabled
|
my $nightrate = $ENV{nightrate} || "0"; # 0 = disabled
|
||||||
my $nighthours = $ENV{nighthours} || "23:30-06:30";
|
my $nighthours = $ENV{nighthours} || "23:30-06:30";
|
||||||
my $standingcharge = $ENV{standingcharge} || "0.0"; # pence/cents per month
|
my $standingcharge = $ENV{standingcharge} || "0.0"; # pence/cents per month
|
||||||
|
my $metertype = $ENV{metertype} || "CC128"; # or "CC02"
|
||||||
|
|
||||||
|
my $MUNIN_DEBUG = $ENV{MUNIN_DEBUG} || 0; # Set by munin-run
|
||||||
|
|
||||||
my $ret;
|
my $ret;
|
||||||
if ( !eval "require XML::Simple;" ) {
|
if ( !eval "require XML::Simple;" ) {
|
||||||
|
@ -168,6 +174,10 @@ sub save_data {
|
||||||
if ( !@lastread
|
if ( !@lastread
|
||||||
or time >= Time::Local::timelocal(@lastread) + ($tick_rate) )
|
or time >= Time::Local::timelocal(@lastread) + ($tick_rate) )
|
||||||
{
|
{
|
||||||
|
print "# Saving Data (Data is "
|
||||||
|
. ( time - Time::Local::timelocal(@lastread) )
|
||||||
|
. " seconds old)\n"
|
||||||
|
if $MUNIN_DEBUG;
|
||||||
@lastread = localtime(time);
|
@lastread = localtime(time);
|
||||||
|
|
||||||
my @save_vector;
|
my @save_vector;
|
||||||
|
@ -198,12 +208,27 @@ sub load_data {
|
||||||
{
|
{
|
||||||
|
|
||||||
# Data is stale
|
# Data is stale
|
||||||
|
print "# Data is stale ("
|
||||||
|
. ( time - Time::Local::timelocal(@lastread) )
|
||||||
|
. " seconds). Re-reading device\n"
|
||||||
|
if $MUNIN_DEBUG;
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
|
|
||||||
# Fetch the XML
|
# Fetch the XML
|
||||||
my @temparray = collect_cc128_data( $device_node, $baud_rate );
|
my @temparray;
|
||||||
|
if ( $metertype eq "CC128" ) {
|
||||||
|
@temparray = collect_cc128_data( $device_node, $baud_rate );
|
||||||
|
}
|
||||||
|
elsif ( $metertype eq "CC02" ) {
|
||||||
|
@temparray = collect_cc02_data( $device_node, $baud_rate );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die "Unknown meter type $metertype.";
|
||||||
|
}
|
||||||
|
|
||||||
# Read the time so we know whether to reset daily/monthly/yearly counters
|
# Read the time so we know whether to reset
|
||||||
|
# daily/monthly/yearly counters
|
||||||
my @now = localtime(time);
|
my @now = localtime(time);
|
||||||
my %is_new;
|
my %is_new;
|
||||||
$is_new{daily} = ( $now[3] != $lastread[3] ) ? 1 : 0;
|
$is_new{daily} = ( $now[3] != $lastread[3] ) ? 1 : 0;
|
||||||
|
@ -222,6 +247,8 @@ sub load_data {
|
||||||
if ( $is_new{$period} ) {
|
if ( $is_new{$period} ) {
|
||||||
|
|
||||||
# Start of a new period, reset the counter
|
# Start of a new period, reset the counter
|
||||||
|
print "# Start of a new $period period." .
|
||||||
|
" Resetting counter\n" if $MUNIN_DEBUG;
|
||||||
$temparray[$i]->{data}[$j]->{$period} = 0;
|
$temparray[$i]->{data}[$j]->{$period} = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -266,9 +293,11 @@ sub is_night_rate {
|
||||||
if ( $now_time >= $start_time
|
if ( $now_time >= $start_time
|
||||||
or $now_time <= $stop_time )
|
or $now_time <= $stop_time )
|
||||||
{
|
{
|
||||||
|
print "# Night rate is ACTIVE\n" if $MUNIN_DEBUG;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
print "# Night rate is enabled, but NOT active\n" if $MUNIN_DEBUG;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,34 +308,34 @@ The device will periodically output a string of XML. The string will be all on o
|
||||||
|
|
||||||
=head2 Classic format
|
=head2 Classic format
|
||||||
|
|
||||||
Note: I can't find an official spec for this format so, for now, this plugin doesn't support it.
|
As per L<http://cumbers.wordpress.com/2008/05/07/breakdown-of-currentcost-xml-output/>:
|
||||||
|
|
||||||
<msg>
|
<msg>
|
||||||
<date>
|
<date>
|
||||||
<dsb>00014</dsb>
|
<dsb>00014</dsb> days since birth
|
||||||
<hr>14</hr>
|
<hr>14</hr> the time
|
||||||
<min>07</min>
|
<min>07</min>
|
||||||
<sec>07</sec>
|
<sec>07</sec>
|
||||||
</date>
|
</date>
|
||||||
<src>
|
<src>
|
||||||
<name>CC02</name>
|
<name>CC02</name> name of this device
|
||||||
<id>03280</id>
|
<id>03280</id> communication channel for device
|
||||||
<type>1</type>
|
<type>1</type> hardware version of the device
|
||||||
<sver>0.07</sver>
|
<sver>0.07</sver> software version
|
||||||
</src>
|
</src>
|
||||||
<ch1>
|
<ch1>
|
||||||
<watts>00080</watts>
|
<watts>00080</watts> value from the first channel clamp
|
||||||
</ch1>
|
</ch1>
|
||||||
<ch2>
|
<ch2>
|
||||||
<watts>00000</watts>
|
<watts>00000</watts> value from the second channel clamp
|
||||||
</ch2>
|
</ch2>
|
||||||
<ch3>
|
<ch3>
|
||||||
<watts>00000</watts>
|
<watts>00000</watts> value from the third channel clamp
|
||||||
</ch3>
|
</ch3>
|
||||||
<tmpr>28.8</tmpr>
|
<tmpr>28.8</tmpr> current temperature (degrees celsius)
|
||||||
<hist>
|
<hist>
|
||||||
<hrs>
|
<hrs>
|
||||||
<h02>000.0</h02>
|
<h02>000.0</h02> total Kwh used in 2 hour blocks
|
||||||
<h04>000.1</h04>
|
<h04>000.1</h04>
|
||||||
<h06>000.1</h06>
|
<h06>000.1</h06>
|
||||||
<h08>000.0</h08>
|
<h08>000.0</h08>
|
||||||
|
@ -321,7 +350,7 @@ Note: I can't find an official spec for this format so, for now, this plugin doe
|
||||||
<h26>000.0</h26>
|
<h26>000.0</h26>
|
||||||
</hrs>
|
</hrs>
|
||||||
<days>
|
<days>
|
||||||
<d01>0000</d01>
|
<d01>0000</d01> total Kwh used per day(s)
|
||||||
<d02>0000</d02>
|
<d02>0000</d02>
|
||||||
<d03>0000</d03>
|
<d03>0000</d03>
|
||||||
<d04>0000</d04>
|
<d04>0000</d04>
|
||||||
|
@ -354,7 +383,7 @@ Note: I can't find an official spec for this format so, for now, this plugin doe
|
||||||
<d31>0000</d31>
|
<d31>0000</d31>
|
||||||
</days>
|
</days>
|
||||||
<mths>
|
<mths>
|
||||||
<m01>0000</m01>
|
<m01>0000</m01> total Kwh used per month(s)
|
||||||
<m02>0000</m02>
|
<m02>0000</m02>
|
||||||
<m03>0000</m03>
|
<m03>0000</m03>
|
||||||
<m04>0000</m04>
|
<m04>0000</m04>
|
||||||
|
@ -368,7 +397,7 @@ Note: I can't find an official spec for this format so, for now, this plugin doe
|
||||||
<m12>0000</m12>
|
<m12>0000</m12>
|
||||||
</mths>
|
</mths>
|
||||||
<yrs>
|
<yrs>
|
||||||
<y1>0000000</y1>
|
<y1>0000000</y1> total Kwh used per year(s)
|
||||||
<y2>0000000</y2>
|
<y2>0000000</y2>
|
||||||
<y3>0000000</y3>
|
<y3>0000000</y3>
|
||||||
<y4>0000000</y4>
|
<y4>0000000</y4>
|
||||||
|
@ -419,15 +448,18 @@ sub collect_cc128_data {
|
||||||
my %seen_sensors;
|
my %seen_sensors;
|
||||||
|
|
||||||
while (<$ttydev>) {
|
while (<$ttydev>) {
|
||||||
|
print "# Read from device: $_\n" if $MUNIN_DEBUG;
|
||||||
if (m{(<msg>.*</msg>)}) {
|
if (m{(<msg>.*</msg>)}) {
|
||||||
my $xmlref = XML::Simple::XMLin( $1, KeepRoot => 1 );
|
my $xmlref = XML::Simple::XMLin( $1, KeepRoot => 1 );
|
||||||
|
|
||||||
my $sensor = $xmlref->{msg}->{sensor};
|
my $sensor = $xmlref->{msg}->{sensor};
|
||||||
|
print "# Parsing Sensor $sensor\n" if $MUNIN_DEBUG;
|
||||||
next unless defined $sensor;
|
next unless defined $sensor;
|
||||||
if ( defined $seen_sensors{$sensor} ) {
|
if ( defined $seen_sensors{$sensor} ) {
|
||||||
|
|
||||||
# We've seen this sensor before.
|
# We've seen this sensor before.
|
||||||
# Time to stop reading data
|
# Time to stop reading data
|
||||||
|
print "# Hello again, Sensor $sensor\n" if $MUNIN_DEBUG;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
$seen_sensors{$sensor} = 1;
|
$seen_sensors{$sensor} = 1;
|
||||||
|
@ -436,6 +468,56 @@ sub collect_cc128_data {
|
||||||
$temphash->{sensor} = $sensor;
|
$temphash->{sensor} = $sensor;
|
||||||
$temphash->{temp} = $xmlref->{msg}->{tmpr};
|
$temphash->{temp} = $xmlref->{msg}->{tmpr};
|
||||||
my @temparr;
|
my @temparr;
|
||||||
|
foreach my $key ( keys %{ $xmlref->{msg} } ) {
|
||||||
|
if ( $key =~ /ch(\d+)/ ) {
|
||||||
|
my $channel = $1;
|
||||||
|
my $unit = ( keys %{ $xmlref->{msg}->{"ch$channel"} } )[0];
|
||||||
|
my $val = $xmlref->{msg}->{"ch$channel"}->{$unit};
|
||||||
|
print "# Channel $channel, Unit $unit, Value $val\n"
|
||||||
|
if $MUNIN_DEBUG;
|
||||||
|
push @temparr,
|
||||||
|
{
|
||||||
|
"channel" => $channel,
|
||||||
|
"unit" => $unit,
|
||||||
|
"value" => $val
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$temphash->{data} = \@temparr;
|
||||||
|
|
||||||
|
push @cc_data_arr, $temphash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close($ttydev);
|
||||||
|
|
||||||
|
return @cc_data_arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub collect_cc02_data {
|
||||||
|
# Function supplied by David Edmondson <dme@dme.org>
|
||||||
|
|
||||||
|
# Read data from the serial port
|
||||||
|
my ( $port, $baud ) = @_;
|
||||||
|
|
||||||
|
my $tty = Device::SerialPort->new($port) || die "Can't open $port: $!";
|
||||||
|
$tty->baudrate($baud) || die "Can't set serial baudrate";
|
||||||
|
$tty->parity("none") || die "Can't set serial parity";
|
||||||
|
$tty->databits(8) || die "Can't set serial databits";
|
||||||
|
$tty->handshake("none") || die "Can't set serial handshake";
|
||||||
|
$tty->write_settings || die "Can't set serial parameters";
|
||||||
|
|
||||||
|
open( my $ttydev, "<", $port ) || die "Can't open $port: $?";
|
||||||
|
|
||||||
|
my @cc_data_arr;
|
||||||
|
|
||||||
|
while (<$ttydev>) {
|
||||||
|
if (m{(<msg>.*</msg>)}) {
|
||||||
|
my $xmlref = XML::Simple::XMLin( $1, KeepRoot => 1 );
|
||||||
|
|
||||||
|
my $temphash;
|
||||||
|
$temphash->{sensor} = 0; # Only one sensor.
|
||||||
|
$temphash->{temp} = $xmlref->{msg}->{tmpr};
|
||||||
|
my @temparr;
|
||||||
foreach my $key ( keys %{ $xmlref->{msg} } ) {
|
foreach my $key ( keys %{ $xmlref->{msg} } ) {
|
||||||
if ( $key =~ /ch(\d+)/ ) {
|
if ( $key =~ /ch(\d+)/ ) {
|
||||||
my $channel = $1;
|
my $channel = $1;
|
||||||
|
@ -452,6 +534,8 @@ sub collect_cc128_data {
|
||||||
$temphash->{data} = \@temparr;
|
$temphash->{data} = \@temparr;
|
||||||
|
|
||||||
push @cc_data_arr, $temphash;
|
push @cc_data_arr, $temphash;
|
||||||
|
|
||||||
|
last;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close($ttydev);
|
close($ttydev);
|
||||||
|
@ -475,7 +559,7 @@ if ( defined $ARGV[0] and $ARGV[0] eq 'config' ) {
|
||||||
}
|
}
|
||||||
elsif ( $unit != $key->{unit} ) {
|
elsif ( $unit != $key->{unit} ) {
|
||||||
print STDERR
|
print STDERR
|
||||||
"Conflicting units ($unit and $key->{unit}) on sensor $datum->{sensor}";
|
"# Conflicting units ($unit and $key->{unit}) on sensor $datum->{sensor}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,9 +596,10 @@ ${fieldname}_n.type GAUGE
|
||||||
${fieldname}_n.min 0
|
${fieldname}_n.min 0
|
||||||
${fieldname}_t.cdef ${fieldname}_n,UN,${fieldname},${fieldname},IF,3600,TRENDNAN
|
${fieldname}_t.cdef ${fieldname}_n,UN,${fieldname},${fieldname},IF,3600,TRENDNAN
|
||||||
EOF
|
EOF
|
||||||
} else {
|
}
|
||||||
print "${fieldname}_t.cdef ${fieldname},3600,TRENDNAN\n";
|
else {
|
||||||
}
|
print "${fieldname}_t.cdef ${fieldname},3600,TRENDNAN\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Output the Root cumulative graph
|
# Output the Root cumulative graph
|
||||||
|
|
|
@ -1,9 +1,44 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
: <<=cut
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
sa-learn - Munin plugin to monitor spamassasin bayes database size
|
||||||
|
|
||||||
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
|
Any server running spamassassin
|
||||||
|
|
||||||
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
|
This plugin assumes your Spamassassin database is in /var/lib/MailScanner.
|
||||||
|
If it's elsewhere (or you want to use a different database) you will need
|
||||||
|
a configuration such as:
|
||||||
|
|
||||||
|
[sa-learn]
|
||||||
|
env.BayesDir /path/to/bayes/directory/
|
||||||
|
user mail
|
||||||
|
|
||||||
|
(where 'user mail' refers to a user that can read the database).
|
||||||
|
|
||||||
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
#%# family=contrib
|
#%# family=contrib
|
||||||
|
|
||||||
|
=head1 VERSION
|
||||||
|
|
||||||
|
2
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Paul Saunders L<darac+munin@darac.org.uk>
|
||||||
|
|
||||||
|
=cut
|
||||||
|
#'
|
||||||
|
|
||||||
case $1 in
|
case $1 in
|
||||||
config)
|
config)
|
||||||
cat <<'EOM'
|
cat <<'EOM'
|
||||||
graph_title SA-Learn Magic
|
graph_title SA-Learn Magic
|
||||||
graph_vlabel Count
|
graph_vlabel Count
|
||||||
graph_args --base 1000 -l 0
|
graph_args --base 1000 -l 0
|
||||||
|
@ -15,26 +50,26 @@ ham.type GAUGE
|
||||||
tokens.label Num Tokens
|
tokens.label Num Tokens
|
||||||
tokens.type GAUGE
|
tokens.type GAUGE
|
||||||
EOM
|
EOM
|
||||||
exit 0;;
|
exit 0;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
## Print values
|
## Print values
|
||||||
BayesDir=${BayesDir:-/var/lib/MailScanner}
|
BayesDir=${BayesDir:-/var/lib/MailScanner}
|
||||||
|
|
||||||
sa-learn --dbpath $BayesDir --dump magic 2>/dev/null | while read line
|
sa-learn --dbpath $BayesDir/ --dump magic 2>/dev/null | while read line
|
||||||
do
|
do
|
||||||
case "$line" in
|
case "$line" in
|
||||||
*nspam*)
|
*nspam*)
|
||||||
echo -n "spam.value "
|
echo -n "spam.value "
|
||||||
echo $line | awk '{print $3}'
|
echo $line | awk '{print $3}'
|
||||||
;;
|
;;
|
||||||
*nham*)
|
*nham*)
|
||||||
echo -n "ham.value "
|
echo -n "ham.value "
|
||||||
echo $line | awk '{print $3}'
|
echo $line | awk '{print $3}'
|
||||||
;;
|
;;
|
||||||
*ntokens*)
|
*ntokens*)
|
||||||
echo -n "tokens.value "
|
echo -n "tokens.value "
|
||||||
echo $line | awk '{print $3}'
|
echo $line | awk '{print $3}'
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
File diff suppressed because it is too large
Load diff
67
plugins/other/xfs_frag
Executable file
67
plugins/other/xfs_frag
Executable file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
: <<=cut
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
xfs_frag - Munin plugin to monitor the fragmentation level on your XFS filesystems
|
||||||
|
|
||||||
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
|
Any machine with an XFS file system.
|
||||||
|
|
||||||
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
|
None, generally, but you may want to run as root and set a timeout.
|
||||||
|
|
||||||
|
[xfs_frag]
|
||||||
|
user root
|
||||||
|
timeout 90
|
||||||
|
|
||||||
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
|
#%# family=auto contrib
|
||||||
|
#%# capabilities=
|
||||||
|
|
||||||
|
=head1 VERSION
|
||||||
|
|
||||||
|
1
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Paul Saunders L<darac+munin@darac.org.uk>
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
declare -a ARRY
|
||||||
|
shopt -s nocasematch
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
config)
|
||||||
|
cat <<'EOF'
|
||||||
|
graph_title XFS fragmentation
|
||||||
|
graph_vlabel Percent
|
||||||
|
graph_category disk
|
||||||
|
EOF
|
||||||
|
cat /etc/mtab | awk '{print $2 " " $3}' | while read LINE
|
||||||
|
do
|
||||||
|
ARRY=($LINE)
|
||||||
|
if [[ ${ARRY[1]} =~ xfs ]]; then
|
||||||
|
FIELDNAME=$(echo ${ARRY[0]} | sed 's/^[^A-Za-z_]/_/; s/[^A-Za-z0-9_]/_/g')
|
||||||
|
echo "$FIELDNAME.label ${ARRY[0]}"
|
||||||
|
echo "$FIELDNAME.type GAUGE"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cat /etc/mtab | awk '{print $2 " " $3 " " $1}' | while read LINE
|
||||||
|
do
|
||||||
|
ARRY=($LINE)
|
||||||
|
if [[ ${ARRY[1]} =~ xfs ]]; then
|
||||||
|
FIELDNAME=$(echo ${ARRY[0]} | sed 's/^[^A-Za-z_]/_/; s/[^A-Za-z0-9_]/_/g')
|
||||||
|
FRAG=$(xfs_db -c frag -r ${ARRY[2]} | sed 's/.*fragmentation factor \(.*\)%.*/\1/')
|
||||||
|
echo $FIELDNAME.value $FRAG
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
|
@ -45,7 +45,7 @@ Warnings are sent if your estimated allowance drops below 25% of your cap and if
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
Paul Saunders L<darac@darac.org.uk>
|
Paul Saunders L<darac+munin@darac.org.uk>
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
@ -55,13 +55,15 @@ use warnings;
|
||||||
use lib $ENV{'MUNIN_LIBDIR'};
|
use lib $ENV{'MUNIN_LIBDIR'};
|
||||||
use Munin::Plugin;
|
use Munin::Plugin;
|
||||||
use Data::Dump qw(pp);
|
use Data::Dump qw(pp);
|
||||||
|
use Time::Local;
|
||||||
|
|
||||||
my $ret = undef;
|
my $ret = undef;
|
||||||
|
|
||||||
# Load modules like so
|
# Load modules like so
|
||||||
if ( !eval "require zenus;" ) {
|
if ( !eval "require zenus;" ) {
|
||||||
$ret =
|
$ret =
|
||||||
"Could not load zenus. Get it from http://www.rachaelandtom.info/zenus";
|
"Could not load zenus. Get it from http://www.rachaelandtom.info/zenus\n";
|
||||||
|
$ret .= "(BTW, \@INC is: " . join( ', ', @INC ) . ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $USER = $ENV{user};
|
my $USER = $ENV{user};
|
||||||
|
@ -178,24 +180,30 @@ if ( defined $ARGV[0] and $ARGV[0] eq "config" ) {
|
||||||
print $ret;
|
print $ret;
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
my $data = load_data();
|
my $data = load_data();
|
||||||
my $cap = sprintf( "%.3f", $data->{avail} );
|
my $cap = sprintf( "%.3f", $data->{avail} );
|
||||||
my $warn = sprintf( "%.3f", $cap * 0.25 );
|
my $warn = sprintf( "%.3f", $cap * 0.25 );
|
||||||
my $crit = sprintf( "%.3f", $cap * 0.1 );
|
my $crit = sprintf( "%.3f", $cap * 0.1 );
|
||||||
|
my $datestr = scalar( localtime($lastread) );
|
||||||
print <<EOF;
|
print <<EOF;
|
||||||
graph_args --base 1000
|
graph_args --base 1000
|
||||||
graph_vlabel GBytes
|
graph_vlabel GBytes out (-) / in (+)
|
||||||
graph_category Network
|
graph_category Network
|
||||||
graph_title Zen Broadband Usage
|
graph_title Zen Broadband Usage
|
||||||
graph_info Usage of your Zen Broadband account: $data->{name}
|
graph_info Usage of your Zen Broadband account: $data->{name}
|
||||||
download.label Downloaded
|
|
||||||
download.type GAUGE
|
|
||||||
download.info Amount of data downloaded (Limit is $cap GB)
|
|
||||||
download.draw AREA
|
|
||||||
upload.label Uploaded
|
upload.label Uploaded
|
||||||
upload.type GAUGE
|
upload.type GAUGE
|
||||||
upload.info Amount of data uploaded (No upper limit)
|
upload.info Amount of data uploaded (No upper limit)
|
||||||
upload.draw AREA
|
upload.draw AREA
|
||||||
|
upload.graph no
|
||||||
|
upload.colour 00CC00EE
|
||||||
|
download.label Transfer
|
||||||
|
download.type GAUGE
|
||||||
|
download.info Amount of data downloaded (Limit is $cap GB)
|
||||||
|
download.draw AREA
|
||||||
|
download.extinfo Last Read was $datestr
|
||||||
|
download.negative upload
|
||||||
|
download.colour 00CC00EE
|
||||||
allowance.label Allowance
|
allowance.label Allowance
|
||||||
allowance.type GAUGE
|
allowance.type GAUGE
|
||||||
allowance.info Amount of data you are allowed to download this month
|
allowance.info Amount of data you are allowed to download this month
|
||||||
|
@ -214,7 +222,7 @@ overrate.info Rate at which you're downloading beyond the sustainable rate
|
||||||
overrate.draw LINE1
|
overrate.draw LINE1
|
||||||
overrate.min 0
|
overrate.min 0
|
||||||
overrate.warning 0:
|
overrate.warning 0:
|
||||||
graph_order download upload allowance remaining overrate
|
#graph_order download upload allowance remaining overrate
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
save_data($data);
|
save_data($data);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue