1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-21 18:41:03 +00:00
Munin-Contrib/plugins/power/apcupsd_ww
Lars Kruse 72eeb4155f spelling: change "licenced" to "licensed"
Even though "licenced" is proper (British English) spelling,
"spellcheck" complains about it (probably being focused on American
English).
The change should just clean up the output of the spelling linter and
should not be interpreted as a language preference.
Sorry, (British) folks!
2020-08-25 17:44:16 +02:00

342 lines
8.8 KiB
Perl
Executable file

#!/usr/bin/perl -w
#
# Plugin to monitor apcupsd via apcaccess
#
# Version 1.3
#
# Copyright (C) 2005-2008 Behan Webster <behanw AT websterwood DOT com>
# Licensed under GPL 2.0
#
# Written by: Behan Webster <behanw AT websterwood DOT com>
# German translation by: Bianco Veigel <bianco.veigel AT zivillian DOT de>
#
#%# family=auto
#%# capabilities=autoconf
use strict;
use warnings;
use vars qw(%attrs %data %num);
my $apcaccess='/sbin/apcaccess';
#$apcaccess='/home/behanw/bin/apcaccess';
my $config='/etc/munin/plugin-conf.d/apcupsd_ww';
my $language = $ENV{LANG} || 'en';
# Example apcaccess output
# KEY : VALUE
#
# UPSNAME : Elfhild
# MODEL : SMART-UPS 1400 RM XL
# STATUS : ONLINE
# LINEV : 123.5 Volts
# LOADPCT : 24.9 Percent Load Capacity
# BCHARGE : 100.0 Percent
# TIMELEFT : 63.0 Minutes
# OUTPUTV : 123.5 Volts
# ITEMP : 39.1 C Internal
# BATTV : 54.5 Volts
# NOMOUTV : 115 Volts
# NOMBATTV : 48.0 Volts
# Possible values to graph in munin
# Only the ones which are available will be graphed
%attrs = (
# APCACCESS_KEY => {
# name => 'attribute_name',
# label => {
# en => 'English title',
# de => 'Titel in Deutsch',
# fr => 'titre en Francais',
# },
# type => 'name_of_functio_for_type', # Default is 'num'
# # Can use one value, or list of values. If the first value can't be used, try the next.
# # KEY Key from apcaccess
# # num,num,num Specify a list of possible nominal values to guess from
# # num Specify fixed nominal value
# nominal => [ 'KEY', '100' ],
# # KEY Key from apcaccess
# # +-num% Calculate percentage min:max from nominal value
# # +-num Calculate min:max from nominal value
# # -num:+num Calculate min:max from nominal value
# # num:num Specify fixed min:max values
# # num or :num Specify fixed max value
# # num: Specify fixed min value
# warning => [ 'KEY:KEY', '+-10%', '-10:+15' ],
# critical => [ 'KEY:KEY', '+-10%', '-10:+15' ],
# },
BCHARGE => { # BCHARGE : 100.0 Percent
name => 'battery',
label => {
en => 'Percent battery charge',
de => 'Batterieladung in Prozent',
},
warning => '33:', # %
critical => '5:', # %
},
LOADPCT => { # LOADPCT : 28.6 Percent Load Capacity
name => 'upsload',
label => {
en => 'Percent load capacity',
de => 'Auslastung in Prozent',
},
warning => '75', # %
critical => '90', # %
},
TIMELEFT => { # TIMELEFT : 17.0 Minutes
name => 'timeleft',
label => {
en => 'Minutes of run time',
de => 'Akkulaufzeit in Minuten',
},
warning => '5:', # mins
critical => [ 'DLOWBATT:', '2:' ], # DLOWBATT : 02 Minutes
},
LINEV => { # LINEV : 121.5 Volts
name => 'linevolts',
label => {
en => 'Line voltage',
de => 'Eingangsspannung',
},
nominal => [ 'NOMINV', 'NOMOUTV', '115,230' ], # NA=115V, Europe=230V
warning => [ '+-10%', '108:128' ],
critical => [ 'LOTRANS:HITRANS', '+-15%', '104:132' ],
},
BATTV => { # BATTV : 27.7 Volts
name => 'batteryvolts',
label => {
en => 'Battery voltage',
de => 'Batteriespannung',
},
nominal => [ 'NOMBATTV', '12,24,48' ], # NOMBATTV : 48.0 Volts
warning => '-5%:+15%',
critical => '-10%:+25%',
},
OUTPUTV => { # OUTPUTV : 122.2 Volts
name => 'outputvolts',
label => {
en => 'Output voltage',
de => 'Ausgangsspannung',
},
nominal => [ 'NOMOUTV', '115,230' ], # NOMOUTV : 115 Volts
warning => [ '+-10%', '108:128' ],
critical => [ 'LOTRANS:HITRANS', '+-15%', '104:132' ],
},
ITEMP => { # ITEMP : 44.1 C Internal
name => 'temperature',
label => {
en => 'UPS temperature',
de => 'USV Temperatur',
},
warning => 50, # C
critical => 60, # C
},
LINEFAIL => { # LINEFAIL : OK
name => 'linefail',
label => {
en => 'Line voltage status',
de => 'Status Eingangsspannung',
},
type => 'bool',
critical => '0:', # Failed
},
BATTSTAT => { # BATTSTAT : OK
name => 'battstat',
label => {
en => 'Battery status',
de => 'Batteriestatus',
},
type => 'bool',
critical => '0:', # Failed
},
MAINS => { # MAINS : OK
name => 'mains',
label => {
en => 'Mains status',
de => 'Status Eingangsspannung',
},
type => 'bool',
critical => '0:', # Failed
},
#STATUS => { # STATUS : ONLINE
# name => 'status',
# label => {
# en => 'Status',
# },
# type => 'status',
# critical => 0,
#},
);
# Read config file
# Can be used to override settings in %attrs
if (-f $config) {
require $config;
}
# Determine plugin capabilities
if (defined $ARGV[0] && $ARGV[0] =~ /autoconf|detect/) {
if (-x $apcaccess) {
print "yes\n";
} else {
print "no (apcaccess not found)\n";
}
exit 0;
}
# Read info from apcupsd using apcaccess
die "$apcaccess: not found\n" unless -x $apcaccess;
open (APCACCESS, "$apcaccess 2>&1 |") || die "$apcaccess: $!\n";
while (<APCACCESS>) {
chomp;
die "$apcaccess: $_\n" if /Error contacting apcupsd/;
$data{$1} = $2 if /^(\S+?)\s*:\s+(.+?)$/;
$num{$1} = $2 if /^(\S+?)\s*:\s+([\d.x]+)/;
}
close APCACCESS;
# Auto-configure plugin
if (defined $ARGV[0] && $ARGV[0] eq 'config') {
if (defined $data{UPSNAME}) {
print "graph_title $data{UPSNAME} ($data{MODEL})\n";
} else {
print "graph_title $data{MODEL}\n";
}
#print "graph_vlabel Units\n";
print "graph_category sensors\n";
print "graph_info This graph shows information about your APC uninterruptible power supply.\n";
foreach my $what (sort keys %attrs) {
&label("$what");
}
# Print current values
} else {
foreach my $what (sort keys %attrs) {
next unless defined $data{$what};
my $func = $attrs{$what}{type} || 'num';
my $value = eval "\&$func('$what')";
print "$attrs{$what}{name}.value $value\n";
}
}
exit 0;
##############################################################################
# Print label/title for value
sub label {
my $what = shift;
return unless defined $data{$what};
my $attr = $attrs{$what};
# Determine language to use for labels
my $lang = $language;
$lang =~ s/_.*$// unless defined $attr->{label}{$lang};
# Failback to english if translation isn't available
$lang = 'en' unless defined $attr->{label}{$lang};
print "$attr->{name}.label $attr->{label}{$lang}\n";
&info($what, 'warning');
&info($what, 'critical');
}
##############################################################################
# Makes a scalar or array into an array (used in &info)
sub list {
return (ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_;
}
##############################################################################
# Used to setup warning or critical levels for munin
sub info {
my $what = shift;
my $level = shift; # 'warning' or 'critical'
my $attr = $attrs{$what};
return unless defined $attr->{$level};
# Determine nominal value for info calculation
my $nom = undef;
if (defined $attr->{nominal}) {
for my $n (&list($attr->{nominal})) {
# Guess list: compare guesses to value of $num{$what}
if ($n =~ /,/) {
my $fitness = ~0;
next unless $num{$what};
foreach my $possibility (split /[,\s]+/, $n) {
my $diff = abs($num{$what} - $possibility);
($nom, $fitness) = ($possibility, $diff) if $fitness >= $diff;
}
# Absolute nominal value
} elsif ($n =~ /^[\d.]+$/) {
$nom = $n;
last;
# Lookup nominal value as an APCUPSD key
} elsif (defined $num{$n}) {
$nom = $num{$n};
last;
}
}
}
# Calculate info value for $level
foreach my $value (&list($attr->{$level})) {
$value =~ s/([^:]+)/&calc($1,$nom)/eg;
if ($value =~ /^[\d.:]+$/) {
print "$attr->{name}.$level $value\n";
return;
}
}
}
##############################################################################
# Change warning/critical ranges into numbers for munin
sub calc {
my $v = shift;
my $nom = shift;
return $v if $v =~ /^[\d.]+$/;
return $num{$v} if defined $num{$v};
return '' unless defined $nom;
if ($v =~ /^\+-([\d.]+)%$/) {
return sprintf "%.0f:%.0f", (100 - $1) * $nom / 100, (100 + $1) * $nom / 100;
} elsif ($v =~ /^([-+][\d.]+)%$/) {
return sprintf "%.0f", (100 + $1) * $nom / 100;
} elsif ($v =~ /^\+-([\d.]+)$/) {
return sprintf "%d:%d", $nom - $1, $nom + $1;
} elsif ($v =~ /^([-+][\d.]+)$/) {
return $nom + $1;
} elsif ($v =~ /^\*([\d.]+)$/) {
return $nom * $1;
} elsif ($v =~ /^\/([\d.]+)$/) {
return sprintf "%.0f", $nom / $1;
}
return '';
}
##############################################################################
# Default "type" routine to display values
sub num {
my $what = shift;
return $num{$what};
}
##############################################################################
# "type" routine to change Ok/Not Ok into 1/0
sub bool {
my $what = shift;
return $num{$what} eq "OK" ? "1" : "0";
}
#sub status {
# my $what = shift;
# return unless defined $data{$what};
# print "$attrs{$what}{name}.value ";
# print $num{$what} eq "ONLINE" ? "1" : "0";
# print "\n";
#}
# vim: sw=4 ts=4