9078110b3bb3216b9706e9d1cb5246f0177f34ec
1 package Collectd::Graph::TypeLoader;
3 =head1 NAME
5 Collectd::Graph::TypeLoader - Load a module according to the "type"
7 =cut
9 # Copyright (C) 2008,2009 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.
24 use strict;
25 use warnings;
27 use Carp (qw(cluck confess));
28 use Exporter ();
29 use Config::General ('ParseConfig');
30 use Collectd::Graph::Config ('gc_get_config');
31 use Collectd::Graph::Type ();
33 @Collectd::Graph::TypeLoader::ISA = ('Exporter');
34 @Collectd::Graph::TypeLoader::EXPORT_OK = ('tl_load_type');
36 our @ArrayMembers = (qw(data_sources rrd_opts custom_order));
37 our @ScalarMembers = (qw(rrd_title rrd_format rrd_vertical scale ignore_unknown stacking));
38 our @DSMappedMembers = (qw(ds_names rrd_colors));
40 our %MemberToConfigMap =
41 (
42 data_sources => 'datasources',
43 ds_names => 'dsname',
44 rrd_title => 'rrdtitle',
45 rrd_opts => 'rrdoptions',
46 rrd_format => 'rrdformat',
47 rrd_vertical => 'rrdverticallabel',
48 rrd_colors => 'color',
49 scale => 'scale', # GenericIO only
50 custom_order => 'order', # GenericStacked only
51 stacking => 'stacking', # GenericStacked only
52 ignore_unknown => 'ignoreunknown' # GenericStacked only
53 );
55 return (1);
57 sub _create_object
58 {
59 my $module = shift;
60 my $obj;
62 # Surpress warnings and error messages caused by the eval.
63 local $SIG{__WARN__} = sub { return (1); print STDERR "WARNING: " . join (', ', @_) . "\n"; };
64 local $SIG{__DIE__} = sub { return (1); print STDERR "FATAL: " . join (', ', @_) . "\n"; };
66 eval <<PERL;
67 require $module;
68 \$obj = ${module}->new ();
69 PERL
70 if (!$obj)
71 {
72 return;
73 }
75 return ($obj);
76 } # _create_object
78 sub _load_module_from_config
79 {
80 my $conf = shift;
82 my $module = $conf->{'module'};
83 my $obj;
85 if ($module && !($module =~ m/::/))
86 {
87 $module = "Collectd::Graph::Type::$module";
88 }
90 if ($module)
91 {
92 $obj = _create_object ($module);
93 if (!$obj)
94 {
95 cluck ("Creating an $module object failed");
96 return;
97 }
98 }
99 else
100 {
101 $obj = Collectd::Graph::Type->new ();
102 if (!$obj)
103 {
104 cluck ("Creating an Collectd::Graph::Type object failed");
105 return;
106 }
107 }
109 for (@ScalarMembers) # {{{
110 {
111 my $member = $_;
112 my $key = $MemberToConfigMap{$member};
113 my $val;
115 if (!defined $conf->{$key})
116 {
117 next;
118 }
119 $val = $conf->{$key};
121 if (ref ($val) ne '')
122 {
123 cluck ("Invalid value type for $key: " . ref ($val));
124 next;
125 }
127 $obj->{$member} = $val;
128 } # }}}
130 for (@ArrayMembers) # {{{
131 {
132 my $member = $_;
133 my $key = $MemberToConfigMap{$member};
134 my $val;
136 if (!defined $conf->{$key})
137 {
138 next;
139 }
140 $val = $conf->{$key};
142 if (ref ($val) eq 'ARRAY')
143 {
144 $obj->{$member} = $val;
145 }
146 elsif (ref ($val) eq '')
147 {
148 $obj->{$member} = [split (' ', $val)];
149 }
150 else
151 {
152 cluck ("Invalid value type for $key: " . ref ($val));
153 }
154 } # }}}
156 for (@DSMappedMembers) # {{{
157 {
158 my $member = $_;
159 my $key = $MemberToConfigMap{$member};
160 my @val_list;
162 if (!defined $conf->{$key})
163 {
164 next;
165 }
167 if (ref ($conf->{$key}) eq 'ARRAY')
168 {
169 @val_list = @{$conf->{$key}};
170 }
171 elsif (ref ($conf->{$key}) eq '')
172 {
173 @val_list = ($conf->{$key});
174 }
175 else
176 {
177 cluck ("Invalid value type for $key: " . ref ($conf->{$key}));
178 next;
179 }
181 for (@val_list)
182 {
183 my $line = $_;
184 my $ds;
185 my $val;
187 if (!defined ($line) || (ref ($line) ne ''))
188 {
189 next;
190 }
192 ($ds, $val) = split (' ', $line, 2);
193 if (!$ds || !$val)
194 {
195 next;
196 }
198 $obj->{$member} ||= {};
199 $obj->{$member}{$ds} = $val;
200 } # for (@val_list)
201 } # }}} for (@DSMappedMembers)
203 return ($obj);
204 } # _load_module_from_config
206 sub _load_module_generic
207 {
208 my $type = shift;
209 my $module = ucfirst (lc ($type));
210 my $obj;
212 $module =~ s/[^A-Za-z_]//g;
213 $module =~ s/_([A-Za-z])/\U$1\E/g;
215 $obj = _create_object ($module);
216 if (!$obj)
217 {
218 $obj = Collectd::Graph::Type->new ();
219 if (!$obj)
220 {
221 cluck ("Creating an Collectd::Graph::Type object failed");
222 return;
223 }
224 }
226 return ($obj);
227 } # _load_module_generic
229 =head1 EXPORTED FUNCTIONS
231 =over 4
233 =item B<tl_load_type> (I<$type>)
235 Does whatever is necessary to get an object with which to graph RRD files of
236 type I<$type>.
238 =cut
240 sub tl_load_type
241 {
242 my $type = shift;
243 my $conf = gc_get_config ();
245 if (defined ($conf) && defined ($conf->{'type'}{$type}))
246 {
247 return (_load_module_from_config ($conf->{'type'}{$type}));
248 }
249 else
250 {
251 return (_load_module_generic ($type));
252 }
253 } # tl_load_type
255 =back
257 =head1 SEE ALSO
259 L<Collectd::Graph::Type::GenericStacked>
261 =head1 AUTHOR AND LICENSE
263 Copyright (c) 2008 by Florian Forster
264 E<lt>octoE<nbsp>atE<nbsp>verplant.orgE<gt>. Licensed under the terms of the GNU
265 General Public License, VersionE<nbsp>2 (GPLv2).
267 =cut
269 # vim: set shiftwidth=2 softtabstop=2 tabstop=8 et fdm=marker :