contrib/collection3: Add an basic, extensible, modular graphing front-end.
[collectd.git] / contrib / collection3 / lib / Collectd / Graph / TypeLoader.pm
1 package Collectd::Graph::TypeLoader;
2
3 =head1 NAME
4
5 Collectd::Graph::TypeLoader - Load a module according to the "type"
6
7 =cut
8
9 # Copyright (C) 2008  Florian octo Forster <octo at verplant.org>
10 #
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; only version 2 of the License is applicable.
14 #
15 # This program is distributed in the hope that it will be useful, but WITHOUT
16 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18 # details.
19 #
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, write to the Free Software Foundation, Inc.,
22 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23
24 use strict;
25 use warnings;
26
27 use Carp (qw(cluck confess));
28 use Exporter ();
29 use Config::General ('ParseConfig');
30 use Collectd::Graph::Type ();
31
32 @Collectd::Graph::TypeLoader::ISA = ('Exporter');
33 @Collectd::Graph::TypeLoader::EXPORT_OK = ('tl_read_config', 'tl_load_type');
34
35 our $Configuration = undef;
36
37 our @ArrayMembers = (qw(data_sources rrd_opts custom_order));
38 our @ScalarMembers = (qw(rrd_title rrd_format rrd_vertical scale));
39 our @DSMappedMembers = (qw(ds_names rrd_colors));
40
41 our %MemberToConfigMap =
42 (
43   data_sources => 'datasources',
44   ds_names => 'dsname',
45   rrd_title => 'rrdtitle',
46   rrd_opts => 'rrdoptions',
47   rrd_format => 'rrdformat',
48   rrd_vertical => 'rrdverticallabel',
49   rrd_colors => 'color',
50   scale => 'scale', # GenericIO only
51   custom_order => 'order' # GenericStacked only
52 );
53
54 return (1);
55
56 =head1 EXPORTED FUNCTIONS
57
58 =over 4
59
60 =item B<tl_read_config> (I<$file>)
61
62 Reads the configuration from the file located at I<$file>.
63
64 =cut
65
66 sub tl_read_config
67 {
68   my $file = shift;
69   my %conf;
70
71   if ($Configuration)
72   {
73     return (1);
74   }
75
76   %conf = ParseConfig (-ConfigFile => $file,
77     -LowerCaseNames => 1,
78     -UseApacheInclude => 1,
79     -IncludeDirectories => 1,
80     ($Config::General::VERSION >= 2.38) ? (-IncludeAgain => 0) : (),
81     -MergeDuplicateBlocks => 1,
82     -CComments => 0);
83   if (!%conf)
84   {
85     return;
86   }
87
88   $Configuration = \%conf;
89   return (1);
90 } # tl_read_config
91
92 sub _create_object
93 {
94   my $module = shift;
95   my $obj;
96
97   local $SIG{__WARN__} = sub {};
98   local $SIG{__DIE__} = sub {};
99
100   eval <<PERL;
101   require $module;
102   \$obj = ${module}->new ();
103 PERL
104   if (!$obj)
105   {
106     return;
107   }
108
109   return ($obj);
110 } # _create_object
111
112 sub _load_module_from_config
113 {
114   my $conf = shift;
115
116   my $module = $conf->{'module'};
117   my $obj;
118   
119   if ($module && !($module =~ m/::/))
120   {
121     $module = "Collectd::Graph::Type::$module";
122   }
123
124   if ($module)
125   {
126     print STDERR "\$module = $module;\n";
127     $obj = _create_object ($module);
128     if (!$obj)
129     {
130       cluck ("Creating an $module object failed");
131       return;
132     }
133   }
134   else
135   {
136     $obj = Collectd::Graph::Type->new ();
137     if (!$obj)
138     {
139       cluck ("Creating an Collectd::Graph::Type object failed");
140       return;
141     }
142   }
143
144   for (@ScalarMembers) # {{{
145   {
146     my $member = $_;
147     my $key = $MemberToConfigMap{$member};
148     my $val;
149
150     if (!defined $conf->{$key})
151     {
152       next;
153     }
154     $val = $conf->{$key};
155     
156     if (ref ($val) ne '')
157     {
158       cluck ("Invalid value type for $key: " . ref ($val));
159       next;
160     }
161
162     $obj->{$member} = $val;
163   } # }}}
164
165   for (@ArrayMembers) # {{{
166   {
167     my $member = $_;
168     my $key = $MemberToConfigMap{$member};
169     my $val;
170
171     if (!defined $conf->{$key})
172     {
173       next;
174     }
175     $val = $conf->{$key};
176     
177     if (ref ($val) eq 'ARRAY')
178     {
179       $obj->{$member} = $val;
180     }
181     elsif (ref ($val) eq '')
182     {
183       $obj->{$member} = [split (' ', $val)];
184     }
185     else
186     {
187       cluck ("Invalid value type for $key: " . ref ($val));
188     }
189   } # }}}
190
191   for (@DSMappedMembers) # {{{
192   {
193     my $member = $_;
194     my $key = $MemberToConfigMap{$member};
195     my @val_list;
196
197     if (!defined $conf->{$key})
198     {
199       next;
200     }
201
202     if (ref ($conf->{$key}) eq 'ARRAY')
203     {
204       @val_list = @{$conf->{$key}};
205     }
206     elsif (ref ($conf->{$key}) eq '')
207     {
208       @val_list = ($conf->{$key});
209     }
210     else
211     {
212       cluck ("Invalid value type for $key: " . ref ($conf->{$key}));
213       next;
214     }
215
216     for (@val_list)
217     {
218       my $line = $_;
219       my $ds;
220       my $val;
221
222       if (!defined ($line) || (ref ($line) ne ''))
223       {
224         next;
225       }
226
227       ($ds, $val) = split (' ', $line, 2);
228       if (!$ds || !$val)
229       {
230         next;
231       }
232
233       $obj->{$member} ||= {};
234       $obj->{$member}{$ds} = $val;
235
236       print STDERR "\$obj->{$member}{$ds} = $val;\n";
237     } # for (@val_list)
238   } # }}} for (@DSMappedMembers)
239
240   return ($obj);
241 } # _load_module_from_config
242
243 sub _load_module_generic
244 {
245   my $type = shift;
246   my $module = ucfirst (lc ($type));
247   my $obj;
248
249   $module =~ s/[^A-Za-z_]//g;
250   $module =~ s/_([A-Za-z])/\U$1\E/g;
251
252   $obj = _create_object ($module);
253   if (!$obj)
254   {
255     $obj = Collectd::Graph::Type->new ();
256     if (!$obj)
257     {
258       cluck ("Creating an Collectd::Graph::Type object failed");
259       return;
260     }
261   }
262
263   return ($obj);
264 } # _load_module_generic
265
266 =item B<tl_load_type> (I<$type>)
267
268 Does whatever is necessary to get an object with which to graph RRD files of
269 type I<$type>.
270
271 =cut
272
273 sub tl_load_type
274 {
275   my $type = shift;
276
277   if (defined $Configuration->{'type'}{$type})
278   {
279     return (_load_module_from_config ($Configuration->{'type'}{$type}));
280   }
281   else
282   {
283     return (_load_module_generic ($type));
284   }
285 } # tl_load_type
286
287 =back
288
289 =head1 SEE ALSO
290
291 L<Collectd::Graph::Type::GenericStacked>
292
293 =head1 AUTHOR AND LICENSE
294
295 Copyright (c) 2008 by Florian Forster
296 E<lt>octoE<nbsp>atE<nbsp>verplant.orgE<gt>. Licensed under the terms of the GNU
297 General Public License, VersionE<nbsp>2 (GPLv2).
298
299 =cut
300
301 # vim: set shiftwidth=2 softtabstop=2 tabstop=8 et fdm=marker :