Code

RedHat RPM spec: updates for 5.4.0
[collectd.git] / contrib / exec-munin.px
1 #!/usr/bin/perl
3 #
4 # collectd - contrib/exec-munin.px
5 # Copyright (C) 2007,2008  Florian Forster
6 #
7 # This program is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by the
9 # Free Software Foundation; only version 2 of the License is applicable.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with this program; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19 #
20 # Authors:
21 #   Florian octo Forster <octo at verplant.org>
22 #
24 use strict;
25 use warnings;
27 =head1 NAME
29 exec-munin.px
31 =head1 DESCRIPTION
33 This script allows you to use plugins that were written for Munin with
34 collectd's C<exec-plugin>. Since the data models of Munin and collectd are
35 quite different rewriting the plugins should be preferred over using this
36 transition layer. Having more than one "data source" for one "data set" doesn't
37 work with this script, for example.
39 =cut
41 use Sys::Hostname ('hostname');
42 use File::Basename ('basename');
43 use Config::General ('ParseConfig');
44 use Regexp::Common ('number');
46 our $ConfigFile = '/etc/exec-munin.conf';
47 our $TypeMap = {};
48 our $Scripts = [];
49 our $Interval = defined ($ENV{'COLLECTD_INTERVAL'}) ? (0 + $ENV{'COLLECTD_INTERVAL'}) : 300;
50 our $Hostname = defined ($ENV{'COLLECTD_HOSTNAME'}) ? $ENV{'COLLECTD_HOSTNAME'} : '';
52 main ();
53 exit (0);
55 # Configuration {{{
57 =head1 CONFIGURATION
59 This script reads it's configuration from F</etc/exec-munin.conf>. The
60 configuration is read using C<Config::General> which understands a Apache-like
61 config syntax, so it's very similar to the F<collectd.conf> syntax, too.
63 Here's a short sample config:
65   AddType voltage-in in
66   AddType voltage-out out
67   Interval 300
68   Script /usr/lib/munin/plugins/nut
70 The options have the following semantic (i.E<nbsp>e. meaning):
72 =over 4
74 =item B<AddType> I<to> I<from> [I<from> ...]
76 collectd uses B<types> to specify how data is structured. In Munin all data is
77 structured the same way, so some way of telling collectd how to handle the data
78 is needed. This option translates the so called "field names" of Munin to the
79 "types" of collectd. If more than one field are of the same type, e.E<nbsp>g.
80 the C<nut> plugin above provides C<in> and C<out> which are both voltages, you
81 can use a hyphen to add a "type instance" to the type.
83 For a list of already defined "types" look at the F<types.db> file in
84 collectd's shared data directory, e.E<nbsp>g. F</usr/share/collectd/>.
86 =item B<Interval> I<Seconds>
88 Sets the interval in which the plugins are executed. This doesn't need to match
89 the interval setting of the collectd daemon. Usually, you want to execute the
90 Munin plugins much less often, e.E<nbsp>g. every 300 seconds versus every 10
91 seconds.
93 =item B<Script> I<File>
95 Adds a script to the list of scripts to be executed once per I<Interval>
96 seconds.
98 =back
100 =cut
102 sub handle_config_addtype
104   my $list = shift;
106   for (my $i = 0; $i < @$list; $i++)
107   {
108     my ($to, @from) = split (' ', $list->[$i]);
109     for (my $j = 0; $j < @from; $j++)
110     {
111       $TypeMap->{$from[$j]} = $to;
112     }
113   }
114 } # handle_config_addtype
116 sub handle_config_script
118   my $scripts = shift;
120   for (my $i = 0; $i < @$scripts; $i++)
121   {
122     my $script = $scripts->[$i];
123     if (!-e $script)
124     {
125       print STDERR "Script `$script' doesn't exist.\n";
126     }
127     elsif (!-x $script)
128     {
129       print STDERR "Script `$script' exists but is not executable.\n";
130     }
131     else
132     {
133       push (@$Scripts, $script);
134     }
135   } # for $i
136 } # handle_config_script
138 sub handle_config
140   my $config = shift;
142   if (defined ($config->{'addtype'}))
143   {
144     if (ref ($config->{'addtype'}) eq 'ARRAY')
145     {
146       handle_config_addtype ($config->{'addtype'});
147     }
148     elsif (ref ($config->{'addtype'}) eq '')
149     {
150       handle_config_addtype ([$config->{'addtype'}]);
151     }
152     else
153     {
154       print STDERR "Cannot handle ref type '"
155       . ref ($config->{'addtype'}) . "' for option 'AddType'.\n";
156     }
157   }
159   if (defined ($config->{'script'}))
160   {
161     if (ref ($config->{'script'}) eq 'ARRAY')
162     {
163       handle_config_script ($config->{'script'});
164     }
165     elsif (ref ($config->{'script'}) eq '')
166     {
167       handle_config_script ([$config->{'script'}]);
168     }
169     else
170     {
171       print STDERR "Cannot handle ref type '"
172       . ref ($config->{'script'}) . "' for option 'Script'.\n";
173     }
174   }
176   if (defined ($config->{'interval'})
177     && (ref ($config->{'interval'}) eq ''))
178   {
179     my $num = int ($config->{'interval'});
180     if ($num > 0)
181     {
182       $Interval = $num;
183     }
184   }
185 } # handle_config }}}
187 sub execute_script
189   my $fh;
190   my $pinst;
191   my $time = time ();
192   my $script = shift;
193   my $host = $Hostname || hostname () || 'localhost';
194   if (!open ($fh, '-|', $script))
195   {
196     print STDERR "Cannot execute $script: $!";
197     return;
198   }
200   $pinst = basename ($script);
202   while (my $line = <$fh>)
203   {
204     chomp ($line);
205     if ($line =~ m#^([^\.\-/]+)\.value\s+($RE{num}{real})#)
206     {
207       my $field = $1;
208       my $value = $2;
209       my $type = (defined ($TypeMap->{$field})) ? $TypeMap->{$field} : $field;
210       my $ident = "$host/munin-$pinst/$type";
212       $ident =~ s/"/\\"/g;
214       print qq(PUTVAL "$ident" interval=$Interval $time:$value\n);
215     }
216   }
218   close ($fh);
219 } # execute_script
221 sub main
223   my $last_run;
224   my $next_run;
226   my %config = ParseConfig (-ConfigFile => $ConfigFile,
227     -AutoTrue => 1,
228     -LowerCaseNames => 1);
229   handle_config (\%config);
231   while (42)
232   {
233     $last_run = time ();
234     $next_run = $last_run + $Interval;
236     for (@$Scripts)
237     {
238       execute_script ($_);
239     }
241     while ((my $timeleft = ($next_run - time ())) > 0)
242     {
243       sleep ($timeleft);
244     }
245   }
246 } # main
248 =head1 REQUIREMENTS
250 This script requires the following Perl modules to be installed:
252 =over 4
254 =item C<Config::General>
256 =item C<Regexp::Common>
258 =back
260 =head1 SEE ALSO
262 L<http://munin.projects.linpro.no/>,
263 L<http://collectd.org/>,
264 L<collectd-exec(5)>
266 =head1 AUTHOR
268 Florian octo Forster E<lt>octo at verplant.orgE<gt>
270 =cut
272 # vim: set sw=2 sts=2 ts=8 fdm=marker :