#!/usr/bin/perl
# -*- perl -*-

# Copyright (C) 2015-2019 Pirx Developers - https://pirx.dev/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

=head1 NAME

hq_sensors - Munin plugin to monitor sensors reported by lm_sensors.

=head1 APPLICABLE SYSTEMS

Linux systems with lm_sensors installed and configured.

=head1 CONFIGURATION

You may need to specify path to sensors binary if its not on PATH:

[hq_sensors]
  env.sensors /usr/local/bin/sensors

You can also choose which sensors are monitored. For example to monitor
just fan2 and temp3 on sensor #2 (and everything on other sensors):

[hq_sensors]
  env.sensor2 fan2;temp3

Valid sensors names are: fan# for fans, temp# for temperatures and in#
for voltages. Run 'sensor -A -u' for full list of sensors on your system.

=head1 VERSION

  20190108

=head1 MAGIC MARKERS

  #%# family=manual
  #%# capabilities=autoconf

=head1 BUGS

None.

=head1 AUTHOR

Pirx Developers - https://pirx.dev/

=head1 LICENSE

GPLv3

=cut

use strict;
use warnings;
use Munin::Plugin;

# Handle autoconf
if(defined($ARGV[0]) and $ARGV[0] eq 'autoconf') {
  print("yes\n");
  exit(0);
}

need_multigraph();

my %sensors;
my $exec_fd;

my $sensors = $ENV{'sensors'} || "sensors";
# Read sensors
if(open($exec_fd, $sensors. " -A -u 2>/dev/null |")) {
  my $chip_id = 0;
  my $sensor_id = 0;
  my $sensor_description;
  SENSORS_READ_LOOP: while(defined(my $line=<$exec_fd>)) {
    if($line =~ /^$/) {
      next(SENSORS_READ_LOOP);
    }
    if($line =~ m/^([^\s].*):$/) {
      $sensor_id++;
      $sensor_description = $1;
    }
    elsif($line =~ m/^\s+[^\s]+:\s+.*$/) {
      if($line =~ m/^\s+(fan|in|temp)[0-9]+_input:\s+.*$/) {
        my @names;
        if(defined($ENV{'sensor' . $chip_id})) {
          @names = split(";", $ENV{'sensor' . $chip_id})
        }
        my ($sensor_name, $sensor_type, $sensor_value) = $line =~ m/^\s+((fan|in|temp)[0-9]+)_input:\s+(.*)$/;
        my $sensor_group = "";
        if($sensor_type eq "fan") { $sensor_group = "fans"; }
        if($sensor_type eq "in") { $sensor_group = "voltages"; }
        if($sensor_type eq "temp") { $sensor_group = "temps"; }
        if($sensor_group ne "") {
          my $skip = 0;
          if(scalar(@names) > 0) {
            $skip = 1;
            foreach my $name (@names) {
              if($name eq $sensor_name) { $skip = 0; }
            }
          }
          if($skip == 0) {
            $sensors{$chip_id}{$sensor_group}{$sensor_id}{'name'} = $sensor_name;
            $sensors{$chip_id}{$sensor_group}{$sensor_id}{'value'} = $sensor_value;
            $sensors{$chip_id}{$sensor_group}{$sensor_id}{'description'} = $sensor_description;
          }
        }
      }
    }
    else {
      $chip_id++;
      $sensor_id = 0;
      ($sensors{$chip_id}{'name'}) = $line =~ m/^(.*)$/;
    }
  }
  close($exec_fd);
  if($? >> 8 != 0) {
    print("Error running sensors. Exiting.\n");
    exit(1);
  }
}
else {
  print("Error running sensors. Exiting.\n");
  exit(1);
}

