#define PLUGIN_WRITE 2
#define PLUGIN_SHUTDOWN 3
#define PLUGIN_LOG 4
+#define PLUGIN_NOTIF 5
-#define PLUGIN_TYPES 5
+#define PLUGIN_TYPES 6
#define PLUGIN_DATASET 255
static XS (Collectd_plugin_register_ds);
static XS (Collectd_plugin_unregister_ds);
static XS (Collectd_plugin_dispatch_values);
+static XS (Collectd_plugin_dispatch_notification);
static XS (Collectd_plugin_log);
static XS (Collectd_call_by_name);
{ "Collectd::plugin_register_data_set", Collectd_plugin_register_ds },
{ "Collectd::plugin_unregister_data_set", Collectd_plugin_unregister_ds },
{ "Collectd::plugin_dispatch_values", Collectd_plugin_dispatch_values },
+ { "Collectd::plugin_dispatch_notification",
+ Collectd_plugin_dispatch_notification },
{ "Collectd::plugin_log", Collectd_plugin_log },
{ "Collectd::call_by_name", Collectd_call_by_name },
{ "", NULL }
{ "Collectd::TYPE_WRITE", PLUGIN_WRITE },
{ "Collectd::TYPE_SHUTDOWN", PLUGIN_SHUTDOWN },
{ "Collectd::TYPE_LOG", PLUGIN_LOG },
+ { "Collectd::TYPE_NOTIF", PLUGIN_NOTIF },
{ "Collectd::TYPE_DATASET", PLUGIN_DATASET },
{ "Collectd::DS_TYPE_COUNTER", DS_TYPE_COUNTER },
{ "Collectd::DS_TYPE_GAUGE", DS_TYPE_GAUGE },
{ "Collectd::LOG_NOTICE", LOG_NOTICE },
{ "Collectd::LOG_INFO", LOG_INFO },
{ "Collectd::LOG_DEBUG", LOG_DEBUG },
+ { "Collectd::NOTIF_FAILURE", NOTIF_FAILURE },
+ { "Collectd::NOTIF_WARNING", NOTIF_WARNING },
+ { "Collectd::NOTIF_OKAY", NOTIF_OKAY },
{ "", 0 }
};
+struct {
+ char name[64];
+ char *var;
+} g_strings[] =
+{
+ { "Collectd::hostname_g", hostname_g },
+ { "", NULL }
+};
+
+struct {
+ char name[64];
+ int *var;
+} g_integers[] =
+{
+ { "Collectd::interval_g", &interval_g },
+ { "", NULL }
+};
+
/*
* Helper functions for data type conversion.
*/
return 0;
} /* static int value2av (value_list_t *, data_set_t *, HV *) */
+static int notification2hv (pTHX_ notification_t *n, HV *hash)
+{
+ if (NULL == hv_store (hash, "severity", 8, newSViv (n->severity), 0))
+ return -1;
+
+ if (0 != n->time)
+ if (NULL == hv_store (hash, "time", 4, newSViv (n->time), 0))
+ return -1;
+
+ if ('\0' != *n->message)
+ if (NULL == hv_store (hash, "message", 7, newSVpv (n->message, 0), 0))
+ return -1;
+
+ if ('\0' != *n->host)
+ if (NULL == hv_store (hash, "host", 4, newSVpv (n->host, 0), 0))
+ return -1;
+
+ if ('\0' != *n->plugin)
+ if (NULL == hv_store (hash, "plugin", 6, newSVpv (n->plugin, 0), 0))
+ return -1;
+
+ if ('\0' != *n->plugin_instance)
+ if (NULL == hv_store (hash, "plugin_instance", 15,
+ newSVpv (n->plugin_instance, 0), 0))
+ return -1;
+
+ if ('\0' != *n->type)
+ if (NULL == hv_store (hash, "type", 4, newSVpv (n->type, 0), 0))
+ return -1;
+
+ if ('\0' != *n->type_instance)
+ if (NULL == hv_store (hash, "type_instance", 13,
+ newSVpv (n->type_instance, 0), 0))
+ return -1;
+ return 0;
+} /* static int notification2hv (notification_t *, HV *) */
+
/*
* Internal functions.
*/
status = snprintf (buf, buf_len, "%s", module);
else
status = snprintf (buf, buf_len, "%s::%s", base_name, module);
- if ((status < 0) || (status >= buf_len))
+ if ((status < 0) || ((unsigned int)status >= buf_len))
return (NULL);
buf[buf_len - 1] = '\0';
return (buf);
static int pplugin_register_data_set (pTHX_ char *name, AV *dataset)
{
int len = -1;
+ int ret = 0;
int i = 0;
data_source_t *ds = NULL;
set->ds_num = len + 1;
set->ds = ds;
- return plugin_register_data_set (set);
+
+ ret = plugin_register_data_set (set);
+
+ free (ds);
+ free (set);
+ return ret;
} /* static int pplugin_register_data_set (char *, SV *) */
/*
list.plugin[DATA_MAX_NAME_LEN - 1] = '\0';
}
- if (NULL != (tmp = hv_fetch (values,
- "plugin_instance", 15, 0))) {
+ if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0))) {
strncpy (list.plugin_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
list.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
}
} /* static int pplugin_dispatch_values (char *, HV *) */
/*
+ * Dispatch a notification.
+ *
+ * notification:
+ * {
+ * severity => $severity,
+ * time => $time,
+ * message => $msg,
+ * host => $host,
+ * plugin => $plugin,
+ * type => $type,
+ * plugin_instance => $instance,
+ * type_instance => $type_instance
+ * }
+ */
+static int pplugin_dispatch_notification (pTHX_ HV *notif)
+{
+ notification_t n;
+
+ SV **tmp = NULL;
+
+ if (NULL == notif)
+ return -1;
+
+ memset (&n, 0, sizeof (n));
+
+ if (NULL != (tmp = hv_fetch (notif, "severity", 8, 0)))
+ n.severity = SvIV (*tmp);
+ else
+ n.severity = NOTIF_FAILURE;
+
+ if (NULL != (tmp = hv_fetch (notif, "time", 4, 0)))
+ n.time = (time_t)SvIV (*tmp);
+ else
+ n.time = time (NULL);
+
+ if (NULL != (tmp = hv_fetch (notif, "message", 7, 0)))
+ strncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
+ n.message[sizeof (n.message) - 1] = '\0';
+
+ if (NULL != (tmp = hv_fetch (notif, "host", 4, 0)))
+ strncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
+ else
+ strncpy (n.host, hostname_g, sizeof (n.host));
+ n.host[sizeof (n.host) - 1] = '\0';
+
+ if (NULL != (tmp = hv_fetch (notif, "plugin", 6, 0)))
+ strncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
+ n.plugin[sizeof (n.plugin) - 1] = '\0';
+
+ if (NULL != (tmp = hv_fetch (notif, "plugin_instance", 15, 0)))
+ strncpy (n.plugin_instance, SvPV_nolen (*tmp),
+ sizeof (n.plugin_instance));
+ n.plugin_instance[sizeof (n.plugin_instance) - 1] = '\0';
+
+ if (NULL != (tmp = hv_fetch (notif, "type", 4, 0)))
+ strncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
+ n.type[sizeof (n.type) - 1] = '\0';
+
+ if (NULL != (tmp = hv_fetch (notif, "type_instance", 13, 0)))
+ strncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
+ n.type_instance[sizeof (n.type_instance) - 1] = '\0';
+ return plugin_dispatch_notification (&n);
+} /* static int pplugin_dispatch_notification (HV *) */
+
+/*
* Call all working functions of the given type.
*/
static int pplugin_call_all (pTHX_ int type, ...)
ds = va_arg (ap, data_set_t *);
vl = va_arg (ap, value_list_t *);
- if (-1 == data_set2av (aTHX_ ds, pds))
- return -1;
+ if (-1 == data_set2av (aTHX_ ds, pds)) {
+ av_clear (pds);
+ av_undef (pds);
+ pds = Nullav;
+ ret = -1;
+ }
- if (-1 == value_list2hv (aTHX_ vl, ds, pvl))
- return -1;
+ if (-1 == value_list2hv (aTHX_ vl, ds, pvl)) {
+ hv_clear (pvl);
+ hv_undef (pvl);
+ pvl = Nullhv;
+ ret = -1;
+ }
XPUSHs (sv_2mortal (newSVpv (ds->type, 0)));
XPUSHs (sv_2mortal (newRV_noinc ((SV *)pds)));
XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
}
+ else if (PLUGIN_NOTIF == type) {
+ /*
+ * $_[0] =
+ * {
+ * severity => $severity,
+ * time => $time,
+ * message => $msg,
+ * host => $host,
+ * plugin => $plugin,
+ * type => $type,
+ * plugin_instance => $instance,
+ * type_instance => $type_instance
+ * };
+ */
+ notification_t *n;
+ HV *notif = newHV ();
+
+ n = va_arg (ap, notification_t *);
+
+ if (-1 == notification2hv (aTHX_ n, notif)) {
+ hv_clear (notif);
+ hv_undef (notif);
+ notif = Nullhv;
+ ret = -1;
+ }
+
+ XPUSHs (sv_2mortal (newRV_noinc ((SV *)notif)));
+ }
PUTBACK;
log_debug ("Collectd::plugin_unregister_data_set: type = \"%s\"",
SvPV_nolen (ST (0)));
- if (0 == pplugin_unregister_data_set (SvPV_nolen (ST (1))))
+ if (0 == pplugin_unregister_data_set (SvPV_nolen (ST (0))))
XSRETURN_YES;
else
XSRETURN_EMPTY;
} /* static XS (Collectd_plugin_dispatch_values) */
/*
+ * Collectd::plugin_dispatch_notification (notif).
+ *
+ * notif:
+ * notification to dispatch
+ */
+static XS (Collectd_plugin_dispatch_notification)
+{
+ SV *notif = NULL;
+
+ int ret = 0;
+
+ dXSARGS;
+
+ if (1 != items) {
+ log_err ("Usage: Collectd::plugin_dispatch_notification(notif)");
+ XSRETURN_EMPTY;
+ }
+
+ log_debug ("Collectd::plugin_dispatch_notification: notif = \"%s\"",
+ SvPV_nolen (ST (0)));
+
+ notif = ST (0);
+
+ if (! (SvROK (notif) && (SVt_PVHV == SvTYPE (SvRV (notif))))) {
+ log_err ("Collectd::plugin_dispatch_notification: Invalid notif.");
+ XSRETURN_EMPTY;
+ }
+
+ ret = pplugin_dispatch_notification (aTHX_ (HV *)SvRV (notif));
+
+ if (0 == ret)
+ XSRETURN_YES;
+ else
+ XSRETURN_EMPTY;
+} /* static XS (Collectd_plugin_dispatch_notification) */
+
+/*
* Collectd::plugin_log (level, message).
*
* level:
return;
} /* static void perl_log (int, const char *) */
+static int perl_notify (const notification_t *notif)
+{
+ dTHX;
+
+ if (NULL == perl_threads)
+ return 0;
+
+ if (NULL == aTHX) {
+ c_ithread_t *t = NULL;
+
+ pthread_mutex_lock (&perl_threads->mutex);
+ t = c_ithread_create (perl_threads->head->interp);
+ pthread_mutex_unlock (&perl_threads->mutex);
+
+ aTHX = t->interp;
+ }
+ return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
+} /* static int perl_notify (const notification_t *) */
+
static int perl_shutdown (void)
{
c_ithread_t *t = NULL;
aTHX, perl_threads->number_of_threads);
plugin_unregister_log ("perl");
+ plugin_unregister_notification ("perl");
plugin_unregister_init ("perl");
plugin_unregister_read ("perl");
plugin_unregister_write ("perl");
return ret;
} /* static void perl_shutdown (void) */
+/*
+ * Access functions for global variables.
+ *
+ * These functions implement the "magic" used to access
+ * the global variables from Perl.
+ */
+
+static int g_pv_get (pTHX_ SV *var, MAGIC *mg)
+{
+ char *pv = mg->mg_ptr;
+ sv_setpv (var, pv);
+ return 0;
+} /* static int g_pv_get (pTHX_ SV *, MAGIC *) */
+
+static int g_pv_set (pTHX_ SV *var, MAGIC *mg)
+{
+ char *pv = mg->mg_ptr;
+ strncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
+ pv[DATA_MAX_NAME_LEN - 1] = '\0';
+ return 0;
+} /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
+
+static int g_iv_get (pTHX_ SV *var, MAGIC *mg)
+{
+ int *iv = (int *)mg->mg_ptr;
+ sv_setiv (var, *iv);
+ return 0;
+} /* static int g_iv_get (pTHX_ SV *, MAGIC *) */
+
+static int g_iv_set (pTHX_ SV *var, MAGIC *mg)
+{
+ int *iv = (int *)mg->mg_ptr;
+ *iv = (int)SvIV (var);
+ return 0;
+} /* static int g_iv_set (pTHX_ SV *, MAGIC *) */
+
+static MGVTBL g_pv_vtbl = { g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL };
+static MGVTBL g_iv_vtbl = { g_iv_get, g_iv_set, NULL, NULL, NULL, NULL, NULL };
+
/* bootstrap the Collectd module */
static void xs_init (pTHX)
{
HV *stash = NULL;
+ SV *tmp = NULL;
char *file = __FILE__;
int i = 0;
/* export "constants" */
for (i = 0; '\0' != constants[i].name[0]; ++i)
newCONSTSUB (stash, constants[i].name, newSViv (constants[i].value));
+
+ /* export global variables
+ * by adding "magic" to the SV's representing the globale variables
+ * perl is able to automagically call the get/set function when
+ * accessing any such variable (this is basically the same as using
+ * tie() in Perl) */
+ /* global strings */
+ for (i = 0; '\0' != g_strings[i].name[0]; ++i) {
+ tmp = get_sv (g_strings[i].name, 1);
+ sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_pv_vtbl,
+ g_strings[i].var, 0);
+ }
+
+ /* global integers */
+ for (i = 0; '\0' != g_integers[i].name[0]; ++i) {
+ tmp = get_sv (g_integers[i].name, 1);
+ sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_iv_vtbl,
+ (char *)g_integers[i].var, 0);
+ }
return;
} /* static void xs_init (pTHX) */
perl_run (aTHX);
plugin_register_log ("perl", perl_log);
+ plugin_register_notification ("perl", perl_notify);
plugin_register_init ("perl", perl_init);
plugin_register_read ("perl", perl_read);
return 1;
}
+ if (NULL == aTHX) {
+ log_warn ("EnableDebugger has no effects if used after LoadPlugin.");
+ return 1;
+ }
+
value = ci->values[0].value.string;
if (NULL == aTHX) {