diff options
Diffstat (limited to 'contrib-reporting')
| -rw-r--r-- | contrib-reporting/process_perfdata.pl | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/contrib-reporting/process_perfdata.pl b/contrib-reporting/process_perfdata.pl new file mode 100644 index 00000000..c97d4832 --- /dev/null +++ b/contrib-reporting/process_perfdata.pl | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | #!/usr/local/bin/perl -w | ||
| 2 | # author: Al Tobey <albert.tobey@priority-health.com> | ||
| 3 | # what: process perfdata from Nagios and put it into RRD files | ||
| 4 | # license: GPL - http://www.fsf.org/licenses/gpl.txt | ||
| 5 | # | ||
| 6 | # Todo: | ||
| 7 | # * more documentation (POD) & comments | ||
| 8 | # * clean up a bit, make it more configurable - possibly a config file | ||
| 9 | |||
| 10 | use strict; | ||
| 11 | use lib qw( /opt/nagios/libexec ); | ||
| 12 | use utils qw( %ERRORS ); | ||
| 13 | use vars qw( $debug_file %data $debug $rrd_base $process_func $rrd_type ); | ||
| 14 | use RRDs; | ||
| 15 | $debug_file = undef; #"/var/opt/nagios/perfdata.out"; | ||
| 16 | $rrd_base = '/var/opt/nagios/rrds'; | ||
| 17 | $process_func = \&process_multi; | ||
| 18 | $rrd_type = 'GAUGE'; | ||
| 19 | $data{hostname} = shift(@ARGV); | ||
| 20 | $data{metric} = shift(@ARGV); | ||
| 21 | $data{timestamp} = shift(@ARGV); | ||
| 22 | $data{perfdata} = join( " ", @ARGV ); $data{perfdata} =~ s/\s+/ /g; | ||
| 23 | |||
| 24 | # make sure there's data to work with | ||
| 25 | exit $ERRORS{OK} if ( !defined($data{hostname}) || !defined($data{metric}) | ||
| 26 | || !defined($data{timestamp}) || !defined($data{perfdata}) | ||
| 27 | || $data{perfdata} eq ' ' || $data{perfdata} eq '' ); | ||
| 28 | |||
| 29 | if ( defined($debug_file) ) { | ||
| 30 | open( LOGFILE, ">>$debug_file" ); | ||
| 31 | print LOGFILE "$data{hostname}\t$data{metric}\t$data{timestamp}\t$data{perfdata}\n\n"; | ||
| 32 | } | ||
| 33 | |||
| 34 | # make sure host directory exists | ||
| 35 | if ( !-d "$rrd_base/$data{hostname}" ) { | ||
| 36 | mkdir( "$rrd_base/$data{hostname}" ) | ||
| 37 | || warn "could not create host directory $rrd_base/$data{hostname}: $!"; | ||
| 38 | } | ||
| 39 | our $rrd_dir = $rrd_base .'/'. $data{hostname}; | ||
| 40 | |||
| 41 | # --------------------------------------------------------------------------- # | ||
| 42 | # do some setup based on the name of the metric | ||
| 43 | |||
| 44 | # host data | ||
| 45 | if ( $data{metric} eq "HOSTCHECK" ) { | ||
| 46 | $rrd_dir .= '/hostperf'; | ||
| 47 | } | ||
| 48 | # processing disk information | ||
| 49 | elsif ( $data{metric} =~ /_DISK$/ ) { | ||
| 50 | $rrd_dir .= '/disk'; | ||
| 51 | } | ||
| 52 | # network interface information | ||
| 53 | elsif ( $data{metric} =~ /^IFACE_/ ) { | ||
| 54 | $rrd_dir .= '/interfaces'; | ||
| 55 | $rrd_type = [ 'COUNTER', 'COUNTER' ]; | ||
| 56 | } | ||
| 57 | # process performance statistics | ||
| 58 | elsif ( $data{metric} =~ /_PROC$/ ) { | ||
| 59 | $rrd_dir .= '/processes'; | ||
| 60 | $process_func = \&process_single; | ||
| 61 | $rrd_type = [ 'COUNTER', 'GAUGE' ]; | ||
| 62 | } | ||
| 63 | # a resonable guess | ||
| 64 | elsif ( $data{perfdata} =~ /=/ ) { | ||
| 65 | $process_func = \&process_single; | ||
| 66 | } | ||
| 67 | # everything else | ||
| 68 | else { | ||
| 69 | $rrd_dir .= '/other'; | ||
| 70 | } | ||
| 71 | |||
| 72 | # --------------------------------------------------------------------------- # | ||
| 73 | # call the proper processing function set up above (functions defined below) | ||
| 74 | our @processed = ( $process_func->() ); | ||
| 75 | |||
| 76 | # --------------------------------------------------------------------------- # | ||
| 77 | |||
| 78 | if ( !-d $rrd_dir ) { | ||
| 79 | mkdir( $rrd_dir ) || warn "could not mkdir( $rrd_dir ): $!"; | ||
| 80 | } | ||
| 81 | foreach my $datum ( @processed ) { | ||
| 82 | if ( defined($debug_file) ) { | ||
| 83 | print LOGFILE $datum->{rrd_name}, " = ", join('--',@{$datum->{data}}), "\n" | ||
| 84 | } | ||
| 85 | |||
| 86 | my $rrdfile = $rrd_dir.'/'.$datum->{rrd_name}; | ||
| 87 | |||
| 88 | # create the RRD file if it doesn't already exist | ||
| 89 | if ( !-e $rrdfile ) { | ||
| 90 | # create a non-useful datasource title for each "part" | ||
| 91 | RRDs::create( $rrdfile, "-b", $data{timestamp}, "-s", 300, $process_func->($datum, 1), | ||
| 92 | "RRA:AVERAGE:0.5:1:600", | ||
| 93 | "RRA:MAX:0.5:1:600", | ||
| 94 | "RRA:AVERAGE:0.5:6:600", | ||
| 95 | "RRA:MAX:0.5:6:600", | ||
| 96 | "RRA:AVERAGE:0.5:24:600", | ||
| 97 | "RRA:MAX:0.5:24:600", | ||
| 98 | "RRA:AVERAGE:0.5:288:600", | ||
| 99 | "RRA:MAX:0.5:288:600" | ||
| 100 | ); | ||
| 101 | if ( my $ERROR = RRDs::error ) { print "ERROR: $ERROR\n"; exit $ERRORS{UNKNOWN}; } | ||
| 102 | } | ||
| 103 | else { | ||
| 104 | # create a template to make sure data goes into the RRD as planned | ||
| 105 | if ( defined($debug_file) ) { | ||
| 106 | print LOGFILE "updating $rrdfile with data:\n\t", | ||
| 107 | join(':', $data{timestamp}, @{$datum->{data}}), "\n"; | ||
| 108 | } | ||
| 109 | # update the RRD file | ||
| 110 | RRDs::update( $rrdfile, '-t', $process_func->($datum), | ||
| 111 | join(':', $data{timestamp}, @{$datum->{data}}) ); | ||
| 112 | if ( my $ERROR = RRDs::error ) { print "ERROR: $ERROR\n"; exit $ERRORS{UNKNOWN}; } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | # --------------------------------------------------------------------------- # | ||
| 117 | |||
| 118 | if ( defined($debug_file) ) { | ||
| 119 | print LOGFILE "-------------------------------------------------------------------------------\n"; | ||
| 120 | close( LOGFILE ); | ||
| 121 | } | ||
| 122 | |||
| 123 | exit $ERRORS{OK}; | ||
| 124 | |||
| 125 | # /opt=value,value,value:/=value,value,value - into multiple rrd's | ||
| 126 | sub process_multi { | ||
| 127 | my( $datum, $create ) = @_; | ||
| 128 | |||
| 129 | # return a string for creating new RRDs | ||
| 130 | if ( defined($create) && $create == 1 ) { | ||
| 131 | my @DS = (); | ||
| 132 | for ( my $i=0; $i<scalar(@{$datum->{data}}); $i++ ) { | ||
| 133 | # allow the RRD type to be set in the switch/if above | ||
| 134 | my $tmp_rrd_type = $rrd_type; | ||
| 135 | if ( ref($rrd_type) eq 'ARRAY' ) { $tmp_rrd_type = $rrd_type->[$i] } | ||
| 136 | # put the new datasource into the list | ||
| 137 | push( @DS, "DS:$data{metric}$i:GAUGE:86400:U:U" ); | ||
| 138 | } | ||
| 139 | return @DS; | ||
| 140 | } | ||
| 141 | # return a template for updating an RRD | ||
| 142 | elsif ( defined($datum) && !defined($create) ) { | ||
| 143 | my @template = (); | ||
| 144 | for ( my $i=0; $i<scalar(@{$datum->{data}}); $i++ ) { | ||
| 145 | push( @template, $data{metric}.$i ); | ||
| 146 | } | ||
| 147 | return join( ':', @template ); | ||
| 148 | } | ||
| 149 | # break the data up into parts for processing (updates and creates) | ||
| 150 | else { | ||
| 151 | my @processed = (); | ||
| 152 | foreach my $part ( split(/:/, $data{perfdata}) ) { # break the line into parts | ||
| 153 | my @parts = split( /,/, $part ); # break the part into parts | ||
| 154 | my $rrd_name = $parts[0]; # figure out a good name for the RRD | ||
| 155 | if ( $parts[0] =~ /^\// ) { # handle /'s in disk names | ||
| 156 | $rrd_name = $parts[0]; | ||
| 157 | $rrd_name =~ s#/#_#g; $rrd_name =~ s/^_//; $rrd_name =~ s/_$//; | ||
| 158 | if ( $parts[0] eq '/' ) { $rrd_name = 'root' }; | ||
| 159 | } | ||
| 160 | # store our munged data in an array of hashes | ||
| 161 | push( @processed, { rrd_name => $rrd_name, name => shift(@parts), data => [ @parts ] } ); | ||
| 162 | } | ||
| 163 | return @processed; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | # name=value:name=value - into one rrd | ||
| 168 | sub process_single { | ||
| 169 | my( $datum, $create ) = @_; | ||
| 170 | |||
| 171 | my( @names, @values ) = (); | ||
| 172 | foreach my $part ( split(/:/, $data{perfdata}) ) { | ||
| 173 | my( $name, $value ) = split( /=/, $part ); | ||
| 174 | push( @names, $name ); | ||
| 175 | push( @values, $value ); | ||
| 176 | } | ||
| 177 | |||
| 178 | if ( defined($create) && $create == 1 ) { | ||
| 179 | my @DS = (); | ||
| 180 | for( my $i=0; $i<scalar(@names); $i++ ) { | ||
| 181 | my $tmp_rrd_type = $rrd_type; | ||
| 182 | if ( ref($rrd_type) eq 'ARRAY' ) { $tmp_rrd_type = $rrd_type->[$i] } | ||
| 183 | push( @DS, 'DS:'.$names[$i].":$tmp_rrd_type:86400:U:U" ); | ||
| 184 | } | ||
| 185 | return @DS; | ||
| 186 | } | ||
| 187 | elsif ( defined($datum) && !defined($create) ) { | ||
| 188 | return join( ':', @names ); | ||
| 189 | } | ||
| 190 | else { | ||
| 191 | return( {rrd_name=>lc($data{metric}), name=>$data{metric}, data=>[@values]} ); | ||
| 192 | } | ||
| 193 | } | ||
