%PDF- %PDF-
Direktori : /usr/share/munin/plugins/ |
Current File : //usr/share/munin/plugins/sensors_ |
#!/usr/bin/perl -w # -*- perl -*- =head1 NAME sensors_ - Wildcard-plugin to monitor information from temperature, voltage, and fan speed sensors. =head1 CONFIGURATION The possible wildcard values are the follwing: fan, temp, volt. So you would create symlinks to this plugin called sensors_fan, sensors_temp, and sensors_volt. The plugins needs the following components configured: =over =item i2c and lm_sensors modules installed and loaded. =item sensors program installed and in path. =back Note: Sensor names are read from the output of the sensors program. Change them in /etc/sensors.conf if you don't like them. [sensors_*] env.sensors - Override default sensors program path env.ignore_temp<n> - Temperature <n> will not be plotted env.ignore_fan<n> - Fan <n> will not be plotted env.ignore_volt<n> - Voltage <n> will not be plotted env.fan_warn_percent - Percentage over mininum for warning env.volt_warn_percent - Percentage over mininum/under maximum for warning =head1 AUTHOR Unknown author =head1 LICENSE GPLv2 =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf suggest =cut use strict; $ENV{'LANG'} = "C"; # Force parsable output from sensors. $ENV{'LC_ALL'} = "C"; # Force parsable output from sensors. my $SENSORS = $ENV{'sensors'} || 'sensors'; # Example outputs from sensors & matching regex parts: # Fan output example from sensors: # -------------------------------- # Case Fan: 1268 RPM (min = 3750 RPM, div = 8) ALARM # CPU Fan: 0 RPM (min = 1171 RPM, div = 128) ALARM # Aux Fan: 0 RPM (min = 753 RPM, div = 128) ALARM # fan4: 3375 RPM (min = 774 RPM, div = 8) # fan5: 0 RPM (min = 1054 RPM, div = 128) ALARM # # ^^^^ ^^^^ ^^^^ # $+{label} $+{value} $+{threshold1} # # -------------------------------- # # Temperature output example from sensors: # * Note that the degree character is replaced by a space, as we are running # with LC_ALL=C and LANG=C. # --------------------------------------- # Sys Temp: +41.0 C (high = -128.0 C, hyst = +24.0 C) ALARM sensor = thermistor # CPU Temp: +40.5 C (high = +80.0 C, hyst = +75.0 C) sensor = thermistor # AUX Temp: +39.0 C (high = +80.0 C, hyst = +75.0 C) sensor = thermistor # # ^^^^^^^^ ^^ ^^ ^^ # $+{label} $+{value} $+{threshold1} $+{threshold2} # # --------------------------------------- # # Voltage output example from sensors: # ------------------------------------ # # VCore: +1.09 V (min = +0.00 V, max = +1.74 V) # in1: +12.14 V (min = +10.51 V, max = +2.38 V) ALARM # # ^^^ ^^^ ^^^ ^^ # $+{label} $+{value} $+{threshold1} $+{threshold2} # # # ------------------------------------ my %config = ( fan => { regex => qr/ ^ # String must start with: (?<label>[^:\n]*) # Match any non-whitespace char, except ':' and new line \s* # Zero or more spaces followed by : # : character \s* # Zero or more spaces followed by \+? # Zero or one '+' char. Note: This might not be needed # as FAN speeds don't have + signs in front of them. # This can be probably be removed as the # sensors program never prints a + char in front of # RPM values. Verified in lm-sensors-3-3.1.2 (?<value>\d+) # Match one or more digits (Match current value) \s # Exactly one space followed by (?: # a optional group, which might contain the minimum value: RPM.*? # RPM string, and then any chars (but no newlines) (?<threshold1>\d+) # Match one or more digits (Match minimum value) \s # Exactly one space followed by )? # end of optional group RPM # RPM string /xm, # Use extended regular expressions and treat string as multiple lines. title => 'Fans', vlabel => 'RPM', print_threshold => \&fan_threshold, graph_args => '--base 1000 -l 0' }, temp => { regex => qr/ ^ # String must start with: (?<label>[^:\n]*) # Match any non-whitespace char, except ':' and new line \s* # Zero or more spaces followed by : # ':' character \s* # Zero or more spaces followed by \+? # Zero or one '+' char followed by (?<value>-? # Match zero or one '-' char \d+ # Match one or more digits # (Match current value) followed by (?:\.\d+)?)# Zero or one match of '.' char followed by one or more # digits. '?:' means it is not a numbered capture group. [°\s] # Match degree char or space char C # Match 'C' char (?: # >>>>Match the following statement zero or one time. # '?:' means it is not a numbered capture group. \s+ # One or more space followed by \( # '(' char (?:high|limit|crit) # 'high' or 'limit' or 'crit' string. # '?:' means it is not a numbered capture group. \s*=\s* # Match zero or more spaces and then '=' char and then # zero or more spaces, followed by \+? # Zero or one '+' char (?<threshold1>\d+ # Match one or more digits # (Match high value) followed by (?:\.\d+)?)# Zero or one match of '.' char followed by one or more # digits. '?:' means it is not a numbered capture group. [°\s] # Match degree char or space char C,?\s* # 'C' followed by optional comma and zero or more spaces (?: # >>>Match the following non-capture group zero or more times (?:crit|hyst(?:eresis)?) # 'crit' or 'hyst' string followed by optional 'eresis' string. # '?:' means it is not a numbered capture group. \s*=\s* # Match zero or more spaces and then '=' char and then # zero or more spaces, followed by \+? # Zero or one '+' char (?<threshold2>\d+ # Match one or more digits # (Match hyst value) followed by (?:\.\d+)?)# Zero or one match of '.' char followed by one or more # digits. '?:' means it is not a numbered capture group. [°\s]C # Match degree char or space char, and then 'C' char )? # >>>end of group \) # ')' char )? # >>>>end of group /xm, # Use extended regular expressions and treat string as multiple lines. title => 'Temperatures', vlabel => 'degrees Celsius', print_threshold => \&temp_threshold, graph_args => '--base 1000 -l 0' }, volt => { regex => qr/ ^ # String must start with: (?<label>[^:\n]*) # Match any non-whitespace char, except ':' and new line # one space in front of them. \s*:\s* # Zero or more spaces followed by ':' and # zero or more spaces followed by \+? # Zero or one '+' char followed by (?<value>-? # Match zero or one '-' char \d+ # Match one or more digits # (match the current voltage) followed by (?:\.\d+)?) # Zero or one match of '.' char followed by one or more digits. # '?:' means it is not a numbered capture group. \s(?<unit_prefix_value>[m])?V # one space, 'V' char (?: # >>>>Match the following statement. # '?:' means it is not a numbered capture group. \s+ # One or more space followed by \( # '(' char min # Match min string \s*=\s* # Match zero or more spaces and then '=' char and # then zero or more spaces, followed by \+? # Zero or one '+' char (?<threshold1>-? # Match zero or one '-' char \d+ # Match one or more digits # (Match the minimum value) followed by (?:\.\d+)?) # Zero or one match of '.' char followed by one or more # digits. '?:' means it is not a numbered capture group. \s(?<unit_prefix_threshold1>[m])?V,\s* # One space char, 'V,' string followed by zero or # more spaces max # Match 'max' string \s*=\s* # Match zero or more spaces and then '=' char and # then zero or more spaces, followed by \+? # Zero or one '+' char (?<threshold2>-? # Match zero or one '-' char \d+ # Match one or more digits # (Match the max value) followed by (?:\.\d+)?) # Zero or one match of '.' char followed by one or more digits. # '?:' means passive group (does not match) \s(?<unit_prefix_threshold2>[m])?V # one space, 'V' char \) # ')' char )? # >>>>end of statement /xm, # Use extended regular expressions and treat string as multiple lines. title => 'Voltages', vlabel => 'Volt', print_threshold => \&volt_threshold, graph_args => '--base 1000 --logarithmic' }, power => { regex => qr/ ^ # String must start with: (?<label>[^:\n]*) # Match any non-whitespace char, except ':' and new line # one space in front of them. \s*:\s* # Zero or more spaces followed by ':' and # zero or more spaces followed by (?<value>\d+ # Match one or more digits # (match the power) followed by (?:\.\d+)?) # Zero or one match of '.' char followed by one or more digits. # '?:' means it is not a numbered capture group. \sW # one space, 'W' char (?: # >>>>Match the following statement. # '?:' means it is not a numbered capture group. \s+ # One or more space followed by \( # '(' char crit # Match crit string \s*=\s* # Match zero or more spaces and then '=' char and # then zero or more spaces, followed by (?<threshold1>\d+ # Match one or more digits # (Match the minimum value) followed by (?:\.\d+)?) # Zero or one match of '.' char followed by one or more # digits. '?:' means it is not a numbered capture group. \sW\s* # One space char, 'W' character followed by zero or # more spaces \) # ')' char )? # >>>>end of statement /xm, # Use extended regular expressions and treat string as multiple lines. title => 'Power', vlabel => 'Watts', print_threshold => \&power_threshold, graph_args => '--base 1000 --logarithmic' }, ); if ( defined $ARGV[0] and $ARGV[0] eq 'autoconf' ) { # Now see if "sensors" can run my $text = `$SENSORS 2>/dev/null`; if ($?) { if ($? == -1) { print "no (program $SENSORS not found)\n"; } else { print "no (program $SENSORS died)\n"; } exit 0; } unless ($text =~ /[° ]C/) { print "no (no temperature readings)\n"; exit 0; } print "yes\n"; exit 0; } if (defined $ARGV[0] and $ARGV[0] eq 'suggest') { my $text = `$SENSORS 2>/dev/null`; foreach my $func (keys %config) { print $func, "\n" if $text =~ $config{$func}->{regex}; } exit; } $0 =~ /sensors_(.+)*$/; my $func = $1; exit 2 unless defined $func; if ( defined $ARGV[0] and $ARGV[0] eq 'config' ) { print "graph_title $config{$func}->{title}\n"; print "graph_vlabel $config{$func}->{vlabel}\n"; print "graph_args $config{$func}->{graph_args}\n"; print "graph_category sensors\n"; my $text = `$SENSORS`; my $sensor = 1; while ($text =~ /$config{$func}->{regex}/g) { print "$func$sensor.label $+{label}\n"; my $threshold1 = convert_unit_value($+{threshold1}, $+{unit_prefix_threshold1}); my $threshold2 = convert_unit_value($+{threshold2}, $+{unit_prefix_threshold2}); $config{$func}->{print_threshold}->($func.$sensor, $threshold1, $threshold2); print "$func$sensor.graph no\n" if exists $ENV{"ignore_$func$sensor"}; $sensor++; } exit 0; } my $text = `$SENSORS`; my $sensor = 1; while ($text =~ /$config{$func}->{regex}/g) { my $value = convert_unit_value($+{value}, $+{unit_prefix_value}); print "$func$sensor.value $value\n"; $sensor++; } sub fan_threshold { my $name = shift; my $min = shift; my $warn_percent = exists $ENV{fan_warn_percent} ? $ENV{fan_warn_percent} : 5; return unless defined $min; printf "$name.warning %d:\n", $min * (100 + $warn_percent) / 100; printf "$name.critical %d:\n", $min; } sub temp_threshold { my $name = shift; my $max = shift; my $min = shift; if (defined($min) and defined($max) and $min > $max) { ($min, $max) = ($max, $min); } printf "$name.warning $min\n" if $min; printf "$name.critical $max\n" if $max; } sub volt_threshold { my $name = shift; my $min = shift; my $max = shift; my $warn_percent = exists $ENV{volt_warn_percent} ? $ENV{volt_warn_percent} : 20; return unless defined ($min && $max); my $diff = $max - $min; my $dist = $diff * $warn_percent / 100; printf "$name.warning %.2f:%.2f\n", $min + $dist, $max - $dist; printf "$name.critical $min:$max\n"; } sub power_threshold { my $name = shift; my $crit = shift; my $warn_percent = exists $ENV{watt_warn_percent} ? $ENV{watt_warn_percent} : 20; return unless defined ($crit); printf "$name.warning :%.2f\n", $crit * (100-$warn_percent)/100; printf "$name.critical :$crit\n"; } sub convert_unit_value { my $value = shift; my $unit_prefix = shift; if (defined $unit_prefix) { if ($unit_prefix eq "m") { $value /= 1000; } else { warn "Unknown value prefix: '$unit_prefix'"; } } return $value; } # vim:syntax=perl