[collectd] [PATCH] perl plugin: Added "<Plugin>" configuration block.
Sebastian Harl
sh at tokkee.org
Tue Aug 26 11:56:31 CEST 2008
Similar to the global "<Plugin>" blocks this may be used to configure Perl
plugins. The oconfig_item_t object is converted to a Perl hash which will be
passed on to the registered configuration callback. A configuration
callback is registered using the TYPE_CONFIG identifier.
The Perl representation of the oconfig_item_t object looks like this:
{
'key' => '<key>',
'values' => [ '<val1>', '<val2>', ... ],
'children' => [ { ... }, { ... }, ... ]
}
Signed-off-by: Sebastian Harl <sh at tokkee.org>
---
bindings/perl/Collectd.pm | 43 ++++++++++++++-
src/perl.c | 135 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 177 insertions(+), 1 deletions(-)
diff --git a/bindings/perl/Collectd.pm b/bindings/perl/Collectd.pm
index bfc3080..738206b 100644
--- a/bindings/perl/Collectd.pm
+++ b/bindings/perl/Collectd.pm
@@ -56,6 +56,7 @@ our %EXPORT_TAGS = (
TYPE_LOG
TYPE_NOTIF
TYPE_FLUSH
+ TYPE_CONFIG
TYPE_DATASET
) ],
'ds_types' => [ qw(
@@ -98,6 +99,7 @@ our $interval_g;
Exporter::export_ok_tags ('all');
my @plugins : shared = ();
+my %cf_callbacks : shared = ();
my %types = (
TYPE_INIT, "init",
@@ -244,7 +246,8 @@ sub plugin_register {
return;
}
- if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)) {
+ if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)
+ && (TYPE_CONFIG != $type)) {
ERROR ("Collectd::plugin_register: Invalid type \"$type\"");
return;
}
@@ -252,6 +255,16 @@ sub plugin_register {
if ((TYPE_DATASET == $type) && ("ARRAY" eq ref $data)) {
return plugin_register_data_set ($name, $data);
}
+ elsif ((TYPE_CONFIG == $type) && (! ref $data)) {
+ my $pkg = scalar caller;
+
+ if ($data !~ m/^$pkg\:\:/) {
+ $data = $pkg . "::" . $data;
+ }
+
+ lock %cf_callbacks;
+ $cf_callbacks{$name} = $data;
+ }
elsif ((TYPE_DATASET != $type) && (! ref $data)) {
my $pkg = scalar caller;
@@ -291,6 +304,10 @@ sub plugin_unregister {
if (TYPE_DATASET == $type) {
return plugin_unregister_data_set ($name);
}
+ elsif (TYPE_CONFIG == $type) {
+ lock %cf_callbacks;
+ delete $cf_callbacks{$name};
+ }
elsif (defined $plugins[$type]) {
lock %{$plugins[$type]};
delete $plugins[$type]->{$name};
@@ -378,6 +395,30 @@ sub plugin_flush_all {
plugin_flush (timeout => $timeout);
}
+sub _plugin_dispatch_config {
+ my $plugin = shift;
+ my $config = shift;
+
+ our $cb_name = undef;
+
+ if (! (defined ($plugin) && defined ($config))) {
+ return;
+ }
+
+ if (! defined $cf_callbacks{$plugin}) {
+ WARNING ("Found a configuration for the \"$plugin\" plugin, but "
+ . "the plugin isn't loaded or didn't register "
+ . "a configuration callback.");
+ return;
+ }
+
+ {
+ lock %cf_callbacks;
+ $cb_name = $cf_callbacks{$plugin};
+ }
+ call_by_name ($config);
+}
+
1;
# vim: set sw=4 ts=4 tw=78 noexpandtab :
diff --git a/src/perl.c b/src/perl.c
index d34eff4..e6f7de0 100644
--- a/src/perl.c
+++ b/src/perl.c
@@ -71,6 +71,7 @@
#define PLUGIN_TYPES 7
+#define PLUGIN_CONFIG 254
#define PLUGIN_DATASET 255
#define log_debug(...) DEBUG ("perl: " __VA_ARGS__)
@@ -158,6 +159,7 @@ struct {
{ "Collectd::TYPE_LOG", PLUGIN_LOG },
{ "Collectd::TYPE_NOTIF", PLUGIN_NOTIF },
{ "Collectd::TYPE_FLUSH", PLUGIN_FLUSH },
+ { "Collectd::TYPE_CONFIG", PLUGIN_CONFIG },
{ "Collectd::TYPE_DATASET", PLUGIN_DATASET },
{ "Collectd::DS_TYPE_COUNTER", DS_TYPE_COUNTER },
{ "Collectd::DS_TYPE_GAUGE", DS_TYPE_GAUGE },
@@ -424,6 +426,81 @@ static int notification2hv (pTHX_ notification_t *n, HV *hash)
return 0;
} /* static int notification2hv (notification_t *, HV *) */
+static int oconfig_item2hv (pTHX_ oconfig_item_t *ci, HV *hash)
+{
+ int i;
+
+ AV *values;
+ AV *children;
+
+ if (NULL == hv_store (hash, "key", 3, newSVpv (ci->key, 0), 0))
+ return -1;
+
+ values = newAV ();
+ if (0 < ci->values_num)
+ av_extend (values, ci->values_num);
+
+ if (NULL == hv_store (hash, "values", 6, newRV_noinc ((SV *)values), 0)) {
+ av_clear (values);
+ av_undef (values);
+ return -1;
+ }
+
+ for (i = 0; i < ci->values_num; ++i) {
+ SV *value;
+
+ switch (ci->values[i].type) {
+ case OCONFIG_TYPE_STRING:
+ value = newSVpv (ci->values[i].value.string, 0);
+ break;
+ case OCONFIG_TYPE_NUMBER:
+ value = newSVnv ((NV)ci->values[i].value.number);
+ break;
+ case OCONFIG_TYPE_BOOLEAN:
+ value = ci->values[i].value.boolean ? &PL_sv_yes : &PL_sv_no;
+ break;
+ default:
+ log_err ("oconfig_item2hv: Invalid value type %i.",
+ ci->values[i].type);
+ value = &PL_sv_undef;
+ }
+
+ if (NULL == av_store (values, i, value)) {
+ sv_free (value);
+ return -1;
+ }
+ }
+
+ /* ignoring 'parent' member which is uninteresting in this case */
+
+ children = newAV ();
+ if (0 < ci->children_num)
+ av_extend (children, ci->children_num);
+
+ if (NULL == hv_store (hash, "children", 8, newRV_noinc ((SV *)children), 0)) {
+ av_clear (children);
+ av_undef (children);
+ return -1;
+ }
+
+ for (i = 0; i < ci->children_num; ++i) {
+ HV *child = newHV ();
+
+ if (0 != oconfig_item2hv (aTHX_ ci->children + i, child)) {
+ hv_clear (child);
+ hv_undef (child);
+ return -1;
+ }
+
+ if (NULL == av_store (children, i, newRV_noinc ((SV *)child))) {
+ hv_clear (child);
+ hv_undef (child);
+ return -1;
+ }
+ }
+ return 0;
+} /* static int oconfig_item2hv (pTHX_ oconfig_item_t *, HV *) */
+
/*
* Internal functions.
*/
@@ -1646,6 +1723,62 @@ static int perl_config_includedir (pTHX_ oconfig_item_t *ci)
return 0;
} /* static int perl_config_includedir (oconfig_item_it *) */
+/*
+ * <Plugin> block
+ */
+static int perl_config_plugin (pTHX_ oconfig_item_t *ci)
+{
+ int retvals = 0;
+ int ret = 0;
+
+ char *plugin;
+ HV *config;
+
+ dSP;
+
+ if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("LoadPlugin expects a single string argument.");
+ return 1;
+ }
+
+ plugin = ci->values[0].value.string;
+ config = newHV ();
+
+ if (0 != oconfig_item2hv (aTHX_ ci, config)) {
+ hv_clear (config);
+ hv_undef (config);
+
+ log_err ("Unable to convert configuration to a Perl hash value.");
+ config = Nullhv;
+ }
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK (SP);
+
+ XPUSHs (sv_2mortal (newSVpv (plugin, 0)));
+ XPUSHs (sv_2mortal (newRV_noinc ((SV *)config)));
+
+ PUTBACK;
+
+ retvals = call_pv ("Collectd::_plugin_dispatch_config", G_SCALAR);
+
+ SPAGAIN;
+ if (0 < retvals) {
+ SV *tmp = POPs;
+ if (! SvTRUE (tmp))
+ ret = -1;
+ }
+ else
+ ret = -1;
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ return ret;
+} /* static int perl_config_plugin (oconfig_item_it *) */
+
static int perl_config (oconfig_item_t *ci)
{
int i = 0;
@@ -1666,6 +1799,8 @@ static int perl_config (oconfig_item_t *ci)
perl_config_enabledebugger (aTHX_ c);
else if (0 == strcasecmp (c->key, "IncludeDir"))
perl_config_includedir (aTHX_ c);
+ else if (0 == strcasecmp (c->key, "Plugin"))
+ perl_config_plugin (aTHX_ c);
else
log_warn ("Ignoring unknown config key \"%s\".", c->key);
}
--
1.6.0.90.g436ed
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://mailman.verplant.org/pipermail/collectd/attachments/20080826/c53d1af5/attachment-0001.pgp
More information about the collectd
mailing list