set target: Implement a target to set fields in a value list.
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sun, 23 Nov 2008 17:19:34 +0000 (18:19 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sun, 23 Nov 2008 17:19:34 +0000 (18:19 +0100)
It's currently possible to re-set the `type'. This is most likely not
good and will result in unpredictable behavior. I'll remove that,
probably.

configure.in
src/Makefile.am
src/target_set.c [new file with mode: 0644]

index bcd4cc4..04fd27b 100644 (file)
@@ -2998,6 +2998,7 @@ AC_PLUGIN([swap],        [$plugin_swap],       [Swap usage statistics])
 AC_PLUGIN([syslog],      [$have_syslog],       [Syslog logging plugin])
 AC_PLUGIN([tail],        [yes],                [Parsing of logfiles])
 AC_PLUGIN([tape],        [$plugin_tape],       [Tape drive statistics])
+AC_PLUGIN([target_set],  [yes],                [The set target])
 AC_PLUGIN([tcpconns],    [$plugin_tcpconns],   [TCP connection statistics])
 AC_PLUGIN([teamspeak2],  [yes],                [TeamSpeak2 server statistics])
 AC_PLUGIN([thermal],     [$plugin_thermal],    [Linux ACPI thermal zone statistics])
@@ -3174,6 +3175,7 @@ Configuration:
     syslog  . . . . . . . $enable_syslog
     tail  . . . . . . . . $enable_tail
     tape  . . . . . . . . $enable_tape
+    target_set  . . . . . $enable_target_set
     tcpconns  . . . . . . $enable_tcpconns
     teamspeak2  . . . . . $enable_teamspeak2
     thermal . . . . . . . $enable_thermal
index d26f9b8..d868f96 100644 (file)
@@ -734,6 +734,14 @@ collectd_LDADD += "-dlopen" tape.la
 collectd_DEPENDENCIES += tape.la
 endif
 
+if BUILD_PLUGIN_TARGET_SET
+pkglib_LTLIBRARIES += target_set.la
+target_set_la_SOURCES = target_set.c
+target_set_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" target_set.la
+collectd_DEPENDENCIES += target_set.la
+endif
+
 if BUILD_PLUGIN_TCPCONNS
 pkglib_LTLIBRARIES += tcpconns.la
 tcpconns_la_SOURCES = tcpconns.c
diff --git a/src/target_set.c b/src/target_set.c
new file mode 100644 (file)
index 0000000..3a4220e
--- /dev/null
@@ -0,0 +1,253 @@
+/**
+ * collectd - src/target_set.c
+ * Copyright (C) 2008  Florian Forster
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian Forster <octo at verplant.org>
+ **/
+
+/*
+ * First tell the compiler to stick to the C99 and POSIX standards as close as
+ * possible.
+ */
+#ifndef __STRICT_ANSI__ /* {{{ */
+# define __STRICT_ANSI__
+#endif
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifdef _POSIX_C_SOURCE
+# undef _POSIX_C_SOURCE
+#endif
+#define _POSIX_C_SOURCE 200112L
+
+#if 0
+/* Single UNIX needed for strdup. */
+#ifdef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+#define _XOPEN_SOURCE 500
+#endif
+
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
+#ifndef _THREAD_SAFE
+# define _THREAD_SAFE
+#endif
+
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* }}} */
+
+#include "collectd.h"
+#include "common.h"
+#include "filter_chain.h"
+
+struct ts_data_s
+{
+  char *host;
+  char *plugin;
+  char *plugin_instance;
+  char *type;
+  char *type_instance;
+};
+typedef struct ts_data_s ts_data_t;
+
+static char *ts_strdup (const char *orig) /* {{{ */
+{
+  size_t sz;
+  char *dest;
+
+  if (orig == NULL)
+    return (NULL);
+
+  sz = strlen (orig) + 1;
+  dest = (char *) malloc (sz);
+  if (dest == NULL)
+    return (NULL);
+
+  memcpy (dest, orig, sz);
+
+  return (dest);
+} /* }}} char *ts_strdup */
+
+static int ts_config_add_string (char **dest, /* {{{ */
+    const oconfig_item_t *ci)
+{
+  char *temp;
+
+  if (dest == NULL)
+    return (-EINVAL);
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    ERROR ("Target `set': The `%s' option requires exactly one string "
+        "argument.", ci->key);
+    return (-1);
+  }
+
+  temp = ts_strdup (ci->values[0].value.string);
+  if (temp == NULL)
+  {
+    ERROR ("ts_config_add_string: ts_strdup failed.");
+    return (-1);
+  }
+
+  free (*dest);
+  *dest = temp;
+
+  return (0);
+} /* }}} int ts_config_add_string */
+
+static int ts_destroy (void **user_data) /* {{{ */
+{
+  ts_data_t *data;
+
+  if (user_data == NULL)
+    return (-EINVAL);
+
+  data = *user_data;
+  if (data == NULL)
+    return (0);
+
+  free (data->host);
+  free (data->plugin);
+  free (data->plugin_instance);
+  free (data->type);
+  free (data->type_instance);
+  free (data);
+
+  return (0);
+} /* }}} int ts_destroy */
+
+static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+  ts_data_t *data;
+  int status;
+  int i;
+
+  data = (ts_data_t *) malloc (sizeof (*data));
+  if (data == NULL)
+  {
+    ERROR ("ts_create: malloc failed.");
+    return (-ENOMEM);
+  }
+  memset (data, 0, sizeof (*data));
+
+  data->host = NULL;
+  data->plugin = NULL;
+  data->plugin_instance = NULL;
+  data->type = NULL;
+  data->type_instance = NULL;
+
+  status = 0;
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if ((strcasecmp ("Host", child->key) == 0)
+        || (strcasecmp ("Hostname", child->key) == 0))
+      status = ts_config_add_string (&data->host, child);
+    else if (strcasecmp ("Plugin", child->key) == 0)
+      status = ts_config_add_string (&data->plugin, child);
+    else if (strcasecmp ("PluginInstance", child->key) == 0)
+      status = ts_config_add_string (&data->plugin_instance, child);
+    else if (strcasecmp ("Type", child->key) == 0)
+      status = ts_config_add_string (&data->type, child);
+    else if (strcasecmp ("TypeInstance", child->key) == 0)
+      status = ts_config_add_string (&data->type_instance, child);
+    else
+    {
+      ERROR ("Target `set': The `%s' configuration option is not understood "
+          "and will be ignored.", child->key);
+      status = 0;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  /* Additional sanity-checking */
+  while (status == 0)
+  {
+    if ((data->host == NULL)
+        && (data->plugin == NULL)
+        && (data->plugin_instance == NULL)
+        && (data->type == NULL)
+        && (data->type_instance == NULL))
+    {
+      ERROR ("Target `set': You need to set at lease one of `Host', "
+          "`Plugin', `PluginInstance', `Type', or `TypeInstance'.");
+      status = -1;
+    }
+
+    break;
+  }
+
+  if (status != 0)
+  {
+    ts_destroy ((void *) &data);
+    return (status);
+  }
+
+  *user_data = data;
+  return (0);
+} /* }}} int ts_create */
+
+static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
+    notification_meta_t **meta, void **user_data)
+{
+  ts_data_t *data;
+
+  if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
+    return (-EINVAL);
+
+  data = *user_data;
+  if (data == NULL)
+  {
+    ERROR ("Target `set': Invoke: `data' is NULL.");
+    return (-EINVAL);
+  }
+
+#define SET_FIELD(f) if (data->f != NULL) { sstrncpy (vl->f, data->f, sizeof (vl->f)); }
+  SET_FIELD (host);
+  SET_FIELD (plugin);
+  SET_FIELD (plugin_instance);
+  SET_FIELD (type);
+  SET_FIELD (type_instance);
+
+  return (0);
+} /* }}} int ts_invoke */
+
+void module_register (void)
+{
+       target_proc_t tproc;
+
+       memset (&tproc, 0, sizeof (tproc));
+       tproc.create  = ts_create;
+       tproc.destroy = ts_destroy;
+       tproc.invoke  = ts_invoke;
+       fc_register_target ("set", tproc);
+} /* module_register */
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
+