package Collectd::Graph::TypeLoader;
=head1 NAME
Collectd::Graph::TypeLoader - Load a module according to the "type"
=cut
# Copyright (C) 2008,2009 Florian octo Forster <octo at verplant.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; only version 2 of the License is applicable.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
use strict;
use warnings;
use Carp (qw(cluck confess));
use Exporter ();
use Config::General ('ParseConfig');
use Collectd::Graph::Config ('gc_get_config');
use Collectd::Graph::Type ();
@Collectd::Graph::TypeLoader::ISA = ('Exporter');
@Collectd::Graph::TypeLoader::EXPORT_OK = ('tl_load_type');
our @ArrayMembers = (qw(data_sources rrd_opts custom_order));
our @ScalarMembers = (qw(rrd_title rrd_format rrd_vertical scale ignore_unknown stacking));
our @DSMappedMembers = (qw(ds_names rrd_colors));
our %MemberToConfigMap =
(
data_sources => 'datasources',
ds_names => 'dsname',
rrd_title => 'rrdtitle',
rrd_opts => 'rrdoptions',
rrd_format => 'rrdformat',
rrd_vertical => 'rrdverticallabel',
rrd_colors => 'color',
scale => 'scale', # GenericIO only
custom_order => 'order', # GenericStacked only
stacking => 'stacking', # GenericStacked only
ignore_unknown => 'ignoreunknown' # GenericStacked only
);
return (1);
sub _create_object
{
my $module = shift;
my $obj;
# Suppress warnings and error messages caused by the eval.
local $SIG{__WARN__} = sub { return (1); print STDERR "WARNING: " . join (', ', @_) . "\n"; };
local $SIG{__DIE__} = sub { return (1); print STDERR "FATAL: " . join (', ', @_) . "\n"; };
eval <<PERL;
require $module;
\$obj = ${module}->new ();
PERL
if (!$obj)
{
return;
}
return ($obj);
} # _create_object
sub _load_module_from_config
{
my $conf = shift;
my $module = $conf->{'module'};
my $obj;
if ($module && !($module =~ m/::/))
{
$module = "Collectd::Graph::Type::$module";
}
if ($module)
{
$obj = _create_object ($module);
if (!$obj)
{
#cluck ("Creating an $module object failed");
warn ("Creating an $module object failed");
return;
}
}
else
{
$obj = Collectd::Graph::Type->new ();
if (!$obj)
{
cluck ("Creating an Collectd::Graph::Type object failed");
return;
}
}
for (@ScalarMembers) # {{{
{
my $member = $_;
my $key = $MemberToConfigMap{$member};
my $val;
if (!defined $conf->{$key})
{
next;
}
$val = $conf->{$key};
if (ref ($val) ne '')
{
cluck ("Invalid value type for $key: " . ref ($val));
next;
}
$obj->{$member} = $val;
} # }}}
for (@ArrayMembers) # {{{
{
my $member = $_;
my $key = $MemberToConfigMap{$member};
my $val;
if (!defined $conf->{$key})
{
next;
}
$val = $conf->{$key};
if (ref ($val) eq 'ARRAY')
{
$obj->{$member} = $val;
}
elsif (ref ($val) eq '')
{
$obj->{$member} = [split (' ', $val)];
}
else
{
cluck ("Invalid value type for $key: " . ref ($val));
}
} # }}}
for (@DSMappedMembers) # {{{
{
my $member = $_;
my $key = $MemberToConfigMap{$member};
my @val_list;
if (!defined $conf->{$key})
{
next;
}
if (ref ($conf->{$key}) eq 'ARRAY')
{
@val_list = @{$conf->{$key}};
}
elsif (ref ($conf->{$key}) eq '')
{
@val_list = ($conf->{$key});
}
else
{
cluck ("Invalid value type for $key: " . ref ($conf->{$key}));
next;
}
for (@val_list)
{
my $line = $_;
my $ds;
my $val;
if (!defined ($line) || (ref ($line) ne ''))
{
next;
}
($ds, $val) = split (' ', $line, 2);
if (!$ds || !$val)
{
next;
}
$obj->{$member} ||= {};
$obj->{$member}{$ds} = $val;
} # for (@val_list)
} # }}} for (@DSMappedMembers)
return ($obj);
} # _load_module_from_config
sub _load_module_generic
{
my $type = shift;
my $module = ucfirst (lc ($type));
my $obj;
$module =~ s/[^A-Za-z_]//g;
$module =~ s/_([A-Za-z])/\U$1\E/g;
$obj = _create_object ($module);
if (!$obj)
{
$obj = Collectd::Graph::Type->new ();
if (!$obj)
{
cluck ("Creating an Collectd::Graph::Type object failed");
return;
}
}
return ($obj);
} # _load_module_generic
=head1 EXPORTED FUNCTIONS
=over 4
=item B<tl_load_type> (I<$type>)
Does whatever is necessary to get an object with which to graph RRD files of
type I<$type>.
=cut
sub tl_load_type
{
my $type = shift;
my $conf = gc_get_config ();
if (defined ($conf) && defined ($conf->{'type'}{$type}))
{
return (_load_module_from_config ($conf->{'type'}{$type}));
}
else
{
return (_load_module_generic ($type));
}
} # tl_load_type
=back
=head1 SEE ALSO
L<Collectd::Graph::Type::GenericStacked>
=head1 AUTHOR AND LICENSE
Copyright (c) 2008 by Florian Forster
E<lt>octoE<nbsp>atE<nbsp>verplant.orgE<gt>. Licensed under the terms of the GNU
General Public License, VersionE<nbsp>2 (GPLv2).
=cut
# vim: set shiftwidth=2 softtabstop=2 tabstop=8 et fdm=marker :