diff options
Diffstat (limited to 'contrib-reporting/process_perfdata.pl')
-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 | } | ||