# Handle config
if(defined($ARGV[0]) and $ARGV[0] eq 'config') {
  SENSORS_CONFIG_LOOP: foreach my $chip_id (sort keys %sensors) {
    my $graph_name = "sensor_" . $chip_id;
    $graph_name =~ s![/\-\.]!_!g;
    if(defined($sensors{$chip_id}{'fans'}) and scalar(keys %{$sensors{$chip_id}{'fans'}})) {
      print <<EOF;
multigraph $graph_name\_fans
graph_title Sensor \#$chip_id fans
graph_args --base 1000 --lower-limit 0
graph_scale no
graph_vlabel RPM
graph_category sensors
EOF
      foreach my $sensor_id (sort keys %{$sensors{$chip_id}{'fans'}}) {
        print <<EOF;
$sensors{$chip_id}{'fans'}{$sensor_id}{'name'}.label $sensors{$chip_id}{'fans'}{$sensor_id}{'description'}
$sensors{$chip_id}{'fans'}{$sensor_id}{'name'}.type GAUGE
$sensors{$chip_id}{'fans'}{$sensor_id}{'name'}.draw LINE2
EOF
      }
    }
    if(defined($sensors{$chip_id}{'temps'}) and scalar(keys %{$sensors{$chip_id}{'temps'}})) {
      print <<EOF;
multigraph $graph_name\_temps
graph_title Sensor \#$chip_id temperatures
graph_args --base 1000 --lower-limit 0
graph_scale no
graph_vlabel degrees celsius
graph_category sensors
EOF
      foreach my $sensor_id (sort keys %{$sensors{$chip_id}{'temps'}}) {
        print <<EOF;
$sensors{$chip_id}{'temps'}{$sensor_id}{'name'}.label $sensors{$chip_id}{'temps'}{$sensor_id}{'description'}
$sensors{$chip_id}{'temps'}{$sensor_id}{'name'}.type GAUGE
$sensors{$chip_id}{'temps'}{$sensor_id}{'name'}.draw LINE2
EOF
      }
    }
    if(defined($sensors{$chip_id}{'voltages'}) and scalar(keys %{$sensors{$chip_id}{'voltages'}})) {
      print <<EOF;
multigraph $graph_name\_voltages
graph_title Sensor \#$chip_id voltages
graph_args --base 1000 --lower-limit 0
graph_scale no
graph_vlabel V
graph_category sensors
EOF
      foreach my $sensor_id (sort keys %{$sensors{$chip_id}{'voltages'}}) {
        print <<EOF;
$sensors{$chip_id}{'voltages'}{$sensor_id}{'name'}.label $sensors{$chip_id}{'voltages'}{$sensor_id}{'description'}
$sensors{$chip_id}{'voltages'}{$sensor_id}{'name'}.type GAUGE
$sensors{$chip_id}{'voltages'}{$sensor_id}{'name'}.draw LINE2
EOF
      }
    }
  }
  exit(0);
}

foreach my $chip_id (sort keys %sensors) {
  my $graph_name = "sensor_" . $chip_id;
  $graph_name =~ s![/\-\.]!_!g;
  if(defined($sensors{$chip_id}{'fans'}) and scalar(keys %{$sensors{$chip_id}{'fans'}})) {
      print <<EOF;
multigraph $graph_name\_fans
EOF
    foreach my $sensor_id (sort keys %{$sensors{$chip_id}{'fans'}}) {
      print <<EOF;
$sensors{$chip_id}{'fans'}{$sensor_id}{'name'}.value $sensors{$chip_id}{'fans'}{$sensor_id}{'value'}
EOF
    }
  }
  if(defined($sensors{$chip_id}{'temps'}) and scalar(keys %{$sensors{$chip_id}{'temps'}})) {
    print <<EOF;
multigraph $graph_name\_temps
EOF
    foreach my $sensor_id (sort keys %{$sensors{$chip_id}{'temps'}}) {
      print <<EOF;
$sensors{$chip_id}{'temps'}{$sensor_id}{'name'}.value $sensors{$chip_id}{'temps'}{$sensor_id}{'value'}
EOF
    }
  }
  if(defined($sensors{$chip_id}{'voltages'}) and scalar(keys %{$sensors{$chip_id}{'voltages'}})) {
    print <<EOF;
multigraph $graph_name\_voltages
EOF
    foreach my $sensor_id (sort keys %{$sensors{$chip_id}{'voltages'}}) {
      print <<EOF;
$sensors{$chip_id}{'voltages'}{$sensor_id}{'name'}.value $sensors{$chip_id}{'voltages'}{$sensor_id}{'value'}
EOF
    }
  }
}

exit(0);
