Merge pull request #2831 from elieyal/patch-3
authorPavel Rochnyak <pavel2000@ngs.ru>
Wed, 27 Jun 2018 05:16:49 +0000 (12:16 +0700)
committerGitHub <noreply@github.com>
Wed, 27 Jun 2018 05:16:49 +0000 (12:16 +0700)
network plugin: Add BindAddress option

30 files changed:
Makefile.am
configure.ac
src/bind.c
src/collectd-snmp.pod
src/collectd-tg.c
src/collectd.conf.in
src/collectd.conf.pod
src/daemon/common.c
src/daemon/configfile.c
src/daemon/plugin.c
src/daemon/plugin.h
src/daemon/plugin_mock.c
src/filecount.c
src/gmond.c
src/memcachec.c
src/netapp.c
src/notify_email.c
src/redis.c
src/snmp.c
src/snmp_agent.c
src/snmp_agent_test.c
src/table.c
src/threshold.c
src/types.db
src/utils_db_query.c
src/utils_format_graphite.c
src/utils_rrdcreate.c
src/write_redis.c
src/write_riemann.c
src/write_sensu.c

index 83b76a0..190ce8e 100644 (file)
@@ -1558,7 +1558,7 @@ pkglib_LTLIBRARIES += snmp.la
 snmp_la_SOURCES = src/snmp.c
 snmp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
 snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS)
-snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS)
+snmp_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBNETSNMP_LIBS)
 endif
 
 if BUILD_PLUGIN_SNMP_AGENT
index eab3432..7a14e01 100644 (file)
@@ -767,6 +767,8 @@ AC_FUNC_STRERROR_R
 
 SAVE_CFLAGS="$CFLAGS"
 CFLAGS="-Wall -Werror"
+SAVE_LDFAGS="$LDFLAGS"
+LDFLAGS=""
 
 AC_CACHE_CHECK([for strtok_r],
   [c_cv_have_strtok_r_default],
@@ -839,6 +841,7 @@ if test "x$c_cv_have_strtok_r_default" = "xno"; then
 fi
 
 CFLAGS="$SAVE_CFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
 if test "x$c_cv_have_strtok_r_reentrant" = "xyes"; then
   CFLAGS="$CFLAGS -D_REENTRANT=1"
 fi
index 3a5e3c3..b012639 100644 (file)
@@ -73,9 +73,9 @@ typedef int (*list_callback_t)(const char *name, value_t value,
 struct cb_view_s {
   char *name;
 
-  int qtypes;
-  int resolver_stats;
-  int cacherrsets;
+  _Bool qtypes;
+  _Bool resolver_stats;
+  _Bool cacherrsets;
 
   char **zones;
   size_t zones_num;
@@ -107,12 +107,12 @@ typedef struct list_info_ptr_s list_info_ptr_t;
 static bool config_parse_time = true;
 
 static char *url;
-static int global_opcodes = 1;
-static int global_qtypes = 1;
-static int global_server_stats = 1;
-static int global_zone_maint_stats = 1;
-static int global_resolver_stats;
-static int global_memory_stats = 1;
+static _Bool global_opcodes = 1;
+static _Bool global_qtypes = 1;
+static _Bool global_server_stats = 1;
+static _Bool global_zone_maint_stats = 1;
+static _Bool global_resolver_stats;
+static _Bool global_memory_stats = 1;
 static int timeout = -1;
 
 static cb_view_t *views;
@@ -1410,22 +1410,6 @@ static int bind_xml(const char *data) /* {{{ */
   return ret;
 } /* }}} int bind_xml */
 
-static int bind_config_set_bool(const char *name, int *var, /* {{{ */
-                                oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) {
-    WARNING("bind plugin: The `%s' option needs "
-            "exactly one boolean argument.",
-            name);
-    return -1;
-  }
-
-  if (ci->values[0].value.boolean)
-    *var = 1;
-  else
-    *var = 0;
-  return 0;
-} /* }}} int bind_config_set_bool */
-
 static int bind_config_add_view_zone(cb_view_t *view, /* {{{ */
                                      oconfig_item_t *ci) {
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
@@ -1484,11 +1468,11 @@ static int bind_config_add_view(oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("QTypes", child->key) == 0)
-      bind_config_set_bool("QTypes", &tmp->qtypes, child);
+      cf_util_get_boolean(child, &tmp->qtypes);
     else if (strcasecmp("ResolverStats", child->key) == 0)
-      bind_config_set_bool("ResolverStats", &tmp->resolver_stats, child);
+      cf_util_get_boolean(child, &tmp->resolver_stats);
     else if (strcasecmp("CacheRRSets", child->key) == 0)
-      bind_config_set_bool("CacheRRSets", &tmp->cacherrsets, child);
+      cf_util_get_boolean(child, &tmp->cacherrsets);
     else if (strcasecmp("Zone", child->key) == 0)
       bind_config_add_view_zone(tmp, child);
     else {
@@ -1508,27 +1492,19 @@ static int bind_config(oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Url", child->key) == 0) {
-      if ((child->values_num != 1) ||
-          (child->values[0].type != OCONFIG_TYPE_STRING)) {
-        WARNING("bind plugin: The `Url' option needs "
-                "exactly one string argument.");
-        return -1;
-      }
-
-      sfree(url);
-      url = strdup(child->values[0].value.string);
+      cf_util_get_string(child, &url);
     } else if (strcasecmp("OpCodes", child->key) == 0)
-      bind_config_set_bool("OpCodes", &global_opcodes, child);
+      cf_util_get_boolean(child, &global_opcodes);
     else if (strcasecmp("QTypes", child->key) == 0)
-      bind_config_set_bool("QTypes", &global_qtypes, child);
+      cf_util_get_boolean(child, &global_qtypes);
     else if (strcasecmp("ServerStats", child->key) == 0)
-      bind_config_set_bool("ServerStats", &global_server_stats, child);
+      cf_util_get_boolean(child, &global_server_stats);
     else if (strcasecmp("ZoneMaintStats", child->key) == 0)
-      bind_config_set_bool("ZoneMaintStats", &global_zone_maint_stats, child);
+      cf_util_get_boolean(child, &global_zone_maint_stats);
     else if (strcasecmp("ResolverStats", child->key) == 0)
-      bind_config_set_bool("ResolverStats", &global_resolver_stats, child);
+      cf_util_get_boolean(child, &global_resolver_stats);
     else if (strcasecmp("MemoryStats", child->key) == 0)
-      bind_config_set_bool("MemoryStats", &global_memory_stats, child);
+      cf_util_get_boolean(child, &global_memory_stats);
     else if (strcasecmp("View", child->key) == 0)
       bind_config_add_view(child);
     else if (strcasecmp("ParseTime", child->key) == 0)
index 1415cb1..9d508d1 100644 (file)
@@ -26,6 +26,8 @@ collectd-snmp - Documentation of collectd's C<snmp plugin>
       Table true
       Type "if_octets"
       TypeInstanceOID "IF-MIB::ifDescr"
+      #FilterOID "IF-MIB::ifOperStatus"
+      #FilterValues "1", "2"
       Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
     </Data>
 
@@ -113,8 +115,9 @@ queried using the C<GET> SNMP command (see L<snmpget(1)>) and transmitted to
 collectd. B<One> value list is dispatched and, eventually, one file will be
 written.
 
-When B<Table> is set to B<true>, the OIDs given to B<Values> (see below) are
-queried using the C<GETNEXT> SNMP command until the subtree is left. After all
+When B<Table> is set to B<true>, the OIDs given to B<Values>, B<TypeInstanceOID>,
+B<PluginInstanceOID>, B<HostOID> and B<FilterOID> (see below) are queried using
+the C<GETNEXT> SNMP command until the subtree is left. After all
 the lists (think: all columns of the table) have been read B<several> values
 sets will be dispatches and, eventually, several files will be written. If you
 configure a B<Type> (see above) which needs more than one data source (for
@@ -167,23 +170,42 @@ Defaults to an empty string.
 
 =item B<PluginInstanceOID> I<OID>
 
+=item B<HostOID> I<OID>
+
 If B<Table> is set to I<true>, I<OID> is interpreted as an SNMP-prefix that will
-return a list of values. Those values are then used as the actual type-instance
-or plugin-instance of dispatched metrics. An example would be the
+return a list of values. Those values are then used as the actual type-instance,
+plugin-instance or host of dispatched metrics. An example would be the
 C<IF-MIB::ifDescr> subtree. L<variables(5)> from the SNMP distribution describes
-the format of OIDs. When set to empty string, then "SUBID" will be used as the
-instance.
+the format of OIDs. When option is set to empty string, then "SUBID" will be used
+as the value.
 
-Prefix may be set for values with use of B<InstancePrefix> option.
+Prefix may be set for values with use of appropriate B<TypeInstancePrefix>,
+B<PluginInstancePrefix> and B<HostPrefix> options.
 
 When B<Table> is set to I<false> these options has no effect.
-Only one of these options may be used in the same B<Data> block.
-
-Defaults:
 
+Defaults: When no one of these options is configured explicitly,
 B<TypeInstanceOID> defaults to an empty string.
 
-B<PluginInstanceOID> is not configured.
+=item B<TypeInstancePrefix>
+
+=item B<PluginInstancePrefix>
+
+=item B<HostPrefix>
+
+These options are intented to be used together with B<TypeInstanceOID>,
+B<PluginInstanceOID> and B<HostOID> respectively.
+
+If set, I<String> is preprended to values received by querying the agent.
+
+When B<Table> is set to I<false> these options has no effect.
+
+The C<UPS-MIB> is an example where you need this setting: It has voltages of
+the inlets, outlets and the battery of an UPS. However, it doesn't provide a
+descriptive column for these voltages. In this case having 1, 2,E<nbsp>... as
+instances is not enough, because the inlet voltages and outlet voltages may
+both have the subids 1, 2,E<nbsp>... You can use this setting to distinguish
+between the different voltages.
 
 =item B<Instance> I<Instance>
 
@@ -201,17 +223,8 @@ Note what B<Table> option must be set before setting B<Instance>.
 
 =item B<InstancePrefix> I<String>
 
-If B<Table> is set to I<true>, you may feel the need to add something to the
-instance of the files. If set, I<String> is prepended to the instance as
-determined by querying the agent. When B<Table> is set to I<false> this option
-has no effect.
-
-The C<UPS-MIB> is an example where you need this setting: It has voltages of
-the inlets, outlets and the battery of an UPS. However, it doesn't provide a
-descriptive column for these voltages. In this case having 1, 2,E<nbsp>... as
-instances is not enough, because the inlet voltages and outlet voltages may
-both have the subids 1, 2,E<nbsp>... You can use this setting to distinguish
-between the different voltages.
+Attention: this option exists for backwards compatibility only and will be
+removed in next major release. Please use B<TypeInstancePrefix> instead.
 
 =item B<Values> I<OID> [I<OID> ...]
 
@@ -249,16 +262,39 @@ This value is not applied to counter-values.
 
 =item B<Ignore> I<Value> [, I<Value> ...]
 
-The ignore values allows one to ignore Instances based on their name and the
-patterns specified by the various values you've entered. The match is a
+The ignore values allows one to ignore TypeInstances based on their name and
+the patterns specified by the various values you've entered. The match is a
 glob-type shell matching.
 
+When B<Table> is set to I<false> then this option has no effect.
+
 =item B<InvertMatch> I<true|false(default)>
 
 The invertmatch value should be use in combination of the Ignore option.
 It changes the behaviour of the Ignore option, from a blacklist behaviour
 when InvertMatch is set to false, to a whitelist when specified to true.
 
+=item B<FilterOID> I<OID>
+
+=item B<FilterValues> I<Value> [, I<Value> ...]
+
+=item B<FilterIgnoreSelected> I<true|false(default)>
+
+When B<Table> is set to I<true>, these options allow to configure filtering
+based on MIB values.
+
+The B<FilterOID> declares I<OID> to fill table column with values.
+The B<FilterValues> declares values list to do match. Whether table row will be
+collected or ignored depends on the B<FilterIgnoreSelected> setting.
+As with other plugins that use the daemon's ignorelist functionality, a string
+that starts and ends with a slash is interpreted as a regular expression.
+
+If no selection is configured at all, B<all> table rows are selected.
+
+When B<Table> is set to I<false> then these options has no effect.
+
+See B<Table> and F</"IGNORELISTS"> for details.
+
 =back
 
 =head2 The Host block
index 4669c65..2d83bbf 100644 (file)
@@ -105,7 +105,7 @@ static double dtime(void) /* {{{ */
 {
   struct timespec ts = {0};
 
-  if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+  if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
     perror("clock_gettime");
 
   return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
index ee89e94..74b6c88 100644 (file)
 #       Table true
 #       Type "if_octets"
 #       TypeInstanceOID "IF-MIB::ifDescr"
-#       #InstancePrefix "port"
+#       #TypeInstancePrefix "port"
 #       Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
+#       #FilterOID "IF-MIB::ifOperStatus"
+#       #FilterValues "1", "2"
 #   </Data>
 #   <Data "interface_traffic">
 #       Table true
index e2cd3a3..ccc6949 100644 (file)
@@ -7287,26 +7287,26 @@ Defaults to B<false>.
 
 =head2 Plugin C<redis>
 
-The I<Redis plugin> connects to one or more Redis servers and gathers
-information about each server's state. For each server there is a I<Node> block
-which configures the connection parameters for this node.
+The I<Redis plugin> connects to one or more Redis servers, gathers
+information about each server's state and executes user-defined queries.
+For each server there is a I<Node> block which configures the connection
+parameters and set of user-defined queries for this node.
 
   <Plugin redis>
     <Node "example">
         Host "localhost"
         Port "6379"
         Timeout 2000
+        ReportCommandStats false
+        ReportCpuUsage true
         <Query "LLEN myqueue">
           #Database 0
           Type "queue_length"
           Instance "myqueue"
-        <Query>
+        </Query>
     </Node>
   </Plugin>
 
-The information shown in the synopsis above is the I<default configuration>
-which is used by the plugin if no configuration is present.
-
 =over 4
 
 =item B<Node> I<Nodename>
@@ -7314,7 +7314,9 @@ which is used by the plugin if no configuration is present.
 The B<Node> block identifies a new Redis node, that is a new Redis instance
 running in an specified host and port. The name for node is a canonical
 identifier which is used as I<plugin instance>. It is limited to
-64E<nbsp>characters in length.
+128E<nbsp>characters in length.
+
+When no B<Node> is configured explicitly, plugin connects to "localhost:6379".
 
 =item B<Host> I<Hostname>
 
@@ -7334,30 +7336,47 @@ Use I<Password> to authenticate when connecting to I<Redis>.
 =item B<Timeout> I<Milliseconds>
 
 The B<Timeout> option set the socket timeout for node response. Since the Redis
-read function is blocking, you should keep this value as low as possible. Keep
-in mind that the sum of all B<Timeout> values for all B<Nodes> should be lower
-than B<Interval> defined globally.
+read function is blocking, you should keep this value as low as possible.
+It is expected what B<Timeout> values should be lower than B<Interval> defined
+globally.
 
-=item B<Query> I<Querystring>
+Defaults to 2000 (2 seconds).
 
-The B<Query> block identifies a query to execute against the redis server.
-There may be an arbitrary number of queries to execute.
+=item B<ReportCommandStats> B<false>|B<true>
 
-=item B<Database> I<Index>
+Enables or disables reporting of statistics based on the command type, including
+rate of command calls and average CPU time consumed by command processing.
+Defaults to B<false>.
 
-This index selects the Redis logical database to use for query. Defaults
-to C<0>.
+=item B<ReportCpuUsage> B<true>|B<false>
+
+Enables or disables reporting of CPU consumption statistics.
+Defaults to B<true>.
+
+=item B<Query> I<Querystring>
+
+The B<Query> block identifies a query to execute against the redis server.
+There may be an arbitrary number of queries to execute. Each query should
+return single string or integer.
 
 =item B<Type> I<Collectd type>
 
-Within a query definition, a valid collectd type to use as when submitting
+Within a query definition, a valid I<collectd type> to use as when submitting
 the result of the query. When not supplied, will default to B<gauge>.
 
+Currently only types with one datasource are supported.
+See L<types.db(5)> for more details on types and their configuration.
+
 =item B<Instance> I<Type instance>
 
 Within a query definition, an optional type instance to use when submitting
 the result of the query. When not supplied will default to the escaped
-command, up to 64 chars.
+command, up to 128 chars.
+
+=item B<Database> I<Index>
+
+This index selects the Redis logical database to use for query. Defaults
+to C<0>.
 
 =back
 
index 2251d2e..76c7036 100644 (file)
@@ -417,7 +417,7 @@ int strunescape(char *buf, size_t buf_len) {
       continue;
 
     if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
-      ERROR("string unescape: backslash found at end of string.");
+      P_ERROR("string unescape: backslash found at end of string.");
       /* Ensure null-byte at the end of the buffer. */
       buf[i] = 0;
       return -1;
@@ -606,9 +606,9 @@ int check_create_dir(const char *file_orig) {
      * behavior.
      */
     if (fields[i][0] == '.') {
-      ERROR("Cowardly refusing to create a directory that "
-            "begins with a `.' (dot): `%s'",
-            file_orig);
+      P_ERROR("Cowardly refusing to create a directory that "
+              "begins with a `.' (dot): `%s'",
+              file_orig);
       return -2;
     }
 
@@ -619,7 +619,7 @@ int check_create_dir(const char *file_orig) {
     if (strjoin(dir + path_is_absolute,
                 (size_t)(sizeof(dir) - path_is_absolute), fields,
                 (size_t)(i + 1), "/") < 0) {
-      ERROR("strjoin failed: `%s', component #%i", file_orig, i);
+      P_ERROR("strjoin failed: `%s', component #%i", file_orig, i);
       return -1;
     }
 
@@ -635,16 +635,16 @@ int check_create_dir(const char *file_orig) {
           if (EEXIST == errno)
             continue;
 
-          ERROR("check_create_dir: mkdir (%s): %s", dir, STRERRNO);
+          P_ERROR("check_create_dir: mkdir (%s): %s", dir, STRERRNO);
           return -1;
         } else {
-          ERROR("check_create_dir: stat (%s): %s", dir, STRERRNO);
+          P_ERROR("check_create_dir: stat (%s): %s", dir, STRERRNO);
           return -1;
         }
       } else if (!S_ISDIR(statbuf.st_mode)) {
-        ERROR("check_create_dir: `%s' exists but is not "
-              "a directory!",
-              dir);
+        P_ERROR("check_create_dir: `%s' exists but is not "
+                "a directory!",
+                dir);
         return -1;
       }
       break;
@@ -667,12 +667,12 @@ int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name) {
 
   *ksp_ptr = kstat_lookup(kc, module, instance, name);
   if (*ksp_ptr == NULL) {
-    ERROR("get_kstat: Cound not find kstat %s", ident);
+    P_ERROR("get_kstat: Cound not find kstat %s", ident);
     return -1;
   }
 
   if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) {
-    ERROR("get_kstat: kstat %s has wrong type", ident);
+    P_ERROR("get_kstat: kstat %s has wrong type", ident);
     *ksp_ptr = NULL;
     return -1;
   }
@@ -683,12 +683,12 @@ int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name) {
 #endif
 
   if (kstat_read(kc, *ksp_ptr, NULL) == -1) {
-    ERROR("get_kstat: kstat %s could not be read", ident);
+    P_ERROR("get_kstat: kstat %s could not be read", ident);
     return -1;
   }
 
   if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) {
-    ERROR("get_kstat: kstat %s has wrong type", ident);
+    P_ERROR("get_kstat: kstat %s has wrong type", ident);
     return -1;
   }
 
@@ -700,12 +700,12 @@ long long get_kstat_value(kstat_t *ksp, char *name) {
   long long retval = -1LL;
 
   if (ksp == NULL) {
-    ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name);
+    P_ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name);
     return -1LL;
   } else if (ksp->ks_type != KSTAT_TYPE_NAMED) {
-    ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
-          "is not KSTAT_TYPE_NAMED (%#x).",
-          name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED);
+    P_ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
+            "is not KSTAT_TYPE_NAMED (%#x).",
+            name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED);
     return -1LL;
   }
 
@@ -723,7 +723,7 @@ long long get_kstat_value(kstat_t *ksp, char *name) {
   else if (kn->data_type == KSTAT_DATA_UINT64)
     retval = (long long)kn->value.ui64; /* XXX: Might overflow! */
   else
-    WARNING("get_kstat_value: Not a numeric value: %s", name);
+    P_WARNING("get_kstat_value: Not a numeric value: %s", name);
 
   return retval;
 }
@@ -1035,19 +1035,19 @@ int parse_value(const char *value_orig, value_t *ret_value, int ds_type) {
 
   default:
     sfree(value);
-    ERROR("parse_value: Invalid data source type: %i.", ds_type);
+    P_ERROR("parse_value: Invalid data source type: %i.", ds_type);
     return -1;
   }
 
   if (value == endptr) {
-    ERROR("parse_value: Failed to parse string as %s: \"%s\".",
-          DS_TYPE_TO_STRING(ds_type), value);
+    P_ERROR("parse_value: Failed to parse string as %s: \"%s\".",
+            DS_TYPE_TO_STRING(ds_type), value);
     sfree(value);
     return -1;
   } else if ((NULL != endptr) && ('\0' != *endptr))
-    INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
-         "Input string was \"%s\".",
-         endptr, DS_TYPE_TO_STRING(ds_type), value_orig);
+    P_INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
+           "Input string was \"%s\".",
+           endptr, DS_TYPE_TO_STRING(ds_type), value_orig);
 
   sfree(value);
   return 0;
@@ -1212,7 +1212,7 @@ int walk_directory(const char *dir, dirwalk_callback_f callback,
   failure = 0;
 
   if ((dh = opendir(dir)) == NULL) {
-    ERROR("walk_directory: Cannot open '%s': %s", dir, STRERRNO);
+    P_ERROR("walk_directory: Cannot open '%s': %s", dir, STRERRNO);
     return -1;
   }
 
@@ -1252,7 +1252,7 @@ ssize_t read_file_contents(const char *filename, char *buf, size_t bufsize) {
 
   ret = (ssize_t)fread(buf, 1, bufsize, fh);
   if ((ret == 0) && (ferror(fh) != 0)) {
-    ERROR("read_file_contents: Reading file \"%s\" failed.", filename);
+    P_ERROR("read_file_contents: Reading file \"%s\" failed.", filename);
     ret = -1;
   }
 
@@ -1411,8 +1411,8 @@ int service_name_to_port_number(const char *service_name) {
 
   status = getaddrinfo(/* node = */ NULL, service_name, &ai_hints, &ai_list);
   if (status != 0) {
-    ERROR("service_name_to_port_number: getaddrinfo failed: %s",
-          gai_strerror(status));
+    P_ERROR("service_name_to_port_number: getaddrinfo failed: %s",
+            gai_strerror(status));
     return -1;
   }
 
@@ -1450,7 +1450,7 @@ void set_sock_opts(int sockfd) /* {{{ */
   status = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype,
                       &(socklen_t){sizeof(socktype)});
   if (status != 0) {
-    WARNING("set_sock_opts: failed to determine socket type");
+    P_WARNING("set_sock_opts: failed to determine socket type");
     return;
   }
 
@@ -1458,14 +1458,14 @@ void set_sock_opts(int sockfd) /* {{{ */
     status =
         setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int));
     if (status != 0)
-      WARNING("set_sock_opts: failed to set socket keepalive flag");
+      P_WARNING("set_sock_opts: failed to set socket keepalive flag");
 
 #ifdef TCP_KEEPIDLE
     int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
     status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle,
                         sizeof(tcp_keepidle));
     if (status != 0)
-      WARNING("set_sock_opts: failed to set socket tcp keepalive time");
+      P_WARNING("set_sock_opts: failed to set socket tcp keepalive time");
 #endif
 
 #ifdef TCP_KEEPINTVL
@@ -1474,7 +1474,7 @@ void set_sock_opts(int sockfd) /* {{{ */
     status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepintvl,
                         sizeof(tcp_keepintvl));
     if (status != 0)
-      WARNING("set_sock_opts: failed to set socket tcp keepalive interval");
+      P_WARNING("set_sock_opts: failed to set socket tcp keepalive interval");
 #endif
   }
 } /* }}} void set_sock_opts */
@@ -1558,12 +1558,12 @@ int check_capability(int arg) /* {{{ */
     return -1;
 
   if (!(cap = cap_get_proc())) {
-    ERROR("check_capability: cap_get_proc failed.");
+    P_ERROR("check_capability: cap_get_proc failed.");
     return -1;
   }
 
   if (cap_get_flag(cap, cap_value, CAP_EFFECTIVE, &cap_flag_value) < 0) {
-    ERROR("check_capability: cap_get_flag failed.");
+    P_ERROR("check_capability: cap_get_flag failed.");
     cap_free(cap);
     return -1;
   }
@@ -1574,8 +1574,8 @@ int check_capability(int arg) /* {{{ */
 #else
 int check_capability(__attribute__((unused)) int arg) /* {{{ */
 {
-  WARNING("check_capability: unsupported capability implementation. "
-          "Some plugin(s) may require elevated privileges to work properly.");
+  P_WARNING("check_capability: unsupported capability implementation. "
+            "Some plugin(s) may require elevated privileges to work properly.");
   return 0;
 } /* }}} int check_capability */
 #endif /* HAVE_CAPABILITY */
index f88d234..d903800 100644 (file)
@@ -251,11 +251,7 @@ static int dispatch_value_plugindir(oconfig_item_t *ci) {
 }
 
 static int dispatch_loadplugin(oconfig_item_t *ci) {
-  const char *name;
   bool global = false;
-  plugin_ctx_t ctx = {0};
-  plugin_ctx_t old_ctx;
-  int ret_val;
 
   assert(strcasecmp(ci->key, "LoadPlugin") == 0);
 
@@ -265,14 +261,16 @@ static int dispatch_loadplugin(oconfig_item_t *ci) {
     return -1;
   }
 
-  name = ci->values[0].value.string;
+  const char *name = ci->values[0].value.string;
   if (strcmp("libvirt", name) == 0)
     name = "virt";
 
   /* default to the global interval set before loading this plugin */
-  ctx.interval = cf_get_default_interval();
-  ctx.flush_interval = 0;
-  ctx.flush_timeout = 0;
+  plugin_ctx_t ctx = {
+      .interval = cf_get_default_interval(), .name = strdup(name),
+  };
+  if (ctx.name == NULL)
+    return ENOMEM;
 
   for (int i = 0; i < ci->children_num; ++i) {
     oconfig_item_t *child = ci->children + i;
@@ -288,12 +286,12 @@ static int dispatch_loadplugin(oconfig_item_t *ci) {
     else {
       WARNING("Ignoring unknown LoadPlugin option \"%s\" "
               "for plugin \"%s\"",
-              child->key, ci->values[0].value.string);
+              child->key, name);
     }
   }
 
-  old_ctx = plugin_set_ctx(ctx);
-  ret_val = plugin_load(name, global);
+  plugin_ctx_t old_ctx = plugin_set_ctx(ctx);
+  int ret_val = plugin_load(name, global);
   /* reset to the "global" context */
   plugin_set_ctx(old_ctx);
 
@@ -1048,16 +1046,12 @@ int cf_read(const char *filename) {
  * success. */
 int cf_util_get_string(const oconfig_item_t *ci, char **ret_string) /* {{{ */
 {
-  char *string;
-
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    ERROR("cf_util_get_string: The %s option requires "
-          "exactly one string argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
     return -1;
   }
 
-  string = strdup(ci->values[0].value.string);
+  char *string = strdup(ci->values[0].value.string);
   if (string == NULL)
     return -1;
 
@@ -1076,9 +1070,7 @@ int cf_util_get_string_buffer(const oconfig_item_t *ci, char *buffer, /* {{{ */
     return EINVAL;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    ERROR("cf_util_get_string_buffer: The %s option requires "
-          "exactly one string argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
     return -1;
   }
 
@@ -1095,9 +1087,7 @@ int cf_util_get_int(const oconfig_item_t *ci, int *ret_value) /* {{{ */
     return EINVAL;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    ERROR("cf_util_get_int: The %s option requires "
-          "exactly one numeric argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
     return -1;
   }
 
@@ -1112,9 +1102,7 @@ int cf_util_get_double(const oconfig_item_t *ci, double *ret_value) /* {{{ */
     return EINVAL;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    ERROR("cf_util_get_double: The %s option requires "
-          "exactly one numeric argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
     return -1;
   }
 
@@ -1130,9 +1118,7 @@ int cf_util_get_boolean(const oconfig_item_t *ci, bool *ret_bool) /* {{{ */
 
   if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN) &&
                                 (ci->values[0].type != OCONFIG_TYPE_STRING))) {
-    ERROR("cf_util_get_boolean: The %s option requires "
-          "exactly one boolean argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one boolean argument.", ci->key);
     return -1;
   }
 
@@ -1141,19 +1127,19 @@ int cf_util_get_boolean(const oconfig_item_t *ci, bool *ret_bool) /* {{{ */
     *ret_bool = ci->values[0].value.boolean ? true : false;
     break;
   case OCONFIG_TYPE_STRING:
-    WARNING("cf_util_get_boolean: Using string value `%s' for boolean option "
-            "`%s' is deprecated and will be removed in future releases. "
-            "Use unquoted true or false instead.",
-            ci->values[0].value.string, ci->key);
+    P_WARNING("Using string value `%s' for boolean option `%s' is deprecated "
+              "and will be removed in future releases. Use unquoted true or "
+              "false instead.",
+              ci->values[0].value.string, ci->key);
 
     if (IS_TRUE(ci->values[0].value.string))
       *ret_bool = true;
     else if (IS_FALSE(ci->values[0].value.string))
       *ret_bool = false;
     else {
-      ERROR("cf_util_get_boolean: Cannot parse string value `%s' of the `%s' "
-            "option as a boolean value.",
-            ci->values[0].value.string, ci->key);
+      P_ERROR("Cannot parse string value `%s' of the `%s' option as a boolean "
+              "value.",
+              ci->values[0].value.string, ci->key);
       return -1;
     }
     break;
@@ -1194,9 +1180,7 @@ int cf_util_get_port_number(const oconfig_item_t *ci) /* {{{ */
 
   if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) &&
                                 (ci->values[0].type != OCONFIG_TYPE_NUMBER))) {
-    ERROR("cf_util_get_port_number: The \"%s\" option requires "
-          "exactly one string argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
     return -1;
   }
 
@@ -1206,11 +1190,9 @@ int cf_util_get_port_number(const oconfig_item_t *ci) /* {{{ */
   assert(ci->values[0].type == OCONFIG_TYPE_NUMBER);
   tmp = (int)(ci->values[0].value.number + 0.5);
   if ((tmp < 1) || (tmp > 65535)) {
-    ERROR("cf_util_get_port_number: The \"%s\" option requires "
-          "a service name or a port number. The number "
-          "you specified, %i, is not in the valid "
-          "range of 1-65535.",
-          ci->key, tmp);
+    P_ERROR("The `%s' option requires a service name or a port number. The "
+            "number you specified, %i, is not in the valid range of 1-65535.",
+            ci->key, tmp);
     return -1;
   }
 
@@ -1224,18 +1206,15 @@ int cf_util_get_service(const oconfig_item_t *ci, char **ret_string) /* {{{ */
   int status;
 
   if (ci->values_num != 1) {
-    ERROR("cf_util_get_service: The %s option requires exactly "
-          "one argument.",
-          ci->key);
+    P_ERROR("The `%s` option requires exactly one argument.", ci->key);
     return -1;
   }
 
   if (ci->values[0].type == OCONFIG_TYPE_STRING)
     return cf_util_get_string(ci, ret_string);
   if (ci->values[0].type != OCONFIG_TYPE_NUMBER) {
-    ERROR("cf_util_get_service: The %s option requires "
-          "exactly one string or numeric argument.",
-          ci->key);
+    P_ERROR("The `%s` option requires exactly one string or numeric argument.",
+            ci->key);
   }
 
   port = 0;
@@ -1243,16 +1222,14 @@ int cf_util_get_service(const oconfig_item_t *ci, char **ret_string) /* {{{ */
   if (status != 0)
     return status;
   else if ((port < 1) || (port > 65535)) {
-    ERROR("cf_util_get_service: The port number given "
-          "for the %s option is out of "
-          "range (%i).",
-          ci->key, port);
+    P_ERROR("The port number given for the `%s` option is out of range (%i).",
+            ci->key, port);
     return -1;
   }
 
   service = malloc(6);
   if (service == NULL) {
-    ERROR("cf_util_get_service: Out of memory.");
+    P_ERROR("cf_util_get_service: Out of memory.");
     return -1;
   }
   snprintf(service, 6, "%i", port);
@@ -1269,16 +1246,13 @@ int cf_util_get_cdtime(const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */
     return EINVAL;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    ERROR("cf_util_get_cdtime: The %s option requires "
-          "exactly one numeric argument.",
-          ci->key);
+    P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
     return -1;
   }
 
   if (ci->values[0].value.number < 0.0) {
-    ERROR("cf_util_get_cdtime: The numeric argument of the %s "
-          "option must not be negative.",
-          ci->key);
+    P_ERROR("The numeric argument of the `%s' option must not be negative.",
+            ci->key);
     return -1;
   }
 
index 427a813..92e1ab2 100644 (file)
@@ -346,19 +346,22 @@ static void log_list_callbacks(llist_t **list, /* {{{ */
 static int create_register_callback(llist_t **list, /* {{{ */
                                     const char *name, void *callback,
                                     user_data_t const *ud) {
-  callback_func_t *cf;
 
-  cf = calloc(1, sizeof(*cf));
+  if (name == NULL || callback == NULL)
+    return EINVAL;
+
+  callback_func_t *cf = calloc(1, sizeof(*cf));
   if (cf == NULL) {
     free_userdata(ud);
     ERROR("plugin: create_register_callback: calloc failed.");
-    return -1;
+    return ENOMEM;
   }
 
   cf->cf_callback = callback;
   if (ud == NULL) {
-    cf->cf_udata.data = NULL;
-    cf->cf_udata.free_func = NULL;
+    cf->cf_udata = (user_data_t){
+        .data = NULL, .free_func = NULL,
+    };
   } else {
     cf->cf_udata = *ud;
   }
@@ -1714,8 +1717,12 @@ int plugin_write(const char *plugin, /* {{{ */
       callback_func_t *cf = le->value;
       plugin_write_cb callback;
 
-      /* do not switch plugin context; rather keep the context (interval)
-       * information of the calling read plugin */
+      /* Keep the read plugin's interval and flush information but update the
+       * plugin name. */
+      plugin_ctx_t old_ctx = plugin_get_ctx();
+      plugin_ctx_t ctx = old_ctx;
+      ctx.name = cf->cf_ctx.name;
+      plugin_set_ctx(ctx);
 
       DEBUG("plugin: plugin_write: Writing values via %s.", le->key);
       callback = cf->cf_callback;
@@ -1725,6 +1732,7 @@ int plugin_write(const char *plugin, /* {{{ */
       else
         success++;
 
+      plugin_set_ctx(old_ctx);
       le = le->next;
     }
 
@@ -2236,6 +2244,21 @@ void plugin_log(int level, const char *format, ...) {
   }
 } /* void plugin_log */
 
+void daemon_log(int level, const char *format, ...) {
+  char msg[1024] = ""; // Size inherits from plugin_log()
+
+  char const *name = plugin_get_ctx().name;
+  if (name == NULL)
+    name = "UNKNOWN";
+
+  va_list ap;
+  va_start(ap, format);
+  vsnprintf(msg, sizeof(msg), format, ap);
+  va_end(ap);
+
+  plugin_log(level, "%s plugin: %s", name, msg);
+} /* void daemon_log */
+
 int parse_log_severity(const char *severity) {
   int log_level = -1;
 
index 0369067..871eccd 100644 (file)
@@ -171,6 +171,7 @@ struct user_data_s {
 typedef struct user_data_s user_data_t;
 
 struct plugin_ctx_s {
+  char *name;
   cdtime_t interval;
   cdtime_t flush_interval;
   cdtime_t flush_timeout;
@@ -398,6 +399,15 @@ int parse_notif_severity(const char *severity);
 #define DEBUG(...) /* noop */
 #endif             /* ! COLLECT_DEBUG */
 
+/* This will log messages, prefixed by plugin name */
+void daemon_log(int level, const char *format, ...)
+    __attribute__((format(printf, 2, 3)));
+
+#define P_ERROR(...) daemon_log(LOG_ERR, __VA_ARGS__)
+#define P_WARNING(...) daemon_log(LOG_WARNING, __VA_ARGS__)
+#define P_NOTICE(...) daemon_log(LOG_NOTICE, __VA_ARGS__)
+#define P_INFO(...) daemon_log(LOG_INFO, __VA_ARGS__)
+
 const data_set_t *plugin_get_ds(const char *name);
 
 int plugin_notification_meta_add_string(notification_t *n, const char *name,
index a11d4f5..1624f0e 100644 (file)
@@ -170,6 +170,17 @@ void plugin_log(int level, char const *format, ...) {
   printf("plugin_log (%i, \"%s\");\n", level, buffer);
 }
 
+void daemon_log(int level, char const *format, ...) {
+  char buffer[1024];
+  va_list ap;
+
+  va_start(ap, format);
+  vsnprintf(buffer, sizeof(buffer), format, ap);
+  va_end(ap);
+
+  printf("daemon_log (%i, \"%s\");\n", level, buffer);
+}
+
 void plugin_init_ctx(void) { /* nop */
 }
 
index ef1a138..9091ff5 100644 (file)
@@ -154,26 +154,6 @@ static int fc_config_add_dir_instance(fc_directory_conf_t *dir,
   return fc_config_set_instance(dir, ci->values[0].value.string);
 } /* int fc_config_add_dir_instance */
 
-static int fc_config_add_dir_name(fc_directory_conf_t *dir,
-                                  oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("filecount plugin: The `Name' config option needs exactly one "
-            "string argument.");
-    return -1;
-  }
-
-  char *temp = strdup(ci->values[0].value.string);
-  if (temp == NULL) {
-    ERROR("filecount plugin: strdup failed.");
-    return -1;
-  }
-
-  sfree(dir->name);
-  dir->name = temp;
-
-  return 0;
-} /* int fc_config_add_dir_name */
-
 static int fc_config_add_dir_mtime(fc_directory_conf_t *dir,
                                    oconfig_item_t *ci) {
   if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) &&
@@ -369,7 +349,7 @@ static int fc_config_add_dir(oconfig_item_t *ci) {
     else if (strcasecmp("Instance", option->key) == 0)
       status = fc_config_add_dir_instance(dir, option);
     else if (strcasecmp("Name", option->key) == 0)
-      status = fc_config_add_dir_name(dir, option);
+      status = cf_util_get_string(option, &dir->name);
     else if (strcasecmp("MTime", option->key) == 0)
       status = fc_config_add_dir_mtime(dir, option);
     else if (strcasecmp("Size", option->key) == 0)
index ca65419..2bca05a 100644 (file)
@@ -833,28 +833,6 @@ static int mc_receive_thread_stop(void) /* {{{ */
  *   </Metric>
  * </Plugin>
  */
-static int gmond_config_set_string(oconfig_item_t *ci, char **str) /* {{{ */
-{
-  char *tmp;
-
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("gmond plugin: The `%s' option needs "
-            "exactly one string argument.",
-            ci->key);
-    return -1;
-  }
-
-  tmp = strdup(ci->values[0].value.string);
-  if (tmp == NULL) {
-    ERROR("gmond plugin: strdup failed.");
-    return -1;
-  }
-
-  sfree(*str);
-  *str = tmp;
-  return 0;
-} /* }}} int gmond_config_set_string */
-
 static int gmond_config_add_metric(oconfig_item_t *ci) /* {{{ */
 {
   metric_map_t *map;
@@ -889,11 +867,11 @@ static int gmond_config_add_metric(oconfig_item_t *ci) /* {{{ */
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
     if (strcasecmp("Type", child->key) == 0)
-      gmond_config_set_string(child, &map->type);
+      cf_util_get_string(child, &map->type);
     else if (strcasecmp("TypeInstance", child->key) == 0)
-      gmond_config_set_string(child, &map->type_instance);
+      cf_util_get_string(child, &map->type_instance);
     else if (strcasecmp("DataSource", child->key) == 0)
-      gmond_config_set_string(child, &map->ds_name);
+      cf_util_get_string(child, &map->ds_name);
     else {
       WARNING("gmond plugin: Unknown configuration option `%s' ignored.",
               child->key);
index 13e388e..f293aa1 100644 (file)
@@ -123,21 +123,6 @@ static int cmc_page_init_memc(web_page_t *wp) /* {{{ */
   return 0;
 } /* }}} int cmc_page_init_memc */
 
-static int cmc_config_add_string(const char *name, char **dest, /* {{{ */
-                                 oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("memcachec plugin: `%s' needs exactly one string argument.", name);
-    return -1;
-  }
-
-  sfree(*dest);
-  *dest = strdup(ci->values[0].value.string);
-  if (*dest == NULL)
-    return -1;
-
-  return 0;
-} /* }}} int cmc_config_add_string */
-
 static int cmc_config_add_match_dstype(int *dstype_ret, /* {{{ */
                                        oconfig_item_t *ci) {
   int dstype;
@@ -204,16 +189,15 @@ static int cmc_config_add_match(web_page_t *page, /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Regex", child->key) == 0)
-      status = cmc_config_add_string("Regex", &match->regex, child);
+      status = cf_util_get_string(child, &match->regex);
     else if (strcasecmp("ExcludeRegex", child->key) == 0)
-      status =
-          cmc_config_add_string("ExcludeRegex", &match->exclude_regex, child);
+      status = cf_util_get_string(child, &match->exclude_regex);
     else if (strcasecmp("DSType", child->key) == 0)
       status = cmc_config_add_match_dstype(&match->dstype, child);
     else if (strcasecmp("Type", child->key) == 0)
-      status = cmc_config_add_string("Type", &match->type, child);
+      status = cf_util_get_string(child, &match->type);
     else if (strcasecmp("Instance", child->key) == 0)
-      status = cmc_config_add_string("Instance", &match->instance, child);
+      status = cf_util_get_string(child, &match->instance);
     else {
       WARNING("memcachec plugin: Option `%s' not allowed here.", child->key);
       status = -1;
@@ -301,11 +285,11 @@ static int cmc_config_add_page(oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Server", child->key) == 0)
-      status = cmc_config_add_string("Server", &page->server, child);
+      status = cf_util_get_string(child, &page->server);
     else if (strcasecmp("Key", child->key) == 0)
-      status = cmc_config_add_string("Key", &page->key, child);
+      status = cf_util_get_string(child, &page->key);
     else if (strcasecmp("Plugin", child->key) == 0)
-      status = cmc_config_add_string("Plugin", &page->plugin_name, child);
+      status = cf_util_get_string(child, &page->plugin_name);
     else if (strcasecmp("Match", child->key) == 0)
       /* Be liberal with failing matches => don't set `status'. */
       cmc_config_add_match(page, child);
index 281764c..62600ca 100644 (file)
@@ -2229,42 +2229,6 @@ static int cna_query_system(host_config_t *host) /* {{{ */
 /*
  * Configuration handling
  */
-/* Sets a given flag if the boolean argument is true and unsets the flag if it
- * is false. On error, the flag-field is not changed. */
-static int cna_config_bool_to_flag(const oconfig_item_t *ci, /* {{{ */
-                                   uint32_t *flags, uint32_t flag) {
-  if ((ci == NULL) || (flags == NULL))
-    return EINVAL;
-
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) {
-    WARNING("netapp plugin: The %s option needs exactly one boolean argument.",
-            ci->key);
-    return -1;
-  }
-
-  if (ci->values[0].value.boolean)
-    *flags |= flag;
-  else
-    *flags &= ~flag;
-
-  return 0;
-} /* }}} int cna_config_bool_to_flag */
-
-/* Handling of the "Interval" option which is allowed in every block. */
-static int cna_config_get_interval(const oconfig_item_t *ci, /* {{{ */
-                                   cna_interval_t *out_interval) {
-  cdtime_t tmp = 0;
-  int status;
-
-  status = cf_util_get_cdtime(ci, &tmp);
-  if (status != 0)
-    return status;
-
-  out_interval->interval = tmp;
-  out_interval->last_read = 0;
-
-  return 0;
-} /* }}} int cna_config_get_interval */
 
 /* Handling of the "GetIO", "GetOps" and "GetLatency" options within a
  * <VolumePerf /> block. */
@@ -2385,7 +2349,7 @@ static int cna_config_volume_performance(host_config_t *host, /* {{{ */
 
     /* if (!item || !item->key || !*item->key) continue; */
     if (strcasecmp(item->key, "Interval") == 0)
-      cna_config_get_interval(item, &cfg_volume_perf->interval);
+      cf_util_get_cdtime(item, &cfg_volume_perf->interval.interval);
     else if (!strcasecmp(item->key, "GetIO"))
       cna_config_volume_perf_option(cfg_volume_perf, item);
     else if (!strcasecmp(item->key, "GetOps"))
@@ -2481,7 +2445,7 @@ static int cna_config_quota(host_config_t *host, oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *item = ci->children + i;
 
     if (strcasecmp(item->key, "Interval") == 0)
-      cna_config_get_interval(item, &cfg_quota->interval);
+      cf_util_get_cdtime(item, &cfg_quota->interval.interval);
     else
       WARNING("netapp plugin: The option %s is not allowed within "
               "`Quota' blocks.",
@@ -2517,9 +2481,9 @@ static int cna_config_disk(host_config_t *host, oconfig_item_t *ci) { /* {{{ */
 
     /* if (!item || !item->key || !*item->key) continue; */
     if (strcasecmp(item->key, "Interval") == 0)
-      cna_config_get_interval(item, &cfg_disk->interval);
+      cf_util_get_cdtime(item, &cfg_disk->interval.interval);
     else if (strcasecmp(item->key, "GetBusy") == 0)
-      cna_config_bool_to_flag(item, &cfg_disk->flags, CFG_DISK_BUSIEST);
+      cf_util_get_flag(item, &cfg_disk->flags, CFG_DISK_BUSIEST);
   }
 
   if ((cfg_disk->flags & CFG_DISK_ALL) == 0) {
@@ -2556,15 +2520,15 @@ static int cna_config_wafl(host_config_t *host, oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *item = ci->children + i;
 
     if (strcasecmp(item->key, "Interval") == 0)
-      cna_config_get_interval(item, &cfg_wafl->interval);
+      cf_util_get_cdtime(item, &cfg_wafl->interval.interval);
     else if (!strcasecmp(item->key, "GetNameCache"))
-      cna_config_bool_to_flag(item, &cfg_wafl->flags, CFG_WAFL_NAME_CACHE);
+      cf_util_get_flag(item, &cfg_wafl->flags, CFG_WAFL_NAME_CACHE);
     else if (!strcasecmp(item->key, "GetDirCache"))
-      cna_config_bool_to_flag(item, &cfg_wafl->flags, CFG_WAFL_DIR_CACHE);
+      cf_util_get_flag(item, &cfg_wafl->flags, CFG_WAFL_DIR_CACHE);
     else if (!strcasecmp(item->key, "GetBufferCache"))
-      cna_config_bool_to_flag(item, &cfg_wafl->flags, CFG_WAFL_BUF_CACHE);
+      cf_util_get_flag(item, &cfg_wafl->flags, CFG_WAFL_BUF_CACHE);
     else if (!strcasecmp(item->key, "GetInodeCache"))
-      cna_config_bool_to_flag(item, &cfg_wafl->flags, CFG_WAFL_INODE_CACHE);
+      cf_util_get_flag(item, &cfg_wafl->flags, CFG_WAFL_INODE_CACHE);
     else
       WARNING("netapp plugin: The %s config option is not allowed within "
               "`WAFL' blocks.",
@@ -2636,7 +2600,7 @@ static int cna_config_volume_usage(host_config_t *host, /* {{{ */
 
     /* if (!item || !item->key || !*item->key) continue; */
     if (strcasecmp(item->key, "Interval") == 0)
-      cna_config_get_interval(item, &cfg_volume_usage->interval);
+      cf_util_get_cdtime(item, &cfg_volume_usage->interval.interval);
     else if (!strcasecmp(item->key, "GetCapacity"))
       cna_config_volume_usage_option(cfg_volume_usage, item);
     else if (!strcasecmp(item->key, "GetSnapshot"))
@@ -2677,7 +2641,7 @@ static int cna_config_snapvault(host_config_t *host, /* {{{ */
     oconfig_item_t *item = ci->children + i;
 
     if (strcasecmp(item->key, "Interval") == 0)
-      cna_config_get_interval(item, &cfg_snapvault->interval);
+      cf_util_get_cdtime(item, &cfg_snapvault->interval.interval);
     else
       WARNING("netapp plugin: The option %s is not allowed within "
               "`SnapVault' blocks.",
@@ -2712,15 +2676,15 @@ static int cna_config_system(host_config_t *host, /* {{{ */
     oconfig_item_t *item = ci->children + i;
 
     if (strcasecmp(item->key, "Interval") == 0) {
-      cna_config_get_interval(item, &cfg_system->interval);
+      cf_util_get_cdtime(item, &cfg_system->interval.interval);
     } else if (!strcasecmp(item->key, "GetCPULoad")) {
-      cna_config_bool_to_flag(item, &cfg_system->flags, CFG_SYSTEM_CPU);
+      cf_util_get_flag(item, &cfg_system->flags, CFG_SYSTEM_CPU);
     } else if (!strcasecmp(item->key, "GetInterfaces")) {
-      cna_config_bool_to_flag(item, &cfg_system->flags, CFG_SYSTEM_NET);
+      cf_util_get_flag(item, &cfg_system->flags, CFG_SYSTEM_NET);
     } else if (!strcasecmp(item->key, "GetDiskOps")) {
-      cna_config_bool_to_flag(item, &cfg_system->flags, CFG_SYSTEM_OPS);
+      cf_util_get_flag(item, &cfg_system->flags, CFG_SYSTEM_OPS);
     } else if (!strcasecmp(item->key, "GetDiskIO")) {
-      cna_config_bool_to_flag(item, &cfg_system->flags, CFG_SYSTEM_DISK);
+      cf_util_get_flag(item, &cfg_system->flags, CFG_SYSTEM_DISK);
     } else {
       WARNING("netapp plugin: The %s config option is not allowed within "
               "`System' blocks.",
index 6b32ad9..bb36ff2 100644 (file)
@@ -211,8 +211,8 @@ static int notify_email_notification(const notification_t *n,
   char subject[MAXSTRING];
 
   char buf[4096] = "";
+  char *buf_ptr = buf;
   int buf_len = sizeof(buf);
-  int i;
 
   snprintf(severity, sizeof(severity), "%s",
            (n->severity == NOTIF_FAILURE)
@@ -231,15 +231,36 @@ static int notify_email_notification(const notification_t *n,
   timestamp_str[sizeof(timestamp_str) - 1] = '\0';
 
   /* Let's make RFC822 message text with \r\n EOLs */
-  snprintf(buf, buf_len, "MIME-Version: 1.0\r\n"
-                         "Content-Type: text/plain; charset=\"US-ASCII\"\r\n"
-                         "Content-Transfer-Encoding: 8bit\r\n"
-                         "Subject: %s\r\n"
-                         "\r\n"
-                         "%s - %s@%s\r\n"
-                         "\r\n"
-                         "Message: %s",
-           subject, timestamp_str, severity, n->host, n->message);
+  int status = snprintf(buf, buf_len,
+                        "MIME-Version: 1.0\r\n"
+                        "Content-Type: text/plain; charset=\"US-ASCII\"\r\n"
+                        "Content-Transfer-Encoding: 8bit\r\n"
+                        "Subject: %s\r\n"
+                        "\r\n"
+                        "%s - %s@%s\r\n"
+                        "\r\n",
+                        subject, timestamp_str, severity, n->host);
+
+  if (status > 0) {
+    buf_ptr += status;
+    buf_len -= status;
+  }
+
+#define APPEND(format, value)                                                  \
+  if ((buf_len > 0) && (strlen(value) > 0)) {                                  \
+    status = snprintf(buf_ptr, buf_len, format "\r\n", value);                 \
+    if (status > 0) {                                                          \
+      buf_ptr += status;                                                       \
+      buf_len -= status;                                                       \
+    }                                                                          \
+  }
+
+  APPEND("Host: %s", n->host);
+  APPEND("Plugin: %s", n->plugin);
+  APPEND("Plugin instance: %s", n->plugin_instance);
+  APPEND("Type: %s", n->type);
+  APPEND("Type instance: %s", n->type_instance);
+  APPEND("\r\nMessage: %s", n->message);
 
   pthread_mutex_lock(&session_lock);
 
@@ -258,7 +279,7 @@ static int notify_email_notification(const notification_t *n,
   smtp_set_header(message, "To", NULL, NULL);
   smtp_set_message_str(message, buf);
 
-  for (i = 0; i < recipients_len; i++)
+  for (int i = 0; i < recipients_len; i++)
     smtp_add_recipient(message, recipients[i]);
 
   /* Initiate a connection to the SMTP server and transfer the message. */
index 5734098..36f57b0 100644 (file)
 #include <hiredis/hiredis.h>
 #include <sys/time.h>
 
-#ifndef HOST_NAME_MAX
-#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
-#endif
-
 #define REDIS_DEF_HOST "localhost"
 #define REDIS_DEF_PASSWD ""
 #define REDIS_DEF_PORT 6379
-#define REDIS_DEF_TIMEOUT 2000
+#define REDIS_DEF_TIMEOUT_SEC 2
 #define REDIS_DEF_DB_COUNT 256
-#define MAX_REDIS_NODE_NAME 64
-#define MAX_REDIS_PASSWD_LENGTH 512
 #define MAX_REDIS_VAL_SIZE 256
 #define MAX_REDIS_QUERY 2048
 
@@ -68,54 +62,59 @@ struct redis_query_s {
 struct redis_node_s;
 typedef struct redis_node_s redis_node_t;
 struct redis_node_s {
-  char name[MAX_REDIS_NODE_NAME];
-  char host[HOST_NAME_MAX];
-  char passwd[MAX_REDIS_PASSWD_LENGTH];
+  char *name;
+  char *host;
+  char *passwd;
   int port;
   struct timeval timeout;
+  bool report_command_stats;
+  bool report_cpu_usage;
+  redisContext *redisContext;
   redis_query_t *queries;
 
   redis_node_t *next;
 };
 
-static redis_node_t *nodes_head;
+static bool redis_have_instances;
+static int redis_read(user_data_t *user_data);
 
-static int redis_node_add(const redis_node_t *rn) /* {{{ */
-{
-  redis_node_t *rn_copy;
-  redis_node_t *rn_ptr;
+static void redis_node_free(void *arg) {
+  redis_node_t *rn = arg;
+  if (rn == NULL)
+    return;
 
-  /* Check for duplicates first */
-  for (rn_ptr = nodes_head; rn_ptr != NULL; rn_ptr = rn_ptr->next)
-    if (strcmp(rn->name, rn_ptr->name) == 0)
-      break;
-
-  if (rn_ptr != NULL) {
-    ERROR("redis plugin: A node with the name `%s' already exists.", rn->name);
-    return -1;
+  redis_query_t *rq = rn->queries;
+  while (rq != NULL) {
+    redis_query_t *next = rq->next;
+    sfree(rq);
+    rq = next;
   }
 
-  rn_copy = malloc(sizeof(*rn_copy));
-  if (rn_copy == NULL) {
-    ERROR("redis plugin: malloc failed adding redis_node to the tree.");
-    return -1;
-  }
-
-  memcpy(rn_copy, rn, sizeof(*rn_copy));
-  rn_copy->next = NULL;
+  redisFree(rn->redisContext);
+  sfree(rn->name);
+  sfree(rn->host);
+  sfree(rn->passwd);
+  sfree(rn);
+} /* void redis_node_free */
 
+static int redis_node_add(redis_node_t *rn) /* {{{ */
+{
   DEBUG("redis plugin: Adding node \"%s\".", rn->name);
 
-  if (nodes_head == NULL)
-    nodes_head = rn_copy;
-  else {
-    rn_ptr = nodes_head;
-    while (rn_ptr->next != NULL)
-      rn_ptr = rn_ptr->next;
-    rn_ptr->next = rn_copy;
-  }
+  /* Disable automatic generation of default instance in the init callback. */
+  redis_have_instances = true;
 
-  return 0;
+  char cb_name[sizeof("redis/") + DATA_MAX_NAME_LEN];
+  snprintf(cb_name, sizeof(cb_name), "redis/%s", rn->name);
+
+  return plugin_register_complex_read(
+      /* group = */ "redis",
+      /* name      = */ cb_name,
+      /* callback  = */ redis_read,
+      /* interval  = */ 0,
+      &(user_data_t){
+          .data = rn, .free_func = redis_node_free,
+      });
 } /* }}} */
 
 static redis_query_t *redis_config_query(oconfig_item_t *ci) /* {{{ */
@@ -171,44 +170,63 @@ err:
 
 static int redis_config_node(oconfig_item_t *ci) /* {{{ */
 {
-  redis_query_t *rq;
-  int status;
-  int timeout;
+  redis_node_t *rn = calloc(1, sizeof(*rn));
+  if (rn == NULL) {
+    ERROR("redis plugin: calloc failed adding node.");
+    return ENOMEM;
+  }
 
-  redis_node_t rn = {.port = REDIS_DEF_PORT,
-                     .timeout.tv_usec = REDIS_DEF_TIMEOUT};
+  rn->port = REDIS_DEF_PORT;
+  rn->timeout.tv_sec = REDIS_DEF_TIMEOUT_SEC;
+  rn->report_cpu_usage = true;
 
-  sstrncpy(rn.host, REDIS_DEF_HOST, sizeof(rn.host));
+  rn->host = strdup(REDIS_DEF_HOST);
+  if (rn->host == NULL) {
+    ERROR("redis plugin: strdup failed adding node.");
+    sfree(rn);
+    return ENOMEM;
+  }
 
-  status = cf_util_get_string_buffer(ci, rn.name, sizeof(rn.name));
-  if (status != 0)
+  int status = cf_util_get_string(ci, &rn->name);
+  if (status != 0) {
+    sfree(rn->host);
+    sfree(rn);
     return status;
+  }
 
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *option = ci->children + i;
 
     if (strcasecmp("Host", option->key) == 0)
-      status = cf_util_get_string_buffer(option, rn.host, sizeof(rn.host));
+      status = cf_util_get_string(option, &rn->host);
     else if (strcasecmp("Port", option->key) == 0) {
       status = cf_util_get_port_number(option);
       if (status > 0) {
-        rn.port = status;
+        rn->port = status;
         status = 0;
       }
     } else if (strcasecmp("Query", option->key) == 0) {
-      rq = redis_config_query(option);
+      redis_query_t *rq = redis_config_query(option);
       if (rq == NULL) {
         status = 1;
       } else {
-        rq->next = rn.queries;
-        rn.queries = rq;
+        rq->next = rn->queries;
+        rn->queries = rq;
       }
     } else if (strcasecmp("Timeout", option->key) == 0) {
+      int timeout;
       status = cf_util_get_int(option, &timeout);
-      if (status == 0)
-        rn.timeout.tv_usec = timeout;
+      if (status == 0) {
+        rn->timeout.tv_usec = timeout * 1000;
+        rn->timeout.tv_sec = rn->timeout.tv_usec / 1000000L;
+        rn->timeout.tv_usec %= 1000000L;
+      }
     } else if (strcasecmp("Password", option->key) == 0)
-      status = cf_util_get_string_buffer(option, rn.passwd, sizeof(rn.passwd));
+      status = cf_util_get_string(option, &rn->passwd);
+    else if (strcasecmp("ReportCommandStats", option->key) == 0)
+      status = cf_util_get_boolean(option, &rn->report_command_stats);
+    else if (strcasecmp("ReportCpuUsage", option->key) == 0)
+      status = cf_util_get_boolean(option, &rn->report_cpu_usage);
     else
       WARNING("redis plugin: Option `%s' not allowed inside a `Node' "
               "block. I'll ignore this option.",
@@ -218,10 +236,12 @@ static int redis_config_node(oconfig_item_t *ci) /* {{{ */
       break;
   }
 
-  if (status != 0)
+  if (status != 0) {
+    redis_node_free(rn);
     return status;
+  }
 
-  return redis_node_add(&rn);
+  return redis_node_add(rn);
 } /* }}} int redis_config_node */
 
 static int redis_config(oconfig_item_t *ci) /* {{{ */
@@ -237,17 +257,12 @@ static int redis_config(oconfig_item_t *ci) /* {{{ */
               option->key);
   }
 
-  if (nodes_head == NULL) {
-    ERROR("redis plugin: No valid node configuration could be found.");
-    return ENOENT;
-  }
-
   return 0;
 } /* }}} */
 
 __attribute__((nonnull(2))) static void
-redis_submit(char *plugin_instance, const char *type, const char *type_instance,
-             value_t value) /* {{{ */
+redis_submit(const char *plugin_instance, const char *type,
+             const char *type_instance, value_t value) /* {{{ */
 {
   value_list_t vl = VALUE_LIST_INIT;
 
@@ -263,28 +278,78 @@ redis_submit(char *plugin_instance, const char *type, const char *type_instance,
   plugin_dispatch_values(&vl);
 } /* }}} */
 
+__attribute__((nonnull(2))) static void
+redis_submit2(const char *plugin_instance, const char *type,
+              const char *type_instance, value_t value0,
+              value_t value1) /* {{{ */
+{
+  value_list_t vl = VALUE_LIST_INIT;
+  value_t values[] = {value0, value1};
+
+  vl.values = values;
+  vl.values_len = STATIC_ARRAY_SIZE(values);
+
+  sstrncpy(vl.plugin, "redis", sizeof(vl.plugin));
+  sstrncpy(vl.type, type, sizeof(vl.type));
+
+  if (plugin_instance != NULL)
+    sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
+
+  if (type_instance != NULL)
+    sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+
+  plugin_dispatch_values(&vl);
+} /* }}} */
+
 static int redis_init(void) /* {{{ */
 {
-  redis_node_t rn = {.name = "default",
-                     .host = REDIS_DEF_HOST,
-                     .port = REDIS_DEF_PORT,
-                     .timeout.tv_sec = 0,
-                     .timeout.tv_usec = REDIS_DEF_TIMEOUT,
-                     .next = NULL};
+  if (redis_have_instances)
+    return 0;
 
-  if (nodes_head == NULL)
-    redis_node_add(&rn);
+  redis_node_t *rn = calloc(1, sizeof(*rn));
+  if (rn == NULL)
+    return ENOMEM;
 
-  return 0;
+  rn->port = REDIS_DEF_PORT;
+  rn->timeout.tv_sec = REDIS_DEF_TIMEOUT_SEC;
+
+  rn->name = strdup("default");
+  rn->host = strdup(REDIS_DEF_HOST);
+
+  if (rn->name == NULL || rn->host == NULL) {
+    sfree(rn->name);
+    sfree(rn->host);
+    sfree(rn);
+    return ENOMEM;
+  }
+
+  return redis_node_add(rn);
 } /* }}} int redis_init */
 
-static int redis_handle_info(char *node, char const *info_line,
-                             char const *type, char const *type_instance,
-                             char const *field_name, int ds_type) /* {{{ */
-{
+static void *c_redisCommand(redis_node_t *rn, const char *format, ...) {
+  redisContext *c = rn->redisContext;
+
+  if (c == NULL)
+    return NULL;
+
+  va_list ap;
+  va_start(ap, format);
+  void *reply = redisvCommand(c, format, ap);
+  va_end(ap);
+
+  if (reply == NULL) {
+    ERROR("redis plugin: Connection error: %s", c->errstr);
+    redisFree(rn->redisContext);
+    rn->redisContext = NULL;
+  }
+
+  return reply;
+} /* void c_redisCommand */
+
+static int redis_get_info_value(char const *info_line, char const *field_name,
+                                int ds_type, value_t *val) {
   char *str = strstr(info_line, field_name);
   static char buf[MAX_REDIS_VAL_SIZE];
-  value_t val;
   if (str) {
     int i;
 
@@ -294,20 +359,29 @@ static int redis_handle_info(char *node, char const *info_line,
       buf[i] = *str;
     buf[i] = '\0';
 
-    if (parse_value(buf, &val, ds_type) == -1) {
+    if (parse_value(buf, val, ds_type) == -1) {
       WARNING("redis plugin: Unable to parse field `%s'.", field_name);
       return -1;
     }
 
-    redis_submit(node, type, type_instance, val);
     return 0;
   }
   return -1;
+} /* int redis_get_info_value */
 
+static int redis_handle_info(char *node, char const *info_line,
+                             char const *type, char const *type_instance,
+                             char const *field_name, int ds_type) /* {{{ */
+{
+  value_t val;
+  if (redis_get_info_value(info_line, field_name, ds_type, &val) != 0)
+    return -1;
+
+  redis_submit(node, type, type_instance, val);
+  return 0;
 } /* }}} int redis_handle_info */
 
-static int redis_handle_query(redisContext *rh, redis_node_t *rn,
-                              redis_query_t *rq) /* {{{ */
+static int redis_handle_query(redis_node_t *rn, redis_query_t *rq) /* {{{ */
 {
   redisReply *rr;
   const data_set_t *ds;
@@ -315,22 +389,24 @@ static int redis_handle_query(redisContext *rh, redis_node_t *rn,
 
   ds = plugin_get_ds(rq->type);
   if (!ds) {
-    ERROR("redis plugin: DataSet `%s' not defined.", rq->type);
+    ERROR("redis plugin: DS type `%s' not defined.", rq->type);
     return -1;
   }
 
   if (ds->ds_num != 1) {
-    ERROR("redis plugin: DS `%s' has too many types.", rq->type);
+    ERROR("redis plugin: DS type `%s' has too many datasources. This is not "
+          "supported currently.",
+          rq->type);
     return -1;
   }
 
-  if ((rr = redisCommand(rh, "SELECT %d", rq->database)) == NULL) {
+  if ((rr = c_redisCommand(rn, "SELECT %d", rq->database)) == NULL) {
     WARNING("redis plugin: unable to switch to database `%d' on node `%s'.",
             rq->database, rn->name);
     return -1;
   }
 
-  if ((rr = redisCommand(rh, rq->query)) == NULL) {
+  if ((rr = c_redisCommand(rn, rq->query)) == NULL) {
     WARNING("redis plugin: unable to carry out query `%s'.", rq->query);
     return -1;
   }
@@ -354,13 +430,24 @@ static int redis_handle_query(redisContext *rh, redis_node_t *rn,
     break;
   case REDIS_REPLY_STRING:
     if (parse_value(rr->str, &val, ds->ds[0].type) == -1) {
-      WARNING("redis plugin: Unable to parse field `%s'.", rq->type);
+      WARNING("redis plugin: Query `%s': Unable to parse value.", rq->query);
       freeReplyObject(rr);
       return -1;
     }
     break;
+  case REDIS_REPLY_ERROR:
+    WARNING("redis plugin: Query `%s' failed: %s.", rq->query, rr->str);
+    freeReplyObject(rr);
+    return -1;
+  case REDIS_REPLY_ARRAY:
+    WARNING("redis plugin: Query `%s' should return string or integer. Arrays "
+            "are not supported.",
+            rq->query);
+    freeReplyObject(rr);
+    return -1;
   default:
-    WARNING("redis plugin: Cannot coerce redis type.");
+    WARNING("redis plugin: Query `%s': Cannot coerce redis type (%i).",
+            rq->query, rr->type);
     freeReplyObject(rr);
     return -1;
   }
@@ -371,7 +458,7 @@ static int redis_handle_query(redisContext *rh, redis_node_t *rn,
   return 0;
 } /* }}} int redis_handle_query */
 
-static int redis_db_stats(char *node, char const *info_line) /* {{{ */
+static int redis_db_stats(const char *node, char const *info_line) /* {{{ */
 {
   /* redis_db_stats parses and dispatches Redis database statistics,
    * currently the number of keys for each database.
@@ -410,91 +497,245 @@ static int redis_db_stats(char *node, char const *info_line) /* {{{ */
 
 } /* }}} int redis_db_stats */
 
-static int redis_read(void) /* {{{ */
-{
-  for (redis_node_t *rn = nodes_head; rn != NULL; rn = rn->next) {
-    redisContext *rh;
+static void redis_cpu_usage(const char *node, char const *info_line) {
+  while (42) {
+    value_t rusage_user;
+    value_t rusage_syst;
+
+    if (redis_get_info_value(info_line, "used_cpu_user", DS_TYPE_GAUGE,
+                             &rusage_user) != 0)
+      break;
+
+    if (redis_get_info_value(info_line, "used_cpu_sys", DS_TYPE_GAUGE,
+                             &rusage_syst) != 0)
+      break;
+
+    redis_submit2(node, "ps_cputime", "daemon",
+                  (value_t){.derive = rusage_user.gauge * 1000000},
+                  (value_t){.derive = rusage_syst.gauge * 1000000});
+    break;
+  }
+
+  while (42) {
+    value_t rusage_user;
+    value_t rusage_syst;
+
+    if (redis_get_info_value(info_line, "used_cpu_user_children", DS_TYPE_GAUGE,
+                             &rusage_user) != 0)
+      break;
+
+    if (redis_get_info_value(info_line, "used_cpu_sys_children", DS_TYPE_GAUGE,
+                             &rusage_syst) != 0)
+      break;
+
+    redis_submit2(node, "ps_cputime", "children",
+                  (value_t){.derive = rusage_user.gauge * 1000000},
+                  (value_t){.derive = rusage_syst.gauge * 1000000});
+    break;
+  }
+} /* void redis_cpu_usage */
+
+static void redis_check_connection(redis_node_t *rn) {
+  if (rn->redisContext)
+    return;
+
+  redisContext *rh = redisConnectWithTimeout(rn->host, rn->port, rn->timeout);
+
+  if (rh == NULL) {
+    ERROR("redis plugin: can't allocate redis context");
+    return;
+  }
+  if (rh->err) {
+    ERROR("redis plugin: unable to connect to node `%s' (%s:%d): %s.", rn->name,
+          rn->host, rn->port, rh->errstr);
+    redisFree(rh);
+    return;
+  }
+
+  rn->redisContext = rh;
+
+  if (rn->passwd) {
     redisReply *rr;
 
-    DEBUG("redis plugin: querying info from node `%s' (%s:%d).", rn->name,
-          rn->host, rn->port);
+    DEBUG("redis plugin: authenticating node `%s' passwd(%s).", rn->name,
+          rn->passwd);
 
-    rh = redisConnectWithTimeout((char *)rn->host, rn->port, rn->timeout);
-    if (rh == NULL) {
-      ERROR("redis plugin: unable to connect to node `%s' (%s:%d).", rn->name,
-            rn->host, rn->port);
-      continue;
+    if ((rr = c_redisCommand(rn, "AUTH %s", rn->passwd)) == NULL) {
+      WARNING("redis plugin: unable to authenticate on node `%s'.", rn->name);
+      return;
     }
 
-    if (strlen(rn->passwd) > 0) {
-      DEBUG("redis plugin: authenticating node `%s' passwd(%s).", rn->name,
-            rn->passwd);
+    if (rr->type != REDIS_REPLY_STATUS) {
+      WARNING("redis plugin: invalid authentication on node `%s'.", rn->name);
+      freeReplyObject(rr);
+      redisFree(rn->redisContext);
+      rn->redisContext = NULL;
+      return;
+    }
 
-      if ((rr = redisCommand(rh, "AUTH %s", rn->passwd)) == NULL) {
-        WARNING("redis plugin: unable to authenticate on node `%s'.", rn->name);
-        goto redis_fail;
-      }
+    freeReplyObject(rr);
+  }
+  return;
+} /* void redis_check_connection */
 
-      if (rr->type != REDIS_REPLY_STATUS) {
-        WARNING("redis plugin: invalid authentication on node `%s'.", rn->name);
-        goto redis_fail;
-      }
+static void redis_read_server_info(redis_node_t *rn) {
+  redisReply *rr;
 
-      freeReplyObject(rr);
+  if ((rr = c_redisCommand(rn, "INFO")) == NULL) {
+    WARNING("redis plugin: unable to get INFO from node `%s'.", rn->name);
+    return;
+  }
+
+  redis_handle_info(rn->name, rr->str, "uptime", NULL, "uptime_in_seconds",
+                    DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "current_connections", "clients",
+                    "connected_clients", DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "blocked_clients", NULL,
+                    "blocked_clients", DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "memory", NULL, "used_memory",
+                    DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "memory_lua", NULL, "used_memory_lua",
+                    DS_TYPE_GAUGE);
+  /* changes_since_last_save: Deprecated in redis version 2.6 and above */
+  redis_handle_info(rn->name, rr->str, "volatile_changes", NULL,
+                    "changes_since_last_save", DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "total_connections", NULL,
+                    "total_connections_received", DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "total_operations", NULL,
+                    "total_commands_processed", DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "operations_per_second", NULL,
+                    "instantaneous_ops_per_sec", DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "expired_keys", NULL, "expired_keys",
+                    DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "evicted_keys", NULL, "evicted_keys",
+                    DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "pubsub", "channels", "pubsub_channels",
+                    DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "pubsub", "patterns", "pubsub_patterns",
+                    DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "current_connections", "slaves",
+                    "connected_slaves", DS_TYPE_GAUGE);
+  redis_handle_info(rn->name, rr->str, "cache_result", "hits", "keyspace_hits",
+                    DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "cache_result", "misses",
+                    "keyspace_misses", DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "total_bytes", "input",
+                    "total_net_input_bytes", DS_TYPE_DERIVE);
+  redis_handle_info(rn->name, rr->str, "total_bytes", "output",
+                    "total_net_output_bytes", DS_TYPE_DERIVE);
+
+  redis_db_stats(rn->name, rr->str);
+
+  if (rn->report_cpu_usage)
+    redis_cpu_usage(rn->name, rr->str);
+
+  freeReplyObject(rr);
+} /* void redis_read_server_info */
+
+static void redis_read_command_stats(redis_node_t *rn) {
+  redisReply *rr;
+
+  if ((rr = c_redisCommand(rn, "INFO commandstats")) == NULL) {
+    WARNING("redis plugin: node `%s': unable to get `INFO commandstats'.",
+            rn->name);
+    return;
+  }
+
+  if (rr->type != REDIS_REPLY_STRING) {
+    WARNING("redis plugin: node `%s' `INFO commandstats' returned unsupported "
+            "redis type %i.",
+            rn->name, rr->type);
+    freeReplyObject(rr);
+    return;
+  }
+
+  char *command;
+  char *line;
+  char *ptr = rr->str;
+  char *saveptr = NULL;
+  while ((line = strtok_r(ptr, "\n\r", &saveptr)) != NULL) {
+    ptr = NULL;
+
+    if (line[0] == '#')
+      continue;
+
+    /* command name */
+    if (strstr(line, "cmdstat_") != line) {
+      ERROR("redis plugin: not found 'cmdstat_' prefix in line '%s'", line);
+      continue;
     }
 
-    if ((rr = redisCommand(rh, "INFO")) == NULL) {
-      WARNING("redis plugin: unable to get info from node `%s'.", rn->name);
-      goto redis_fail;
+    char *values = strstr(line, ":");
+    if (values == NULL) {
+      ERROR("redis plugin: not found ':' separator in line '%s'", line);
+      continue;
     }
 
-    redis_handle_info(rn->name, rr->str, "uptime", NULL, "uptime_in_seconds",
-                      DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "current_connections", "clients",
-                      "connected_clients", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "blocked_clients", NULL,
-                      "blocked_clients", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "memory", NULL, "used_memory",
-                      DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "memory_lua", NULL, "used_memory_lua",
-                      DS_TYPE_GAUGE);
-    /* changes_since_last_save: Deprecated in redis version 2.6 and above */
-    redis_handle_info(rn->name, rr->str, "volatile_changes", NULL,
-                      "changes_since_last_save", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "total_connections", NULL,
-                      "total_connections_received", DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "total_operations", NULL,
-                      "total_commands_processed", DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "operations_per_second", NULL,
-                      "instantaneous_ops_per_sec", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "expired_keys", NULL, "expired_keys",
-                      DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "evicted_keys", NULL, "evicted_keys",
-                      DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "pubsub", "channels",
-                      "pubsub_channels", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "pubsub", "patterns",
-                      "pubsub_patterns", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "current_connections", "slaves",
-                      "connected_slaves", DS_TYPE_GAUGE);
-    redis_handle_info(rn->name, rr->str, "cache_result", "hits",
-                      "keyspace_hits", DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "cache_result", "misses",
-                      "keyspace_misses", DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "total_bytes", "input",
-                      "total_net_input_bytes", DS_TYPE_DERIVE);
-    redis_handle_info(rn->name, rr->str, "total_bytes", "output",
-                      "total_net_output_bytes", DS_TYPE_DERIVE);
-
-    redis_db_stats(rn->name, rr->str);
-
-    for (redis_query_t *rq = rn->queries; rq != NULL; rq = rq->next)
-      redis_handle_query(rh, rn, rq);
-
-  redis_fail:
-    if (rr != NULL)
-      freeReplyObject(rr);
-    redisFree(rh);
+    /* Null-terminate command token */
+    values[0] = '\0';
+    command = line + strlen("cmdstat_");
+    values++;
+
+    /* parse values */
+    /* cmdstat_publish:calls=20795774,usec=111039258,usec_per_call=5.34 */
+    char *field;
+    char *saveptr_field = NULL;
+    while ((field = strtok_r(values, "=", &saveptr_field)) != NULL) {
+      values = NULL;
+
+      const char *type;
+      /* only these are supported */
+      if (strcmp(field, "calls") == 0)
+        type = "commands";
+      else if (strcmp(field, "usec") == 0)
+        type = "redis_command_cputime";
+      else
+        continue;
+
+      if ((field = strtok_r(NULL, ",", &saveptr_field)) == NULL)
+        continue;
+
+      char *endptr = NULL;
+      errno = 0;
+      derive_t value = strtoll(field, &endptr, 0);
+
+      if ((endptr == field) || (errno != 0))
+        continue;
+
+      redis_submit(rn->name, type, command, (value_t){.derive = value});
+    }
+  }
+  freeReplyObject(rr);
+} /* void redis_read_command_stats */
+
+static int redis_read(user_data_t *user_data) /* {{{ */
+{
+  redis_node_t *rn = user_data->data;
+
+  DEBUG("redis plugin: querying info from node `%s' (%s:%d).", rn->name,
+        rn->host, rn->port);
+
+  redis_check_connection(rn);
+
+  if (!rn->redisContext) /* no connection */
+    return -1;
+
+  redis_read_server_info(rn);
+
+  if (!rn->redisContext) /* connection lost */
+    return -1;
+
+  if (rn->report_command_stats) {
+    redis_read_command_stats(rn);
+
+    if (!rn->redisContext) /* connection lost */
+      return -1;
+  }
+
+  for (redis_query_t *rq = rn->queries; rq != NULL; rq = rq->next) {
+    redis_handle_query(rn, rq);
+    if (!rn->redisContext) /* connection lost */
+      return -1;
   }
 
   return 0;
@@ -505,8 +746,5 @@ void module_register(void) /* {{{ */
 {
   plugin_register_complex_config("redis", redis_config);
   plugin_register_init("redis", redis_init);
-  plugin_register_read("redis", redis_read);
-  /* TODO: plugin_register_write: one redis list per value id with
-   * X elements */
 }
 /* }}} */
index dde6079..6c018da 100644 (file)
@@ -29,6 +29,7 @@
 #include "common.h"
 #include "plugin.h"
 #include "utils_complain.h"
+#include "utils_ignorelist.h"
 
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
@@ -46,8 +47,9 @@ typedef struct oid_s oid_t;
 
 struct instance_s {
   bool configured;
-  bool is_plugin;
   oid_t oid;
+  char *prefix;
+  char *value;
 };
 typedef struct instance_s instance_t;
 
@@ -55,11 +57,12 @@ struct data_definition_s {
   char *name; /* used to reference this from the `Collect' option */
   char *type; /* used to find the data_set */
   bool is_table;
-  instance_t instance;
+  instance_t type_instance;
+  instance_t plugin_instance;
+  instance_t host;
+  oid_t filter_oid;
+  ignorelist_t *ignorelist;
   char *plugin_name;
-  char *plugin_instance;
-  char *type_instance;
-  char *instance_prefix;
   oid_t *values;
   size_t values_len;
   double scale;
@@ -102,19 +105,28 @@ typedef struct host_definition_s host_definition_t;
 
 /* These two types are used to cache values in `csnmp_read_table' to handle
  * gaps in tables. */
-struct csnmp_list_instances_s {
+struct csnmp_cell_char_s {
   oid_t suffix;
-  char instance[DATA_MAX_NAME_LEN];
-  struct csnmp_list_instances_s *next;
+  char value[DATA_MAX_NAME_LEN];
+  struct csnmp_cell_char_s *next;
 };
-typedef struct csnmp_list_instances_s csnmp_list_instances_t;
+typedef struct csnmp_cell_char_s csnmp_cell_char_t;
 
-struct csnmp_table_values_s {
+struct csnmp_cell_value_s {
   oid_t suffix;
   value_t value;
-  struct csnmp_table_values_s *next;
+  struct csnmp_cell_value_s *next;
 };
-typedef struct csnmp_table_values_s csnmp_table_values_t;
+typedef struct csnmp_cell_value_s csnmp_cell_value_t;
+
+typedef enum {
+  OID_TYPE_SKIP = 0,
+  OID_TYPE_VARIABLE,
+  OID_TYPE_TYPEINSTANCE,
+  OID_TYPE_PLUGININSTANCE,
+  OID_TYPE_HOST,
+  OID_TYPE_FILTER,
+} csnmp_oid_type_t;
 
 /*
  * Private variables
@@ -203,6 +215,22 @@ static void csnmp_host_definition_destroy(void *arg) /* {{{ */
   sfree(hd);
 } /* }}} void csnmp_host_definition_destroy */
 
+static void csnmp_data_definition_destroy(data_definition_t *dd) {
+  sfree(dd->name);
+  sfree(dd->type);
+  sfree(dd->plugin_name);
+  sfree(dd->plugin_instance.prefix);
+  sfree(dd->plugin_instance.value);
+  sfree(dd->type_instance.prefix);
+  sfree(dd->type_instance.value);
+  sfree(dd->host.prefix);
+  sfree(dd->host.value);
+  sfree(dd->values);
+  sfree(dd->ignores);
+  ignorelist_free(dd->ignorelist);
+  sfree(dd);
+} /* void csnmp_data_definition_destroy */
+
 /* Many functions to handle the configuration. {{{ */
 /* First there are many functions which do configuration stuff. It's a big
  * bloated and messy, I'm afraid. */
@@ -212,7 +240,7 @@ static void csnmp_host_definition_destroy(void *arg) /* {{{ */
  *  csnmp_config
  *  +-> call_snmp_init_once
  *  +-> csnmp_config_add_data
- *  !   +-> csnmp_config_add_data_instance
+ *  !   +-> csnmp_config_configure_data_instance
  *  !   +-> csnmp_config_add_data_values
  *  +-> csnmp_config_add_host
  *      +-> csnmp_config_add_host_version
@@ -229,38 +257,29 @@ static void call_snmp_init_once(void) {
   have_init = 1;
 } /* void call_snmp_init_once */
 
-static int csnmp_config_add_data_instance_oid(data_definition_t *dd,
-                                              oconfig_item_t *ci,
-                                              bool is_plugin) {
+static int csnmp_config_configure_data_instance(instance_t *instance,
+                                                oconfig_item_t *ci) {
   char buffer[DATA_MAX_NAME_LEN];
-  int status;
 
-  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  int status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
   if (status != 0)
     return status;
 
-  if (dd->instance.configured) {
-    ERROR("snmp plugin: Only one of options `TypeInstanceOID', "
-          "`PluginInstanceOID' or `Instance' can be used in `Data' block.");
-    return -1;
-  }
-
-  dd->instance.is_plugin = is_plugin;
-  dd->instance.configured = true;
+  instance->configured = true;
 
   if (strlen(buffer) == 0) {
     return 0;
   }
 
-  dd->instance.oid.oid_len = MAX_OID_LEN;
+  instance->oid.oid_len = MAX_OID_LEN;
 
-  if (!read_objid(buffer, dd->instance.oid.oid, &dd->instance.oid.oid_len)) {
+  if (!read_objid(buffer, instance->oid.oid, &instance->oid.oid_len)) {
     ERROR("snmp plugin: read_objid (%s) failed.", buffer);
     return -1;
   }
 
   return 0;
-} /* int csnmp_config_add_data_instance_oid */
+} /* int csnmp_config_configure_data_instance */
 
 static int csnmp_config_add_data_values(data_definition_t *dd,
                                         oconfig_item_t *ci) {
@@ -297,7 +316,7 @@ static int csnmp_config_add_data_values(data_definition_t *dd,
   }
 
   return 0;
-} /* int csnmp_config_add_data_instance */
+} /* int csnmp_config_configure_data_instance */
 
 static int csnmp_config_add_data_blacklist(data_definition_t *dd,
                                            oconfig_item_t *ci) {
@@ -322,6 +341,41 @@ static int csnmp_config_add_data_blacklist(data_definition_t *dd,
   return 0;
 } /* int csnmp_config_add_data_blacklist */
 
+static int csnmp_config_add_data_filter_values(data_definition_t *data,
+                                               oconfig_item_t *ci) {
+  if (ci->values_num < 1) {
+    WARNING("snmp plugin: `FilterValues' needs at least one argument.");
+    return -1;
+  }
+
+  for (int i = 0; i < ci->values_num; i++) {
+    if (ci->values[i].type != OCONFIG_TYPE_STRING) {
+      WARNING("snmp plugin: All arguments to `FilterValues' must be strings.");
+      return -1;
+    }
+    ignorelist_add(data->ignorelist, ci->values[i].value.string);
+  }
+
+  return 0;
+} /* int csnmp_config_add_data_filter_values */
+
+static int csnmp_config_add_data_filter_oid(data_definition_t *data,
+                                            oconfig_item_t *ci) {
+
+  char buffer[DATA_MAX_NAME_LEN];
+  int status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  if (status != 0)
+    return status;
+
+  data->filter_oid.oid_len = MAX_OID_LEN;
+
+  if (!read_objid(buffer, data->filter_oid.oid, &data->filter_oid.oid_len)) {
+    ERROR("snmp plugin: read_objid (%s) failed.", buffer);
+    return -1;
+  }
+  return 0;
+} /* int csnmp_config_add_data_filter_oid */
+
 static int csnmp_config_add_data(oconfig_item_t *ci) {
   data_definition_t *dd = calloc(1, sizeof(*dd));
   if (dd == NULL)
@@ -338,6 +392,14 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
   dd->ignores_len = 0;
   dd->ignores = NULL;
 
+  dd->ignorelist = ignorelist_create(/* invert = */ 1);
+  if (dd->ignorelist == NULL) {
+    sfree(dd->name);
+    sfree(dd);
+    ERROR("snmp plugin: ignorelist_create() failed.");
+    return ENOMEM;
+  }
+
   dd->plugin_name = strdup("snmp");
   if (dd->plugin_name == NULL) {
     ERROR("snmp plugin: Can't allocate memory");
@@ -356,30 +418,42 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
     else if (strcasecmp("Instance", option->key) == 0) {
       if (dd->is_table) {
         /* Instance is OID */
-        WARNING("snmp plugin: Option `Instance' is deprecated, please update "
-                "Data \"%s\" block to use option `TypeInstanceOID'.",
-                dd->name);
-        status = csnmp_config_add_data_instance_oid(dd, option,
-                                                    false /* type instance */);
+        WARNING(
+            "snmp plugin: data %s: Option `Instance' is deprecated, please use "
+            "option `TypeInstanceOID'.",
+            dd->name);
+        status =
+            csnmp_config_configure_data_instance(&dd->type_instance, option);
       } else {
         /* Instance is a simple string */
-        WARNING("snmp plugin: Option `Instance' is deprecated, please update "
-                "Data \"%s\" block to use option `TypeInstance'.",
-                dd->name);
-        status = cf_util_get_string(option, &dd->type_instance);
+        WARNING(
+            "snmp plugin: data %s: Option `Instance' is deprecated, please use "
+            "option `TypeInstance'.",
+            dd->name);
+        status = cf_util_get_string(option, &dd->type_instance.value);
       }
+    } else if (strcasecmp("InstancePrefix", option->key) == 0) {
+      WARNING("snmp plugin: data %s: Option `InstancePrefix' is deprecated, "
+              "please use option `TypeInstancePrefix'.",
+              dd->name);
+      status = cf_util_get_string(option, &dd->type_instance.prefix);
     } else if (strcasecmp("PluginInstance", option->key) == 0)
-      status = cf_util_get_string(option, &dd->plugin_instance);
+      status = cf_util_get_string(option, &dd->plugin_instance.value);
     else if (strcasecmp("TypeInstance", option->key) == 0)
-      status = cf_util_get_string(option, &dd->type_instance);
+      status = cf_util_get_string(option, &dd->type_instance.value);
     else if (strcasecmp("PluginInstanceOID", option->key) == 0)
-      status = csnmp_config_add_data_instance_oid(dd, option,
-                                                  true /* plugin instance */);
+      status =
+          csnmp_config_configure_data_instance(&dd->plugin_instance, option);
+    else if (strcasecmp("PluginInstancePrefix", option->key) == 0)
+      status = cf_util_get_string(option, &dd->plugin_instance.prefix);
     else if (strcasecmp("TypeInstanceOID", option->key) == 0)
-      status = csnmp_config_add_data_instance_oid(dd, option,
-                                                  false /* type instance */);
-    else if (strcasecmp("InstancePrefix", option->key) == 0)
-      status = cf_util_get_string(option, &dd->instance_prefix);
+      status = csnmp_config_configure_data_instance(&dd->type_instance, option);
+    else if (strcasecmp("TypeInstancePrefix", option->key) == 0)
+      status = cf_util_get_string(option, &dd->type_instance.prefix);
+    else if (strcasecmp("HostOID", option->key) == 0)
+      status = csnmp_config_configure_data_instance(&dd->host, option);
+    else if (strcasecmp("HostPrefix", option->key) == 0)
+      status = cf_util_get_string(option, &dd->host.prefix);
     else if (strcasecmp("Values", option->key) == 0)
       status = csnmp_config_add_data_values(dd, option);
     else if (strcasecmp("Shift", option->key) == 0)
@@ -390,8 +464,18 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
       status = csnmp_config_add_data_blacklist(dd, option);
     else if (strcasecmp("InvertMatch", option->key) == 0)
       status = cf_util_get_boolean(option, &dd->invert_match);
-    else {
-      WARNING("snmp plugin: Option `%s' not allowed here.", option->key);
+    else if (strcasecmp("FilterOID", option->key) == 0) {
+      status = csnmp_config_add_data_filter_oid(dd, option);
+    } else if (strcasecmp("FilterValues", option->key) == 0) {
+      status = csnmp_config_add_data_filter_values(dd, option);
+    } else if (strcasecmp("FilterIgnoreSelected", option->key) == 0) {
+      bool t;
+      status = cf_util_get_boolean(option, &t);
+      if (status == 0)
+        ignorelist_set_invert(dd->ignorelist, /* invert = */ !t);
+    } else {
+      WARNING("snmp plugin: data %s: Option `%s' not allowed here.", dd->name,
+              option->key);
       status = -1;
     }
 
@@ -401,34 +485,62 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
 
   while (status == 0) {
     if (dd->is_table) {
-      if (dd->plugin_instance && dd->instance.is_plugin) {
-        WARNING("snmp plugin: Option `PluginInstance' will be ignored for "
-                "Data `%s'",
+      /* Set type_instance to SUBID by default */
+      if (!dd->plugin_instance.configured && !dd->host.configured)
+        dd->type_instance.configured = true;
+
+      if (dd->plugin_instance.value && dd->plugin_instance.configured) {
+        WARNING(
+            "snmp plugin: data %s: Option `PluginInstance' will be ignored.",
+            dd->name);
+      }
+      if (dd->type_instance.value && dd->type_instance.configured) {
+        WARNING("snmp plugin: data %s: Option `TypeInstance' will be ignored.",
+                dd->name);
+      }
+      if (dd->type_instance.prefix && !dd->type_instance.configured) {
+        WARNING("snmp plugin: data %s: Option `TypeInstancePrefix' will be "
+                "ignored.",
+                dd->name);
+      }
+      if (dd->plugin_instance.prefix && !dd->plugin_instance.configured) {
+        WARNING("snmp plugin: data %s: Option `PluginInstancePrefix' will be "
+                "ignored.",
                 dd->name);
       }
-      if (dd->type_instance && !dd->instance.is_plugin) {
-        WARNING("snmp plugin: Option `TypeInstance' will be ignored for Data "
-                "`%s'",
+      if (dd->host.prefix && !dd->host.configured) {
+        WARNING("snmp plugin: data %s: Option `HostPrefix' will be ignored.",
                 dd->name);
       }
     } else {
-      if (dd->instance.configured) {
-        if (dd->instance.is_plugin) {
-          WARNING("snmp plugin: Option `PluginInstanceOID' will be ignored for "
-                  "Data `%s'",
-                  dd->name);
-        } else {
-          WARNING("snmp plugin: Option `TypeInstanceOID' will be ignored for "
-                  "Data `%s'",
-                  dd->name);
-        }
+      if (dd->plugin_instance.oid.oid_len > 0) {
+        WARNING("snmp plugin: data %s: Option `PluginInstanceOID' will be "
+                "ignored.",
+                dd->name);
       }
-
-      if (dd->instance_prefix) {
-        WARNING("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
-                "is set to `false'.",
+      if (dd->type_instance.oid.oid_len > 0) {
+        WARNING(
+            "snmp plugin: data %s: Option `TypeInstanceOID' will be ignored.",
+            dd->name);
+      }
+      if (dd->type_instance.prefix) {
+        WARNING("snmp plugin: data %s: Option `TypeInstancePrefix' is ignored "
+                "when `Table' "
+                "set to `false'.",
                 dd->name);
       }
+      if (dd->plugin_instance.prefix) {
+        WARNING("snmp plugin: data %s: Option `PluginInstancePrefix' is "
+                "ignored when "
+                "`Table' set to `false'.",
+                dd->name);
+      }
+      if (dd->host.prefix) {
+        WARNING(
+            "snmp plugin: data %s: Option `HostPrefix' is ignored when `Table' "
+            "set to `false'.",
+            dd->name);
+      }
     }
 
     if (dd->type == NULL) {
@@ -446,15 +558,7 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
   } /* while (status == 0) */
 
   if (status != 0) {
-    sfree(dd->name);
-    sfree(dd->type);
-    sfree(dd->plugin_name);
-    sfree(dd->plugin_instance);
-    sfree(dd->type_instance);
-    sfree(dd->instance_prefix);
-    sfree(dd->values);
-    sfree(dd->ignores);
-    sfree(dd);
+    csnmp_data_definition_destroy(dd);
     return -1;
   }
 
@@ -463,11 +567,16 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
         dd->name, dd->type, (dd->is_table) ? "true" : "false", dd->values_len);
 
   DEBUG("snmp plugin:        plugin_instance = %s, type_instance = %s,",
-        dd->plugin_instance, dd->type_instance);
+        dd->plugin_instance.value, dd->type_instance.value);
 
-  DEBUG("snmp plugin:        instance_by_oid = %s, to_plugin_instance = %s }",
-        (dd->instance.oid.oid_len > 0) ? "true" : "SUBID",
-        (dd->instance.is_plugin) ? "true" : "false");
+  DEBUG("snmp plugin:        type_instance_by_oid = %s, plugin_instance_by_oid "
+        "= %s }",
+        (dd->type_instance.oid.oid_len > 0)
+            ? "true"
+            : ((dd->type_instance.configured) ? "SUBID" : "false"),
+        (dd->plugin_instance.oid.oid_len > 0)
+            ? "true"
+            : ((dd->plugin_instance.configured) ? "SUBID" : "false"));
 
   if (data_head == NULL)
     data_head = dd;
@@ -501,7 +610,7 @@ static int csnmp_config_add_host_version(host_definition_t *hd,
   hd->version = version;
 
   return 0;
-} /* int csnmp_config_add_host_address */
+} /* int csnmp_config_add_host_version */
 
 static int csnmp_config_add_host_collect(host_definition_t *host,
                                          oconfig_item_t *ci) {
@@ -889,8 +998,8 @@ static void csnmp_host_open_session(host_definition_t *host) {
 
 /* TODO: Check if negative values wrap around. Problem: negative temperatures.
  */
-static value_t csnmp_value_list_to_value(struct variable_list *vl, int type,
-                                         double scale, double shift,
+static value_t csnmp_value_list_to_value(const struct variable_list *vl,
+                                         int type, double scale, double shift,
                                          const char *host_name,
                                          const char *data_name) {
   value_t ret;
@@ -1093,96 +1202,99 @@ static int csnmp_strvbcopy(char *dst, /* {{{ */
   return 0;
 } /* }}} int csnmp_strvbcopy */
 
-static int csnmp_instance_list_add(csnmp_list_instances_t **head,
-                                   csnmp_list_instances_t **tail,
-                                   const struct snmp_pdu *res,
-                                   const host_definition_t *hd,
-                                   const data_definition_t *dd) {
-  csnmp_list_instances_t *il;
-  struct variable_list *vb;
-  oid_t vb_name;
-  int status;
+static csnmp_cell_char_t *csnmp_get_char_cell(const struct variable_list *vb,
+                                              const oid_t *root_oid,
+                                              const host_definition_t *hd,
+                                              const data_definition_t *dd) {
 
-  /* Set vb on the last variable */
-  for (vb = res->variables; (vb != NULL) && (vb->next_variable != NULL);
-       vb = vb->next_variable)
-    /* do nothing */;
   if (vb == NULL)
-    return -1;
-
-  csnmp_oid_init(&vb_name, vb->name, vb->name_length);
+    return NULL;
 
-  il = calloc(1, sizeof(*il));
+  csnmp_cell_char_t *il = calloc(1, sizeof(*il));
   if (il == NULL) {
     ERROR("snmp plugin: calloc failed.");
-    return -1;
+    return NULL;
   }
   il->next = NULL;
 
-  status = csnmp_oid_suffix(&il->suffix, &vb_name, &dd->instance.oid);
-  if (status != 0) {
+  oid_t vb_name;
+  csnmp_oid_init(&vb_name, vb->name, vb->name_length);
+
+  if (csnmp_oid_suffix(&il->suffix, &vb_name, root_oid) != 0) {
     sfree(il);
-    return status;
+    return NULL;
   }
 
-  /* Get instance name */
+  /* Get value */
   if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR) ||
       (vb->type == ASN_IPADDRESS)) {
-    char *ptr;
-
-    csnmp_strvbcopy(il->instance, vb, sizeof(il->instance));
-    bool is_matched = 0;
-    for (uint32_t i = 0; i < dd->ignores_len; i++) {
-      status = fnmatch(dd->ignores[i], il->instance, 0);
-      if (status == 0) {
-        if (!dd->invert_match) {
-          sfree(il);
-          return 0;
-        } else {
-          is_matched = 1;
-          break;
-        }
-      }
-    }
-    if (dd->invert_match && !is_matched) {
-      sfree(il);
-      return 0;
-    }
-    for (ptr = il->instance; *ptr != '\0'; ptr++) {
-      if ((*ptr > 0) && (*ptr < 32))
-        *ptr = ' ';
-      else if (*ptr == '/')
-        *ptr = '_';
-    }
-    DEBUG("snmp plugin: il->instance = `%s';", il->instance);
+
+    csnmp_strvbcopy(il->value, vb, sizeof(il->value));
+
   } else {
     value_t val = csnmp_value_list_to_value(
         vb, DS_TYPE_COUNTER,
         /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
-    snprintf(il->instance, sizeof(il->instance), "%" PRIu64,
-             (uint64_t)val.counter);
+    snprintf(il->value, sizeof(il->value), "%" PRIu64, (uint64_t)val.counter);
   }
 
-  /* TODO: Debugging output */
+  return il;
+} /* csnmp_cell_char_t csnmp_get_char_cell */
 
+static void csnmp_cells_append(csnmp_cell_char_t **head,
+                               csnmp_cell_char_t **tail,
+                               csnmp_cell_char_t *il) {
   if (*head == NULL)
     *head = il;
   else
     (*tail)->next = il;
   *tail = il;
-
+} /* void csnmp_cells_append */
+
+static bool csnmp_ignore_instance(csnmp_cell_char_t *cell,
+                                  const data_definition_t *dd) {
+  bool is_matched = 0;
+  for (uint32_t i = 0; i < dd->ignores_len; i++) {
+    int status = fnmatch(dd->ignores[i], cell->value, 0);
+    if (status == 0) {
+      if (!dd->invert_match) {
+        return 1;
+      } else {
+        is_matched = 1;
+        break;
+      }
+    }
+  }
+  if (dd->invert_match && !is_matched) {
+    return 1;
+  }
   return 0;
-} /* int csnmp_instance_list_add */
+} /* bool csnmp_ignore_instance */
+
+static void csnmp_cell_replace_reserved_chars(csnmp_cell_char_t *cell) {
+  for (char *ptr = cell->value; *ptr != '\0'; ptr++) {
+    if ((*ptr > 0) && (*ptr < 32))
+      *ptr = ' ';
+    else if (*ptr == '/')
+      *ptr = '_';
+  }
+} /* void csnmp_cell_replace_reserved_chars */
 
 static int csnmp_dispatch_table(host_definition_t *host,
                                 data_definition_t *data,
-                                csnmp_list_instances_t *instance_list,
-                                csnmp_table_values_t **value_table) {
+                                csnmp_cell_char_t *type_instance_cells,
+                                csnmp_cell_char_t *plugin_instance_cells,
+                                csnmp_cell_char_t *hostname_cells,
+                                csnmp_cell_char_t *filter_cells,
+                                csnmp_cell_value_t **value_cells) {
   const data_set_t *ds;
   value_list_t vl = VALUE_LIST_INIT;
 
-  csnmp_list_instances_t *instance_list_ptr;
-  csnmp_table_values_t *value_table_ptr[data->values_len];
+  csnmp_cell_char_t *type_instance_cell_ptr = type_instance_cells;
+  csnmp_cell_char_t *plugin_instance_cell_ptr = plugin_instance_cells;
+  csnmp_cell_char_t *hostname_cell_ptr = hostname_cells;
+  csnmp_cell_char_t *filter_cell_ptr = filter_cells;
+  csnmp_cell_value_t *value_cell_ptr[data->values_len];
 
   size_t i;
   bool have_more;
@@ -1196,13 +1308,11 @@ static int csnmp_dispatch_table(host_definition_t *host,
   assert(ds->ds_num == data->values_len);
   assert(data->values_len > 0);
 
-  instance_list_ptr = instance_list;
-
   for (i = 0; i < data->values_len; i++)
-    value_table_ptr[i] = value_table[i];
+    value_cell_ptr[i] = value_cells[i];
 
-  sstrncpy(vl.host, host->name, sizeof(vl.host));
   sstrncpy(vl.plugin, data->plugin_name, sizeof(vl.plugin));
+  sstrncpy(vl.type, data->type, sizeof(vl.type));
 
   vl.interval = host->interval;
 
@@ -1211,17 +1321,17 @@ static int csnmp_dispatch_table(host_definition_t *host,
     bool suffix_skipped = 0;
 
     /* Determine next suffix to handle. */
-    if (instance_list != NULL) {
-      if (instance_list_ptr == NULL) {
+    if (type_instance_cells != NULL) {
+      if (type_instance_cell_ptr == NULL) {
         have_more = 0;
         continue;
       }
 
-      memcpy(&current_suffix, &instance_list_ptr->suffix,
+      memcpy(&current_suffix, &type_instance_cell_ptr->suffix,
              sizeof(current_suffix));
     } else {
       /* no instance configured */
-      csnmp_table_values_t *ptr = value_table_ptr[0];
+      csnmp_cell_value_t *ptr = value_cell_ptr[0];
       if (ptr == NULL) {
         have_more = 0;
         continue;
@@ -1230,18 +1340,82 @@ static int csnmp_dispatch_table(host_definition_t *host,
       memcpy(&current_suffix, &ptr->suffix, sizeof(current_suffix));
     }
 
-    /* Update all the value_table_ptr to point at the entry with the same
+    /*
+    char oid_buffer[1024] = {0};
+    snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, current_suffix.oid,
+                          current_suffix.oid_len);
+    DEBUG("SNMP PLUGIN: SUFFIX %s", oid_buffer);
+    */
+
+    /* Update plugin_instance_cell_ptr to point expected suffix */
+    if (plugin_instance_cells != NULL) {
+      while ((plugin_instance_cell_ptr != NULL) &&
+             (csnmp_oid_compare(&plugin_instance_cell_ptr->suffix,
+                                &current_suffix) < 0))
+        plugin_instance_cell_ptr = plugin_instance_cell_ptr->next;
+
+      if (plugin_instance_cell_ptr == NULL) {
+        have_more = 0;
+        continue;
+      }
+
+      if (csnmp_oid_compare(&plugin_instance_cell_ptr->suffix,
+                            &current_suffix) > 0) {
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+      }
+    }
+
+    /* Update hostname_cell_ptr to point expected suffix */
+    if (hostname_cells != NULL) {
+      while (
+          (hostname_cell_ptr != NULL) &&
+          (csnmp_oid_compare(&hostname_cell_ptr->suffix, &current_suffix) < 0))
+        hostname_cell_ptr = hostname_cell_ptr->next;
+
+      if (hostname_cell_ptr == NULL) {
+        have_more = 0;
+        continue;
+      }
+
+      if (csnmp_oid_compare(&hostname_cell_ptr->suffix, &current_suffix) > 0) {
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+      }
+    }
+
+    /* Update filter_cell_ptr to point expected suffix */
+    if (filter_cells != NULL) {
+      while ((filter_cell_ptr != NULL) &&
+             (csnmp_oid_compare(&filter_cell_ptr->suffix, &current_suffix) < 0))
+        filter_cell_ptr = filter_cell_ptr->next;
+
+      if (filter_cell_ptr == NULL) {
+        have_more = 0;
+        continue;
+      }
+
+      if (csnmp_oid_compare(&filter_cell_ptr->suffix, &current_suffix) > 0) {
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+      }
+    }
+
+    /* Update all the value_cell_ptr to point at the entry with the same
      * trailing partial OID */
     for (i = 0; i < data->values_len; i++) {
       while (
-          (value_table_ptr[i] != NULL) &&
-          (csnmp_oid_compare(&value_table_ptr[i]->suffix, &current_suffix) < 0))
-        value_table_ptr[i] = value_table_ptr[i]->next;
+          (value_cell_ptr[i] != NULL) &&
+          (csnmp_oid_compare(&value_cell_ptr[i]->suffix, &current_suffix) < 0))
+        value_cell_ptr[i] = value_cell_ptr[i]->next;
 
-      if (value_table_ptr[i] == NULL) {
+      if (value_cell_ptr[i] == NULL) {
         have_more = 0;
         break;
-      } else if (csnmp_oid_compare(&value_table_ptr[i]->suffix,
+      } else if (csnmp_oid_compare(&value_cell_ptr[i]->suffix,
                                    &current_suffix) > 0) {
         /* This suffix is missing in the subtree. Indicate this with the
          * "suffix_skipped" flag and try the next instance / suffix. */
@@ -1255,59 +1429,98 @@ static int csnmp_dispatch_table(host_definition_t *host,
 
     /* Matching the values failed. Start from the beginning again. */
     if (suffix_skipped) {
-      if (instance_list != NULL)
-        instance_list_ptr = instance_list_ptr->next;
+      if (type_instance_cells != NULL)
+        type_instance_cell_ptr = type_instance_cell_ptr->next;
       else
-        value_table_ptr[0] = value_table_ptr[0]->next;
+        value_cell_ptr[0] = value_cell_ptr[0]->next;
 
       continue;
     }
 
-/* if we reach this line, all value_table_ptr[i] are non-NULL and are set
- * to the same subid. instance_list_ptr is either NULL or points to the
+/* if we reach this line, all value_cell_ptr[i] are non-NULL and are set
+ * to the same subid. type_instance_cell_ptr is either NULL or points to the
  * same subid, too. */
 #if COLLECT_DEBUG
     for (i = 1; i < data->values_len; i++) {
-      assert(value_table_ptr[i] != NULL);
-      assert(csnmp_oid_compare(&value_table_ptr[i - 1]->suffix,
-                               &value_table_ptr[i]->suffix) == 0);
+      assert(value_cell_ptr[i] != NULL);
+      assert(csnmp_oid_compare(&value_cell_ptr[i - 1]->suffix,
+                               &value_cell_ptr[i]->suffix) == 0);
     }
-    assert((instance_list_ptr == NULL) ||
-           (csnmp_oid_compare(&instance_list_ptr->suffix,
-                              &value_table_ptr[0]->suffix) == 0));
+    assert((type_instance_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&type_instance_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
+    assert((plugin_instance_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&plugin_instance_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
+    assert((hostname_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&hostname_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
+    assert((filter_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&filter_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
 #endif
 
-    sstrncpy(vl.type, data->type, sizeof(vl.type));
+    /* Check the value in filter column */
+    if (filter_cell_ptr &&
+        ignorelist_match(data->ignorelist, filter_cell_ptr->value) != 0) {
+      if (type_instance_cells != NULL)
+        type_instance_cell_ptr = type_instance_cell_ptr->next;
+      else
+        value_cell_ptr[0] = value_cell_ptr[0]->next;
 
-    {
+      continue;
+    }
+
+    /* set vl.host */
+    if (data->host.configured) {
       char temp[DATA_MAX_NAME_LEN];
+      if (hostname_cell_ptr == NULL)
+        csnmp_oid_to_string(temp, sizeof(temp), &current_suffix);
+      else
+        sstrncpy(temp, hostname_cell_ptr->value, sizeof(temp));
 
-      if (instance_list_ptr == NULL)
+      if (data->host.prefix == NULL)
+        sstrncpy(vl.host, temp, sizeof(vl.host));
+      else
+        snprintf(vl.host, sizeof(vl.host), "%s%s", data->host.prefix, temp);
+    } else {
+      sstrncpy(vl.host, host->name, sizeof(vl.host));
+    }
+
+    /* set vl.type_instance */
+    if (data->type_instance.configured) {
+      char temp[DATA_MAX_NAME_LEN];
+      if (type_instance_cell_ptr == NULL)
         csnmp_oid_to_string(temp, sizeof(temp), &current_suffix);
       else
-        sstrncpy(temp, instance_list_ptr->instance, sizeof(temp));
+        sstrncpy(temp, type_instance_cell_ptr->value, sizeof(temp));
 
-      if (data->instance.is_plugin) {
-        if (data->instance_prefix == NULL)
-          sstrncpy(vl.plugin_instance, temp, sizeof(vl.plugin_instance));
-        else
-          snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s%s",
-                   data->instance_prefix, temp);
+      if (data->type_instance.prefix == NULL)
+        sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance));
+      else
+        snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
+                 data->type_instance.prefix, temp);
+    } else if (data->type_instance.value) {
+      sstrncpy(vl.type_instance, data->type_instance.value,
+               sizeof(vl.type_instance));
+    }
 
-        if (data->type_instance)
-          sstrncpy(vl.type_instance, data->type_instance,
-                   sizeof(vl.type_instance));
-      } else {
-        if (data->instance_prefix == NULL)
-          sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance));
-        else
-          snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
-                   data->instance_prefix, temp);
+    /* set vl.plugin_instance */
+    if (data->plugin_instance.configured) {
+      char temp[DATA_MAX_NAME_LEN];
+      if (plugin_instance_cell_ptr == NULL)
+        csnmp_oid_to_string(temp, sizeof(temp), &current_suffix);
+      else
+        sstrncpy(temp, plugin_instance_cell_ptr->value, sizeof(temp));
 
-        if (data->plugin_instance)
-          sstrncpy(vl.plugin_instance, data->plugin_instance,
-                   sizeof(vl.plugin_instance));
-      }
+      if (data->plugin_instance.prefix == NULL)
+        sstrncpy(vl.plugin_instance, temp, sizeof(vl.plugin_instance));
+      else
+        snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s%s",
+                 data->plugin_instance.prefix, temp);
+    } else if (data->plugin_instance.value) {
+      sstrncpy(vl.plugin_instance, data->plugin_instance.value,
+               sizeof(vl.plugin_instance));
     }
 
     vl.values_len = data->values_len;
@@ -1315,7 +1528,7 @@ static int csnmp_dispatch_table(host_definition_t *host,
     vl.values = values;
 
     for (i = 0; i < data->values_len; i++)
-      vl.values[i] = value_table_ptr[i]->value;
+      vl.values[i] = value_cell_ptr[i]->value;
 
     plugin_dispatch_values(&vl);
 
@@ -1323,10 +1536,10 @@ static int csnmp_dispatch_table(host_definition_t *host,
     vl.values_len = 0;
     vl.values = NULL;
 
-    if (instance_list != NULL)
-      instance_list_ptr = instance_list_ptr->next;
+    if (type_instance_cells != NULL)
+      type_instance_cell_ptr = type_instance_cell_ptr->next;
     else
-      value_table_ptr[0] = value_table_ptr[0]->next;
+      value_cell_ptr[0] = value_cell_ptr[0]->next;
   } /* while (have_more) */
 
   return (0);
@@ -1339,25 +1552,43 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
 
   const data_set_t *ds;
 
-  size_t oid_list_len = data->values_len + 1;
+  size_t oid_list_len = data->values_len;
+
+  if (data->type_instance.oid.oid_len > 0)
+    oid_list_len++;
+
+  if (data->plugin_instance.oid.oid_len > 0)
+    oid_list_len++;
+
+  if (data->host.oid.oid_len > 0)
+    oid_list_len++;
+
+  if (data->filter_oid.oid_len > 0)
+    oid_list_len++;
+
   /* Holds the last OID returned by the device. We use this in the GETNEXT
    * request to proceed. */
   oid_t oid_list[oid_list_len];
   /* Set to false when an OID has left its subtree so we don't re-request it
    * again. */
-  bool oid_list_todo[oid_list_len];
+  csnmp_oid_type_t oid_list_todo[oid_list_len];
 
   int status;
   size_t i;
 
-  /* `value_list_head' and `value_list_tail' implement a linked list for each
-   * value. `instance_list_head' and `instance_list_tail' implement a linked
-   * list of
-   * instance names. This is used to jump gaps in the table. */
-  csnmp_list_instances_t *instance_list_head;
-  csnmp_list_instances_t *instance_list_tail;
-  csnmp_table_values_t **value_list_head;
-  csnmp_table_values_t **value_list_tail;
+  /* `value_list_head' and `value_cells_tail' implement a linked list for each
+   * value. `instance_cells_head' and `instance_cells_tail' implement a linked
+   * list of instance names. This is used to jump gaps in the table. */
+  csnmp_cell_char_t *type_instance_cells_head = NULL;
+  csnmp_cell_char_t *type_instance_cells_tail = NULL;
+  csnmp_cell_char_t *plugin_instance_cells_head = NULL;
+  csnmp_cell_char_t *plugin_instance_cells_tail = NULL;
+  csnmp_cell_char_t *hostname_cells_head = NULL;
+  csnmp_cell_char_t *hostname_cells_tail = NULL;
+  csnmp_cell_char_t *filter_cells_head = NULL;
+  csnmp_cell_char_t *filter_cells_tail = NULL;
+  csnmp_cell_value_t **value_cells_head;
+  csnmp_cell_value_t **value_cells_tail;
 
   DEBUG("snmp plugin: csnmp_read_table (host = %s, data = %s)", host->name,
         data->name);
@@ -1382,31 +1613,48 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
   }
   assert(data->values_len > 0);
 
+  for (i = 0; i < data->values_len; i++)
+    oid_list_todo[i] = OID_TYPE_VARIABLE;
+
   /* We need a copy of all the OIDs, because GETNEXT will destroy them. */
   memcpy(oid_list, data->values, data->values_len * sizeof(oid_t));
-  if (data->instance.oid.oid_len > 0)
-    memcpy(oid_list + data->values_len, &data->instance.oid, sizeof(oid_t));
-  else /* no InstanceFrom option specified. */
-    oid_list_len--;
 
-  for (i = 0; i < oid_list_len; i++)
-    oid_list_todo[i] = 1;
+  if (data->type_instance.oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->type_instance.oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_TYPEINSTANCE;
+    i++;
+  }
+
+  if (data->plugin_instance.oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->plugin_instance.oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_PLUGININSTANCE;
+    i++;
+  }
+
+  if (data->host.oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->host.oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_HOST;
+    i++;
+  }
+
+  if (data->filter_oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->filter_oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_FILTER;
+    i++;
+  }
 
   /* We're going to construct n linked lists, one for each "value".
-   * value_list_head will contain pointers to the heads of these linked lists,
-   * value_list_tail will contain pointers to the tail of the lists. */
-  value_list_head = calloc(data->values_len, sizeof(*value_list_head));
-  value_list_tail = calloc(data->values_len, sizeof(*value_list_tail));
-  if ((value_list_head == NULL) || (value_list_tail == NULL)) {
+   * value_cells_head will contain pointers to the heads of these linked lists,
+   * value_cells_tail will contain pointers to the tail of the lists. */
+  value_cells_head = calloc(data->values_len, sizeof(*value_cells_head));
+  value_cells_tail = calloc(data->values_len, sizeof(*value_cells_tail));
+  if ((value_cells_head == NULL) || (value_cells_tail == NULL)) {
     ERROR("snmp plugin: csnmp_read_table: calloc failed.");
-    sfree(value_list_head);
-    sfree(value_list_tail);
+    sfree(value_cells_head);
+    sfree(value_cells_tail);
     return -1;
   }
 
-  instance_list_head = NULL;
-  instance_list_tail = NULL;
-
   status = 0;
   while (status == 0) {
     req = snmp_pdu_create(SNMP_MSG_GETNEXT);
@@ -1519,30 +1767,126 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
       }
 
       /* An instance is configured and the res variable we process is the
-       * instance value (last index) */
-      if ((data->instance.oid.oid_len > 0) && (i == data->values_len)) {
+       * instance value */
+      if (oid_list_todo[i] == OID_TYPE_TYPEINSTANCE) {
+        if ((vb->type == SNMP_ENDOFMIBVIEW) ||
+            (snmp_oid_ncompare(data->type_instance.oid.oid,
+                               data->type_instance.oid.oid_len, vb->name,
+                               vb->name_length,
+                               data->type_instance.oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; TypeInstance left its "
+                "subtree.",
+                host->name, data->name);
+          oid_list_todo[i] = 0;
+          continue;
+        }
+
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
+         * add it to the list */
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->type_instance.oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
+                host->name);
+          status = -1;
+          break;
+        }
+
+        if (csnmp_ignore_instance(cell, data)) {
+          sfree(cell);
+        } else {
+          csnmp_cell_replace_reserved_chars(cell);
+
+          DEBUG("snmp plugin: il->type_instance = `%s';", cell->value);
+          csnmp_cells_append(&type_instance_cells_head,
+                             &type_instance_cells_tail, cell);
+        }
+      } else if (oid_list_todo[i] == OID_TYPE_PLUGININSTANCE) {
+        if ((vb->type == SNMP_ENDOFMIBVIEW) ||
+            (snmp_oid_ncompare(data->plugin_instance.oid.oid,
+                               data->plugin_instance.oid.oid_len, vb->name,
+                               vb->name_length,
+                               data->plugin_instance.oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; TypeInstance left its "
+                "subtree.",
+                host->name, data->name);
+          oid_list_todo[i] = 0;
+          continue;
+        }
+
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
+         * add it to the list */
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->plugin_instance.oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
+                host->name);
+          status = -1;
+          break;
+        }
+
+        csnmp_cell_replace_reserved_chars(cell);
+
+        DEBUG("snmp plugin: il->plugin_instance = `%s';", cell->value);
+        csnmp_cells_append(&plugin_instance_cells_head,
+                           &plugin_instance_cells_tail, cell);
+      } else if (oid_list_todo[i] == OID_TYPE_HOST) {
+        if ((vb->type == SNMP_ENDOFMIBVIEW) ||
+            (snmp_oid_ncompare(data->host.oid.oid, data->host.oid.oid_len,
+                               vb->name, vb->name_length,
+                               data->host.oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; Host left its subtree.",
+                host->name, data->name);
+          oid_list_todo[i] = 0;
+          continue;
+        }
+
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
+         * add it to the list */
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->host.oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
+                host->name);
+          status = -1;
+          break;
+        }
+
+        csnmp_cell_replace_reserved_chars(cell);
+
+        DEBUG("snmp plugin: il->hostname = `%s';", cell->value);
+        csnmp_cells_append(&hostname_cells_head, &hostname_cells_tail, cell);
+      } else if (oid_list_todo[i] == OID_TYPE_FILTER) {
         if ((vb->type == SNMP_ENDOFMIBVIEW) ||
-            (snmp_oid_ncompare(
-                 data->instance.oid.oid, data->instance.oid.oid_len, vb->name,
-                 vb->name_length, data->instance.oid.oid_len) != 0)) {
-          DEBUG("snmp plugin: host = %s; data = %s; Instance left its subtree.",
+            (snmp_oid_ncompare(data->filter_oid.oid, data->filter_oid.oid_len,
+                               vb->name, vb->name_length,
+                               data->filter_oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; Host left its subtree.",
                 host->name, data->name);
           oid_list_todo[i] = 0;
           continue;
         }
 
-        /* Allocate a new `csnmp_list_instances_t', insert the instance name and
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
          * add it to the list */
-        if (csnmp_instance_list_add(&instance_list_head, &instance_list_tail,
-                                    res, host, data) != 0) {
-          ERROR("snmp plugin: host %s: csnmp_instance_list_add failed.",
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->filter_oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
                 host->name);
           status = -1;
           break;
         }
+
+        csnmp_cell_replace_reserved_chars(cell);
+
+        DEBUG("snmp plugin: il->filter = `%s';", cell->value);
+        csnmp_cells_append(&filter_cells_head, &filter_cells_tail, cell);
       } else /* The variable we are processing is a normal value */
       {
-        csnmp_table_values_t *vt;
+        assert(oid_list_todo[i] == OID_TYPE_VARIABLE);
+
+        csnmp_cell_value_t *vt;
         oid_t vb_name;
         oid_t suffix;
         int ret;
@@ -1561,10 +1905,9 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
         }
 
         /* Make sure the OIDs returned by the agent are increasing. Otherwise
-         * our
-         * table matching algorithm will get confused. */
-        if ((value_list_tail[i] != NULL) &&
-            (csnmp_oid_compare(&suffix, &value_list_tail[i]->suffix) <= 0)) {
+         * our table matching algorithm will get confused. */
+        if ((value_cells_tail[i] != NULL) &&
+            (csnmp_oid_compare(&suffix, &value_cells_tail[i]->suffix) <= 0)) {
           DEBUG("snmp plugin: host = %s; data = %s; i = %" PRIsz "; "
                 "Suffix is not increasing.",
                 host->name, data->name, i);
@@ -1585,11 +1928,11 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
         memcpy(&vt->suffix, &suffix, sizeof(vt->suffix));
         vt->next = NULL;
 
-        if (value_list_tail[i] == NULL)
-          value_list_head[i] = vt;
+        if (value_cells_tail[i] == NULL)
+          value_cells_head[i] = vt;
         else
-          value_list_tail[i]->next = vt;
-        value_list_tail[i] = vt;
+          value_cells_tail[i]->next = vt;
+        value_cells_tail[i] = vt;
       }
 
       /* Copy OID to oid_list[i] */
@@ -1608,25 +1951,45 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
   res = NULL;
 
   if (status == 0)
-    csnmp_dispatch_table(host, data, instance_list_head, value_list_head);
+    csnmp_dispatch_table(host, data, type_instance_cells_head,
+                         plugin_instance_cells_head, hostname_cells_head,
+                         filter_cells_head, value_cells_head);
 
   /* Free all allocated variables here */
-  while (instance_list_head != NULL) {
-    csnmp_list_instances_t *next = instance_list_head->next;
-    sfree(instance_list_head);
-    instance_list_head = next;
+  while (type_instance_cells_head != NULL) {
+    csnmp_cell_char_t *next = type_instance_cells_head->next;
+    sfree(type_instance_cells_head);
+    type_instance_cells_head = next;
+  }
+
+  while (plugin_instance_cells_head != NULL) {
+    csnmp_cell_char_t *next = plugin_instance_cells_head->next;
+    sfree(plugin_instance_cells_head);
+    plugin_instance_cells_head = next;
+  }
+
+  while (hostname_cells_head != NULL) {
+    csnmp_cell_char_t *next = hostname_cells_head->next;
+    sfree(hostname_cells_head);
+    hostname_cells_head = next;
+  }
+
+  while (filter_cells_head != NULL) {
+    csnmp_cell_char_t *next = filter_cells_head->next;
+    sfree(filter_cells_head);
+    filter_cells_head = next;
   }
 
   for (i = 0; i < data->values_len; i++) {
-    while (value_list_head[i] != NULL) {
-      csnmp_table_values_t *next = value_list_head[i]->next;
-      sfree(value_list_head[i]);
-      value_list_head[i] = next;
+    while (value_cells_head[i] != NULL) {
+      csnmp_cell_value_t *next = value_cells_head[i]->next;
+      sfree(value_cells_head[i]);
+      value_cells_head[i] = next;
     }
   }
 
-  sfree(value_list_head);
-  sfree(value_list_tail);
+  sfree(value_cells_head);
+  sfree(value_cells_tail);
 
   return 0;
 } /* int csnmp_read_table */
@@ -1678,10 +2041,11 @@ static int csnmp_read_value(host_definition_t *host, data_definition_t *data) {
   sstrncpy(vl.host, host->name, sizeof(vl.host));
   sstrncpy(vl.plugin, data->plugin_name, sizeof(vl.plugin));
   sstrncpy(vl.type, data->type, sizeof(vl.type));
-  if (data->type_instance)
-    sstrncpy(vl.type_instance, data->type_instance, sizeof(vl.type_instance));
-  if (data->plugin_instance)
-    sstrncpy(vl.plugin_instance, data->plugin_instance,
+  if (data->type_instance.value)
+    sstrncpy(vl.type_instance, data->type_instance.value,
+             sizeof(vl.type_instance));
+  if (data->plugin_instance.value)
+    sstrncpy(vl.plugin_instance, data->plugin_instance.value,
              sizeof(vl.plugin_instance));
 
   vl.interval = host->interval;
@@ -1794,15 +2158,7 @@ static int csnmp_shutdown(void) {
   while (data_this != NULL) {
     data_next = data_this->next;
 
-    sfree(data_this->name);
-    sfree(data_this->type);
-    sfree(data_this->plugin_name);
-    sfree(data_this->plugin_instance);
-    sfree(data_this->type_instance);
-    sfree(data_this->instance_prefix);
-    sfree(data_this->values);
-    sfree(data_this->ignores);
-    sfree(data_this);
+    csnmp_data_definition_destroy(data_this);
 
     data_this = data_next;
   }
index 3c042a8..d65af1f 100644 (file)
@@ -383,11 +383,20 @@ static int snmp_agent_create_token(char const *input, int t_off, int n,
   int ret = 0;
 
   token->key = index_key;
-  token->str = strndup(input + t_off, n);
 
+  /* copy at most n bytes from input with offset t_off into token->str */
+  input += t_off;
+  size_t len = strlen(input);
+  if (n < len)
+    len = n;
+
+  token->str = malloc(len + 1);
   if (token->str == NULL)
     goto free_offset_error;
 
+  memcpy(token->str, input, len);
+  token->str[len] = '\0';
+
   *offset = t_off;
   ret = c_avl_insert(tree, (void *)offset, (void *)token);
 
@@ -522,7 +531,7 @@ static int snmp_agent_fill_index_list(table_definition_t *td,
 
     /* Parsing input string if necessary */
     if (td->index_keys[i].regex) {
-      regmatch_t m = {-1, -1};
+      regmatch_t m;
 
       /* Parsing input string */
       ret = snmp_agent_parse_index_key(ptr, &td->index_keys[i].regex_info,
index 68389fa..581f33d 100644 (file)
@@ -145,9 +145,9 @@ DEF_TEST(format_name_regex_index) {
   snmp_varlist_add_variable(&index_list_tmp, NULL, 0, ASN_OCTET_STR,
                             (const u_char *)plugin_inst, strlen(plugin_inst));
   snmp_varlist_add_variable(&index_list_tmp, NULL, 0, ASN_INTEGER,
-                            (const u_char *)&vcpu, 1);
+                            (const u_char *)&vcpu, sizeof(vcpu));
   snmp_varlist_add_variable(&index_list_tmp, NULL, 0, ASN_INTEGER,
-                            (const u_char *)&cpu, 1);
+                            (const u_char *)&cpu, sizeof(cpu));
 
   build_oid_noalloc(index_oid.oid, sizeof(index_oid.oid), &index_oid.oid_len,
                     NULL, 0, index_list_tmp);
@@ -663,9 +663,15 @@ DEF_TEST(get_token) {
 }
 
 DEF_TEST(tokenize) {
-  regmatch_t m[3] = {{5, 6},    /* "1" */
-                     {12, 13},  /* "2" */
-                     {19, 20}}; /* "3" */
+  regmatch_t m[3];
+
+  m[0].rm_so = 5;
+  m[0].rm_eo = 6;
+  m[1].rm_so = 12;
+  m[1].rm_eo = 13;
+  m[2].rm_so = 19;
+  m[2].rm_eo = 20;
+
   c_avl_tree_t *tokens =
       c_avl_create((int (*)(const void *, const void *))num_compare);
   const char input[] = "testA1-testB2-testC3";
index 189d605..492bea6 100644 (file)
@@ -132,18 +132,6 @@ static size_t tables_num;
 /*
  * configuration handling
  */
-
-static int tbl_config_set_s(char *name, char **var, oconfig_item_t *ci) {
-  if (ci->values_num != 1 || ci->values[0].type != OCONFIG_TYPE_STRING) {
-    log_err("\"%s\" expects a single string argument.", name);
-    return 1;
-  }
-
-  sfree(*var);
-  *var = sstrdup(ci->values[0].value.string);
-  return 0;
-} /* tbl_config_set_separator */
-
 static int tbl_config_append_array_i(char *name, size_t **var, size_t *len,
                                      oconfig_item_t *ci) {
   if (ci->values_num < 1) {
@@ -196,9 +184,9 @@ static int tbl_config_result(tbl_t *tbl, oconfig_item_t *ci) {
     oconfig_item_t *c = ci->children + i;
 
     if (strcasecmp(c->key, "Type") == 0)
-      tbl_config_set_s(c->key, &res->type, c);
+      cf_util_get_string(c, &res->type);
     else if (strcasecmp(c->key, "InstancePrefix") == 0)
-      tbl_config_set_s(c->key, &res->instance_prefix, c);
+      cf_util_get_string(c, &res->instance_prefix);
     else if (strcasecmp(c->key, "InstancesFrom") == 0)
       tbl_config_append_array_i(c->key, &res->instances, &res->instances_num,
                                 c);
@@ -253,11 +241,11 @@ static int tbl_config_table(oconfig_item_t *ci) {
     oconfig_item_t *c = ci->children + i;
 
     if (strcasecmp(c->key, "Separator") == 0)
-      tbl_config_set_s(c->key, &tbl->sep, c);
+      cf_util_get_string(c, &tbl->sep);
     else if (strcasecmp(c->key, "Plugin") == 0)
-      tbl_config_set_s(c->key, &tbl->plugin_name, c);
+      cf_util_get_string(c, &tbl->plugin_name);
     else if (strcasecmp(c->key, "Instance") == 0)
-      tbl_config_set_s(c->key, &tbl->instance, c);
+      cf_util_get_string(c, &tbl->instance);
     else if (strcasecmp(c->key, "Result") == 0)
       tbl_config_result(tbl, c);
     else
index 7900133..79300f1 100644 (file)
@@ -109,90 +109,6 @@ static int ut_threshold_add(const threshold_t *th) { /* {{{ */
  * The following approximately two hundred functions are used to handle the
  * configuration and fill the threshold list.
  * {{{ */
-static int ut_config_type_datasource(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("threshold values: The `DataSource' option needs exactly one "
-            "string argument.");
-    return -1;
-  }
-
-  sstrncpy(th->data_source, ci->values[0].value.string,
-           sizeof(th->data_source));
-
-  return 0;
-} /* int ut_config_type_datasource */
-
-static int ut_config_type_instance(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("threshold values: The `Instance' option needs exactly one "
-            "string argument.");
-    return -1;
-  }
-
-  sstrncpy(th->type_instance, ci->values[0].value.string,
-           sizeof(th->type_instance));
-
-  return 0;
-} /* int ut_config_type_instance */
-
-static int ut_config_type_max(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    WARNING("threshold values: The `%s' option needs exactly one "
-            "number argument.",
-            ci->key);
-    return -1;
-  }
-
-  if (strcasecmp(ci->key, "WarningMax") == 0)
-    th->warning_max = ci->values[0].value.number;
-  else
-    th->failure_max = ci->values[0].value.number;
-
-  return 0;
-} /* int ut_config_type_max */
-
-static int ut_config_type_min(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    WARNING("threshold values: The `%s' option needs exactly one "
-            "number argument.",
-            ci->key);
-    return -1;
-  }
-
-  if (strcasecmp(ci->key, "WarningMin") == 0)
-    th->warning_min = ci->values[0].value.number;
-  else
-    th->failure_min = ci->values[0].value.number;
-
-  return 0;
-} /* int ut_config_type_min */
-
-static int ut_config_type_hits(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    WARNING("threshold values: The `%s' option needs exactly one "
-            "number argument.",
-            ci->key);
-    return -1;
-  }
-
-  th->hits = ci->values[0].value.number;
-
-  return 0;
-} /* int ut_config_type_hits */
-
-static int ut_config_type_hysteresis(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    WARNING("threshold values: The `%s' option needs exactly one "
-            "number argument.",
-            ci->key);
-    return -1;
-  }
-
-  th->hysteresis = ci->values[0].value.number;
-
-  return 0;
-} /* int ut_config_type_hysteresis */
-
 static int ut_config_type(const threshold_t *th_orig, oconfig_item_t *ci) {
   threshold_t th;
   int status = 0;
@@ -223,15 +139,19 @@ static int ut_config_type(const threshold_t *th_orig, oconfig_item_t *ci) {
     oconfig_item_t *option = ci->children + i;
 
     if (strcasecmp("Instance", option->key) == 0)
-      status = ut_config_type_instance(&th, option);
+      status = cf_util_get_string_buffer(option, th.type_instance,
+                                         sizeof(th.type_instance));
     else if (strcasecmp("DataSource", option->key) == 0)
-      status = ut_config_type_datasource(&th, option);
-    else if ((strcasecmp("WarningMax", option->key) == 0) ||
-             (strcasecmp("FailureMax", option->key) == 0))
-      status = ut_config_type_max(&th, option);
-    else if ((strcasecmp("WarningMin", option->key) == 0) ||
-             (strcasecmp("FailureMin", option->key) == 0))
-      status = ut_config_type_min(&th, option);
+      status = cf_util_get_string_buffer(option, th.data_source,
+                                         sizeof(th.data_source));
+    else if (strcasecmp("WarningMax", option->key) == 0)
+      status = cf_util_get_double(option, &th.warning_max);
+    else if (strcasecmp("FailureMax", option->key) == 0)
+      status = cf_util_get_double(option, &th.failure_max);
+    else if (strcasecmp("WarningMin", option->key) == 0)
+      status = cf_util_get_double(option, &th.warning_min);
+    else if (strcasecmp("FailureMin", option->key) == 0)
+      status = cf_util_get_double(option, &th.failure_min);
     else if (strcasecmp("Interesting", option->key) == 0)
       status = cf_util_get_flag(option, &th.flags, UT_FLAG_INTERESTING);
     else if (strcasecmp("Invert", option->key) == 0)
@@ -243,9 +163,9 @@ static int ut_config_type(const threshold_t *th_orig, oconfig_item_t *ci) {
     else if (strcasecmp("Percentage", option->key) == 0)
       status = cf_util_get_flag(option, &th.flags, UT_FLAG_PERCENTAGE);
     else if (strcasecmp("Hits", option->key) == 0)
-      status = ut_config_type_hits(&th, option);
+      status = cf_util_get_int(option, &th.hits);
     else if (strcasecmp("Hysteresis", option->key) == 0)
-      status = ut_config_type_hysteresis(&th, option);
+      status = cf_util_get_double(option, &th.hysteresis);
     else {
       WARNING("threshold values: Option `%s' not allowed inside a `Type' "
               "block.",
@@ -264,19 +184,6 @@ static int ut_config_type(const threshold_t *th_orig, oconfig_item_t *ci) {
   return status;
 } /* int ut_config_type */
 
-static int ut_config_plugin_instance(threshold_t *th, oconfig_item_t *ci) {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("threshold values: The `Instance' option needs exactly one "
-            "string argument.");
-    return -1;
-  }
-
-  sstrncpy(th->plugin_instance, ci->values[0].value.string,
-           sizeof(th->plugin_instance));
-
-  return 0;
-} /* int ut_config_plugin_instance */
-
 static int ut_config_plugin(const threshold_t *th_orig, oconfig_item_t *ci) {
   threshold_t th;
   int status = 0;
@@ -302,7 +209,8 @@ static int ut_config_plugin(const threshold_t *th_orig, oconfig_item_t *ci) {
     if (strcasecmp("Type", option->key) == 0)
       status = ut_config_type(&th, option);
     else if (strcasecmp("Instance", option->key) == 0)
-      status = ut_config_plugin_instance(&th, option);
+      status = cf_util_get_string_buffer(option, th.plugin_instance,
+                                         sizeof(th.plugin_instance));
     else {
       WARNING("threshold values: Option `%s' not allowed inside a `Plugin' "
               "block.",
index 1b1e6f0..f4933ee 100644 (file)
@@ -31,6 +31,7 @@ clock_state             value:GAUGE:0:U
 clock_stratum           value:GAUGE:0:U
 compression             uncompressed:DERIVE:0:U, compressed:DERIVE:0:U
 compression_ratio       value:GAUGE:0:2
+commands                value:DERIVE:0:U
 connections             value:DERIVE:0:U
 conntrack               value:GAUGE:0:4294967295
 contextswitch           value:DERIVE:0:U
@@ -211,6 +212,7 @@ ps_vm                   value:GAUGE:0:9223372036854775807
 pubsub                  value:GAUGE:0:U
 queue_length            value:GAUGE:0:U
 records                 value:GAUGE:0:U
+redis_command_cputime   value:DERIVE:0:U
 requests                value:GAUGE:0:U
 response_code           value:GAUGE:0:U
 response_time           value:GAUGE:0:U
index 61fe2e4..54ddb04 100644 (file)
@@ -92,47 +92,23 @@ struct udb_query_preparation_area_s /* {{{ */
 /*
  * Config Private functions
  */
-static int udb_config_set_string(char **ret_string, /* {{{ */
-                                 oconfig_item_t *ci) {
-  char *string;
-
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("db query utils: The `%s' config option "
-            "needs exactly one string argument.",
-            ci->key);
-    return -1;
-  }
-
-  string = strdup(ci->values[0].value.string);
-  if (string == NULL) {
-    ERROR("db query utils: strdup failed.");
-    return -1;
-  }
-
-  if (*ret_string != NULL)
-    free(*ret_string);
-  *ret_string = string;
-
-  return 0;
-} /* }}} int udb_config_set_string */
-
 static int udb_config_add_string(char ***ret_array, /* {{{ */
                                  size_t *ret_array_len, oconfig_item_t *ci) {
   char **array;
   size_t array_len;
 
   if (ci->values_num < 1) {
-    WARNING("db query utils: The `%s' config option "
-            "needs at least one argument.",
-            ci->key);
+    P_WARNING("The `%s' config option "
+              "needs at least one argument.",
+              ci->key);
     return -1;
   }
 
   for (int i = 0; i < ci->values_num; i++) {
     if (ci->values[i].type != OCONFIG_TYPE_STRING) {
-      WARNING("db query utils: Argument %i to the `%s' option "
-              "is not a string.",
-              i + 1, ci->key);
+      P_WARNING("Argument %i to the `%s' option "
+                "is not a string.",
+                i + 1, ci->key);
       return -1;
     }
   }
@@ -140,7 +116,7 @@ static int udb_config_add_string(char ***ret_array, /* {{{ */
   array_len = *ret_array_len;
   array = realloc(*ret_array, sizeof(char *) * (array_len + ci->values_num));
   if (array == NULL) {
-    ERROR("db query utils: realloc failed.");
+    P_ERROR("udb_config_add_string: realloc failed.");
     return -1;
   }
   *ret_array = array;
@@ -148,7 +124,7 @@ static int udb_config_add_string(char ***ret_array, /* {{{ */
   for (int i = 0; i < ci->values_num; i++) {
     array[array_len] = strdup(ci->values[i].value.string);
     if (array[array_len] == NULL) {
-      ERROR("db query utils: strdup failed.");
+      P_ERROR("udb_config_add_string: strdup failed.");
       *ret_array_len = array_len;
       return -1;
     }
@@ -161,18 +137,19 @@ static int udb_config_add_string(char ***ret_array, /* {{{ */
 
 static int udb_config_set_uint(unsigned int *ret_value, /* {{{ */
                                oconfig_item_t *ci) {
-  double tmp;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
-    WARNING("db query utils: The `%s' config option "
-            "needs exactly one numeric argument.",
-            ci->key);
+    P_WARNING("The `%s' config option "
+              "needs exactly one numeric argument.",
+              ci->key);
     return -1;
   }
 
-  tmp = ci->values[0].value.number;
-  if ((tmp < 0.0) || (tmp > ((double)UINT_MAX)))
+  double tmp = ci->values[0].value.number;
+  if ((tmp < 0.0) || (tmp > ((double)UINT_MAX))) {
+    P_WARNING("The value given for the `%s` option is out of range.", ci->key);
     return -ERANGE;
+  }
 
   *ret_value = (unsigned int)(tmp + .5);
   return 0;
@@ -194,7 +171,7 @@ static int udb_result_submit(udb_result_t *r, /* {{{ */
 
   vl.values = calloc(r->values_num, sizeof(*vl.values));
   if (vl.values == NULL) {
-    ERROR("db query utils: calloc failed.");
+    P_ERROR("udb_result_submit: calloc failed.");
     return -1;
   }
   vl.values_len = r_area->ds->ds_num;
@@ -203,8 +180,8 @@ static int udb_result_submit(udb_result_t *r, /* {{{ */
     char *value_str = r_area->values_buffer[i];
 
     if (0 != parse_value(value_str, &vl.values[i], r_area->ds->ds[i].type)) {
-      ERROR("db query utils: udb_result_submit: Parsing `%s' as %s failed.",
-            value_str, DS_TYPE_TO_STRING(r_area->ds->ds[i].type));
+      P_ERROR("udb_result_submit: Parsing `%s' as %s failed.", value_str,
+              DS_TYPE_TO_STRING(r_area->ds->ds[i].type));
       errno = EINVAL;
       free(vl.values);
       return -1;
@@ -238,7 +215,7 @@ static int udb_result_submit(udb_result_t *r, /* {{{ */
       int status = strjoin(vl.type_instance, sizeof(vl.type_instance),
                            r_area->instances_buffer, r->instances_num, "-");
       if (status < 0) {
-        ERROR(
+        P_ERROR(
             "udb_result_submit: creating type_instance failed with status %d.",
             status);
         return status;
@@ -249,7 +226,7 @@ static int udb_result_submit(udb_result_t *r, /* {{{ */
       int status = strjoin(tmp, sizeof(tmp), r_area->instances_buffer,
                            r->instances_num, "-");
       if (status < 0) {
-        ERROR(
+        P_ERROR(
             "udb_result_submit: creating type_instance failed with status %d.",
             status);
         return status;
@@ -267,7 +244,7 @@ static int udb_result_submit(udb_result_t *r, /* {{{ */
   if (r->metadata_num > 0) {
     vl.meta = meta_data_create();
     if (vl.meta == NULL) {
-      ERROR("db query utils:: meta_data_create failed.");
+      P_ERROR("udb_result_submit: meta_data_create failed.");
       free(vl.values);
       return -ENOMEM;
     }
@@ -276,7 +253,7 @@ static int udb_result_submit(udb_result_t *r, /* {{{ */
       int status = meta_data_add_string(vl.meta, r->metadata[i],
                                         r_area->metadata_buffer[i]);
       if (status != 0) {
-        ERROR("db query utils:: meta_data_add_string failed.");
+        P_ERROR("udb_result_submit: meta_data_add_string failed.");
         meta_data_destroy(vl.meta);
         vl.meta = NULL;
         free(vl.values);
@@ -355,18 +332,18 @@ static int udb_result_prepare_result(udb_result_t const *r, /* {{{ */
   /* Read `ds' and check number of values {{{ */
   prep_area->ds = plugin_get_ds(r->type);
   if (prep_area->ds == NULL) {
-    ERROR("db query utils: udb_result_prepare_result: Type `%s' is not "
-          "known by the daemon. See types.db(5) for details.",
-          r->type);
+    P_ERROR("udb_result_prepare_result: Type `%s' is not "
+            "known by the daemon. See types.db(5) for details.",
+            r->type);
     BAIL_OUT(-1);
   }
 
   if (prep_area->ds->ds_num != r->values_num) {
-    ERROR("db query utils: udb_result_prepare_result: The type `%s' "
-          "requires exactly %" PRIsz
-          " value%s, but the configuration specifies %" PRIsz ".",
-          r->type, prep_area->ds->ds_num,
-          (prep_area->ds->ds_num == 1) ? "" : "s", r->values_num);
+    P_ERROR("udb_result_prepare_result: The type `%s' "
+            "requires exactly %" PRIsz
+            " value%s, but the configuration specifies %" PRIsz ".",
+            r->type, prep_area->ds->ds_num,
+            (prep_area->ds->ds_num == 1) ? "" : "s", r->values_num);
     BAIL_OUT(-1);
   }
   /* }}} */
@@ -377,39 +354,39 @@ static int udb_result_prepare_result(udb_result_t const *r, /* {{{ */
     prep_area->instances_pos =
         (size_t *)calloc(r->instances_num, sizeof(size_t));
     if (prep_area->instances_pos == NULL) {
-      ERROR("db query utils: udb_result_prepare_result: calloc failed.");
+      P_ERROR("udb_result_prepare_result: calloc failed.");
       BAIL_OUT(-ENOMEM);
     }
 
     prep_area->instances_buffer =
         (char **)calloc(r->instances_num, sizeof(char *));
     if (prep_area->instances_buffer == NULL) {
-      ERROR("db query utils: udb_result_prepare_result: calloc failed.");
+      P_ERROR("udb_result_prepare_result: calloc failed.");
       BAIL_OUT(-ENOMEM);
     }
   } /* if (r->instances_num > 0) */
 
   prep_area->values_pos = (size_t *)calloc(r->values_num, sizeof(size_t));
   if (prep_area->values_pos == NULL) {
-    ERROR("db query utils: udb_result_prepare_result: calloc failed.");
+    P_ERROR("udb_result_prepare_result: calloc failed.");
     BAIL_OUT(-ENOMEM);
   }
 
   prep_area->values_buffer = (char **)calloc(r->values_num, sizeof(char *));
   if (prep_area->values_buffer == NULL) {
-    ERROR("db query utils: udb_result_prepare_result: calloc failed.");
+    P_ERROR("udb_result_prepare_result: calloc failed.");
     BAIL_OUT(-ENOMEM);
   }
 
   prep_area->metadata_pos = (size_t *)calloc(r->metadata_num, sizeof(size_t));
   if (prep_area->metadata_pos == NULL) {
-    ERROR("db query utils: udb_result_prepare_result: calloc failed.");
+    P_ERROR("udb_result_prepare_result: calloc failed.");
     BAIL_OUT(-ENOMEM);
   }
 
   prep_area->metadata_buffer = (char **)calloc(r->metadata_num, sizeof(char *));
   if (prep_area->metadata_buffer == NULL) {
-    ERROR("db query utils: udb_result_prepare_result: calloc failed.");
+    P_ERROR("udb_result_prepare_result: calloc failed.");
     BAIL_OUT(-ENOMEM);
   }
 
@@ -427,9 +404,9 @@ static int udb_result_prepare_result(udb_result_t const *r, /* {{{ */
     }
 
     if (j >= column_num) {
-      ERROR("db query utils: udb_result_prepare_result: "
-            "Column `%s' could not be found.",
-            r->instances[i]);
+      P_ERROR("udb_result_prepare_result: "
+              "Column `%s' could not be found.",
+              r->instances[i]);
       BAIL_OUT(-ENOENT);
     }
   } /* }}} for (i = 0; i < r->instances_num; i++) */
@@ -446,9 +423,9 @@ static int udb_result_prepare_result(udb_result_t const *r, /* {{{ */
     }
 
     if (j >= column_num) {
-      ERROR("db query utils: udb_result_prepare_result: "
-            "Column `%s' could not be found.",
-            r->values[i]);
+      P_ERROR("udb_result_prepare_result: "
+              "Column `%s' could not be found.",
+              r->values[i]);
       BAIL_OUT(-ENOENT);
     }
   } /* }}} for (i = 0; i < r->values_num; i++) */
@@ -465,9 +442,9 @@ static int udb_result_prepare_result(udb_result_t const *r, /* {{{ */
     }
 
     if (j >= column_num) {
-      ERROR("db query utils: udb_result_prepare_result: "
-            "Metadata column `%s' could not be found.",
-            r->values[i]);
+      P_ERROR("udb_result_prepare_result: "
+              "Metadata column `%s' could not be found.",
+              r->values[i]);
       BAIL_OUT(-ENOENT);
     }
   } /* }}} for (i = 0; i < r->metadata_num; i++) */
@@ -507,14 +484,14 @@ static int udb_result_create(const char *query_name, /* {{{ */
   int status;
 
   if (ci->values_num != 0) {
-    WARNING("db query utils: The `Result' block doesn't accept "
-            "any arguments. Ignoring %i argument%s.",
-            ci->values_num, (ci->values_num == 1) ? "" : "s");
+    P_WARNING("The `Result' block doesn't accept "
+              "any arguments. Ignoring %i argument%s.",
+              ci->values_num, (ci->values_num == 1) ? "" : "s");
   }
 
   r = calloc(1, sizeof(*r));
   if (r == NULL) {
-    ERROR("db query utils: calloc failed.");
+    P_ERROR("udb_result_create: calloc failed.");
     return -1;
   }
   r->type = NULL;
@@ -530,9 +507,9 @@ static int udb_result_create(const char *query_name, /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Type", child->key) == 0)
-      status = udb_config_set_string(&r->type, child);
+      status = cf_util_get_string(child, &r->type);
     else if (strcasecmp("InstancePrefix", child->key) == 0)
-      status = udb_config_set_string(&r->instance_prefix, child);
+      status = cf_util_get_string(child, &r->instance_prefix);
     else if (strcasecmp("InstancesFrom", child->key) == 0)
       status = udb_config_add_string(&r->instances, &r->instances_num, child);
     else if (strcasecmp("ValuesFrom", child->key) == 0)
@@ -540,8 +517,8 @@ static int udb_result_create(const char *query_name, /* {{{ */
     else if (strcasecmp("MetadataFrom", child->key) == 0)
       status = udb_config_add_string(&r->metadata, &r->metadata_num, child);
     else {
-      WARNING("db query utils: Query `%s': Option `%s' not allowed here.",
-              query_name, child->key);
+      P_WARNING("Query `%s': Option `%s' not allowed here.", query_name,
+                child->key);
       status = -1;
     }
 
@@ -552,15 +529,15 @@ static int udb_result_create(const char *query_name, /* {{{ */
   /* Check that all necessary options have been given. */
   while (status == 0) {
     if (r->type == NULL) {
-      WARNING("db query utils: `Type' not given for "
-              "result in query `%s'",
-              query_name);
+      P_WARNING("udb_result_create: `Type' not given for "
+                "result in query `%s'",
+                query_name);
       status = -1;
     }
     if (r->values == NULL) {
-      WARNING("db query utils: `ValuesFrom' not given for "
-              "result in query `%s'",
-              query_name);
+      P_WARNING("udb_result_create: `ValuesFrom' not given for "
+                "result in query `%s'",
+                query_name);
       status = -1;
     }
 
@@ -623,14 +600,14 @@ int udb_query_create(udb_query_t ***ret_query_list, /* {{{ */
   query_list_len = *ret_query_list_len;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    WARNING("db query utils: The `Query' block "
-            "needs exactly one string argument.");
+    P_WARNING("udb_result_create: The `Query' block "
+              "needs exactly one string argument.");
     return -1;
   }
 
   q = calloc(1, sizeof(*q));
   if (q == NULL) {
-    ERROR("db query utils: calloc failed.");
+    P_ERROR("udb_query_create: calloc failed.");
     return -1;
   }
   q->min_version = 0;
@@ -639,7 +616,7 @@ int udb_query_create(udb_query_t ***ret_query_list, /* {{{ */
   q->results = NULL;
   q->plugin_instance_from = NULL;
 
-  status = udb_config_set_string(&q->name, ci);
+  status = cf_util_get_string(ci, &q->name);
   if (status != 0) {
     sfree(q);
     return status;
@@ -650,7 +627,7 @@ int udb_query_create(udb_query_t ***ret_query_list, /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Statement", child->key) == 0)
-      status = udb_config_set_string(&q->statement, child);
+      status = cf_util_get_string(child, &q->statement);
     else if (strcasecmp("Result", child->key) == 0)
       status = udb_result_create(q->name, &q->results, child);
     else if (strcasecmp("MinVersion", child->key) == 0)
@@ -658,19 +635,19 @@ int udb_query_create(udb_query_t ***ret_query_list, /* {{{ */
     else if (strcasecmp("MaxVersion", child->key) == 0)
       status = udb_config_set_uint(&q->max_version, child);
     else if (strcasecmp("PluginInstanceFrom", child->key) == 0)
-      status = udb_config_set_string(&q->plugin_instance_from, child);
+      status = cf_util_get_string(child, &q->plugin_instance_from);
 
     /* Call custom callbacks */
     else if (cb != NULL) {
       status = (*cb)(q, child);
       if (status != 0) {
-        WARNING("db query utils: The configuration callback failed "
-                "to handle `%s'.",
-                child->key);
+        P_WARNING("The configuration callback failed "
+                  "to handle `%s'.",
+                  child->key);
       }
     } else {
-      WARNING("db query utils: Query `%s': Option `%s' not allowed here.",
-              q->name, child->key);
+      P_WARNING("Query `%s': Option `%s' not allowed here.", q->name,
+                child->key);
       status = -1;
     }
 
@@ -681,12 +658,11 @@ int udb_query_create(udb_query_t ***ret_query_list, /* {{{ */
   /* Check that all necessary options have been given. */
   if (status == 0) {
     if (q->statement == NULL) {
-      WARNING("db query utils: Query `%s': No `Statement' given.", q->name);
+      P_WARNING("Query `%s': No `Statement' given.", q->name);
       status = -1;
     }
     if (q->results == NULL) {
-      WARNING("db query utils: Query `%s': No (valid) `Result' block given.",
-              q->name);
+      P_WARNING("Query `%s': No (valid) `Result' block given.", q->name);
       status = -1;
     }
   } /* if (status == 0) */
@@ -698,7 +674,7 @@ int udb_query_create(udb_query_t ***ret_query_list, /* {{{ */
 
     temp = realloc(query_list, sizeof(*query_list) * (query_list_len + 1));
     if (temp == NULL) {
-      ERROR("db query utils: realloc failed");
+      P_ERROR("udb_query_create: realloc failed");
       status = -1;
     } else {
       query_list = temp;
@@ -738,8 +714,8 @@ int udb_query_pick_from_list_by_name(const char *name, /* {{{ */
 
   if ((name == NULL) || (src_list == NULL) || (dst_list == NULL) ||
       (dst_list_len == NULL)) {
-    ERROR("db query utils: udb_query_pick_from_list_by_name: "
-          "Invalid argument.");
+    P_ERROR("udb_query_pick_from_list_by_name: "
+            "Invalid argument.");
     return -EINVAL;
   }
 
@@ -754,7 +730,7 @@ int udb_query_pick_from_list_by_name(const char *name, /* {{{ */
     tmp_list_len = *dst_list_len;
     tmp_list = realloc(*dst_list, (tmp_list_len + 1) * sizeof(udb_query_t *));
     if (tmp_list == NULL) {
-      ERROR("db query utils: realloc failed.");
+      P_ERROR("udb_query_pick_from_list_by_name: realloc failed.");
       return -ENOMEM;
     }
 
@@ -768,12 +744,12 @@ int udb_query_pick_from_list_by_name(const char *name, /* {{{ */
   } /* for (i = 0; i < src_list_len; i++) */
 
   if (num_added <= 0) {
-    ERROR("db query utils: Cannot find query `%s'. Make sure the <Query> "
-          "block is above the database definition!",
-          name);
+    P_ERROR("Cannot find query `%s'. Make sure the <Query> "
+            "block is above the database definition!",
+            name);
     return -ENOENT;
   } else {
-    DEBUG("db query utils: Added %i versions of query `%s'.", num_added, name);
+    DEBUG("Added %i versions of query `%s'.", num_added, name);
   }
 
   return 0;
@@ -786,15 +762,15 @@ int udb_query_pick_from_list(oconfig_item_t *ci, /* {{{ */
 
   if ((ci == NULL) || (src_list == NULL) || (dst_list == NULL) ||
       (dst_list_len == NULL)) {
-    ERROR("db query utils: udb_query_pick_from_list: "
-          "Invalid argument.");
+    P_ERROR("udb_query_pick_from_list: "
+            "Invalid argument.");
     return -EINVAL;
   }
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
-    ERROR("db query utils: The `%s' config option "
-          "needs exactly one string argument.",
-          ci->key);
+    P_ERROR("The `%s' config option "
+            "needs exactly one string argument.",
+            ci->key);
     return -1;
   }
   name = ci->values[0].value.string;
@@ -883,16 +859,16 @@ int udb_query_handle_result(udb_query_t const *q, /* {{{ */
 
   if ((prep_area->column_num < 1) || (prep_area->host == NULL) ||
       (prep_area->plugin == NULL) || (prep_area->db_name == NULL)) {
-    ERROR("db query utils: Query `%s': Query is not prepared; "
-          "can't handle result.",
-          q->name);
+    P_ERROR("Query `%s': Query is not prepared; "
+            "can't handle result.",
+            q->name);
     return -EINVAL;
   }
 
 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG /* {{{ */
   do {
     for (size_t i = 0; i < prep_area->column_num; i++) {
-      DEBUG("db query utils: udb_query_handle_result (%s, %s): "
+      DEBUG("udb_query_handle_result (%s, %s): "
             "column[%" PRIsz "] = %s;",
             prep_area->db_name, q->name, i, column_values[i]);
     }
@@ -908,9 +884,9 @@ int udb_query_handle_result(udb_query_t const *q, /* {{{ */
   }
 
   if (success == 0) {
-    ERROR("db query utils: udb_query_handle_result (%s, %s): "
-          "All results failed.",
-          prep_area->db_name, q->name);
+    P_ERROR("udb_query_handle_result (%s, %s): "
+            "All results failed.",
+            prep_area->db_name, q->name);
     return -1;
   }
 
@@ -946,8 +922,7 @@ int udb_query_prepare_result(udb_query_t const *q, /* {{{ */
 
   if ((prep_area->host == NULL) || (prep_area->plugin == NULL) ||
       (prep_area->db_name == NULL)) {
-    ERROR("db query utils: Query `%s': Prepare failed: Out of memory.",
-          q->name);
+    P_ERROR("Query `%s': Prepare failed: Out of memory.", q->name);
     udb_query_finish_result(q, prep_area);
     return -ENOMEM;
   }
@@ -955,7 +930,7 @@ int udb_query_prepare_result(udb_query_t const *q, /* {{{ */
 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG
   do {
     for (size_t i = 0; i < column_num; i++) {
-      DEBUG("db query utils: udb_query_prepare_result: "
+      DEBUG("udb_query_prepare_result: "
             "query = %s; column[%" PRIsz "] = %s;",
             q->name, i, column_names[i]);
     }
@@ -974,9 +949,9 @@ int udb_query_prepare_result(udb_query_t const *q, /* {{{ */
     }
 
     if (i >= column_num) {
-      ERROR("db query utils: udb_query_prepare_result: "
-            "Column `%s' from `PluginInstanceFrom' could not be found.",
-            q->plugin_instance_from);
+      P_ERROR("udb_query_prepare_result: "
+              "Column `%s' from `PluginInstanceFrom' could not be found.",
+              q->plugin_instance_from);
       udb_query_finish_result(q, prep_area);
       return -ENOENT;
     }
@@ -986,9 +961,9 @@ int udb_query_prepare_result(udb_query_t const *q, /* {{{ */
   for (r = q->results, r_area = prep_area->result_prep_areas; r != NULL;
        r = r->next, r_area = r_area->next) {
     if (!r_area) {
-      ERROR("db query utils: Query `%s': Invalid number of result "
-            "preparation areas.",
-            q->name);
+      P_ERROR("Query `%s': Invalid number of result "
+              "preparation areas.",
+              q->name);
       udb_query_finish_result(q, prep_area);
       return -EINVAL;
     }
index 0bc802b..44700b5 100644 (file)
@@ -66,8 +66,8 @@ static int gr_format_values(char *ret, size_t ret_len, int ds_num,
   else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
     BUFFER_ADD("%" PRIu64, vl->values[ds_num].absolute);
   else {
-    ERROR("gr_format_values plugin: Unknown data source type: %i",
-          ds->ds[ds_num].type);
+    P_ERROR("gr_format_values: Unknown data source type: %i",
+            ds->ds[ds_num].type);
     return -1;
   }
 
@@ -183,7 +183,7 @@ int format_graphite(char *buffer, size_t buffer_size, data_set_t const *ds,
   if (flags & GRAPHITE_STORE_RATES) {
     rates = uc_get_rate(ds, vl);
     if (rates == NULL) {
-      ERROR("format_graphite: error with uc_get_rate");
+      P_ERROR("format_graphite: error with uc_get_rate");
       return -1;
     }
   }
@@ -202,7 +202,7 @@ int format_graphite(char *buffer, size_t buffer_size, data_set_t const *ds,
     status = gr_format_name(key, sizeof(key), vl, ds_name, prefix, postfix,
                             escape_char, flags);
     if (status != 0) {
-      ERROR("format_graphite: error with gr_format_name");
+      P_ERROR("format_graphite: error with gr_format_name");
       sfree(rates);
       return status;
     }
@@ -212,7 +212,7 @@ int format_graphite(char *buffer, size_t buffer_size, data_set_t const *ds,
      * `values'. */
     status = gr_format_values(values, sizeof(values), i, ds, vl, rates);
     if (status != 0) {
-      ERROR("format_graphite: error with gr_format_values");
+      P_ERROR("format_graphite: error with gr_format_values");
       sfree(rates);
       return status;
     }
@@ -222,16 +222,16 @@ int format_graphite(char *buffer, size_t buffer_size, data_set_t const *ds,
         (size_t)snprintf(message, sizeof(message), "%s %s %u\r\n", key, values,
                          (unsigned int)CDTIME_T_TO_TIME_T(vl->time));
     if (message_len >= sizeof(message)) {
-      ERROR("format_graphite: message buffer too small: "
-            "Need %" PRIsz " bytes.",
-            message_len + 1);
+      P_ERROR("format_graphite: message buffer too small: "
+              "Need %" PRIsz " bytes.",
+              message_len + 1);
       sfree(rates);
       return -ENOMEM;
     }
 
     /* Append it in case we got multiple data set */
     if ((buffer_pos + message_len) >= buffer_size) {
-      ERROR("format_graphite: target buffer too small");
+      P_ERROR("format_graphite: target buffer too small");
       sfree(rates);
       return -ENOMEM;
     }
index ce7838d..8f92cfd 100644 (file)
@@ -96,7 +96,7 @@ static srrd_create_args_t *srrd_create_args_create(const char *filename,
 
   args = calloc(1, sizeof(*args));
   if (args == NULL) {
-    ERROR("srrd_create_args_create: calloc failed.");
+    P_ERROR("srrd_create_args_create: calloc failed.");
     return NULL;
   }
   args->filename = NULL;
@@ -106,14 +106,14 @@ static srrd_create_args_t *srrd_create_args_create(const char *filename,
 
   args->filename = strdup(filename);
   if (args->filename == NULL) {
-    ERROR("srrd_create_args_create: strdup failed.");
+    P_ERROR("srrd_create_args_create: strdup failed.");
     srrd_create_args_destroy(args);
     return NULL;
   }
 
   args->argv = calloc((size_t)(argc + 1), sizeof(*args->argv));
   if (args->argv == NULL) {
-    ERROR("srrd_create_args_create: calloc failed.");
+    P_ERROR("srrd_create_args_create: calloc failed.");
     srrd_create_args_destroy(args);
     return NULL;
   }
@@ -121,7 +121,7 @@ static srrd_create_args_t *srrd_create_args_create(const char *filename,
   for (args->argc = 0; args->argc < argc; args->argc++) {
     args->argv[args->argc] = strdup(argv[args->argc]);
     if (args->argv[args->argc] == NULL) {
-      ERROR("srrd_create_args_create: strdup failed.");
+      P_ERROR("srrd_create_args_create: strdup failed.");
       srrd_create_args_destroy(args);
       return NULL;
     }
@@ -212,7 +212,7 @@ static int rra_get(char ***ret, const value_list_t *vl, /* {{{ */
                         rra_types[j], cfg->xff, cdp_len, cdp_num);
 
       if ((status < 0) || ((size_t)status >= sizeof(buffer))) {
-        ERROR("rra_get: Buffer would have been truncated.");
+        P_ERROR("rra_get: Buffer would have been truncated.");
         continue;
       }
 
@@ -251,7 +251,7 @@ static int ds_get(char ***ret, /* {{{ */
 
   ds_def = calloc(ds->ds_num, sizeof(*ds_def));
   if (ds_def == NULL) {
-    ERROR("rrdtool plugin: calloc failed: %s", STRERRNO);
+    P_ERROR("ds_get: calloc failed: %s", STRERRNO);
     return -1;
   }
 
@@ -271,7 +271,7 @@ static int ds_get(char ***ret, /* {{{ */
     else if (d->type == DS_TYPE_ABSOLUTE)
       type = "ABSOLUTE";
     else {
-      ERROR("rrdtool plugin: Unknown DS type: %i", d->type);
+      P_ERROR("ds_get: Unknown DS type: %i", d->type);
       break;
     }
 
@@ -335,8 +335,8 @@ static int srrd_create(const char *filename, /* {{{ */
   status = rrd_create_r(filename_copy, pdp_step, last_up, argc, (void *)argv);
 
   if (status != 0) {
-    WARNING("rrdtool plugin: rrd_create_r (%s) failed: %s", filename,
-            rrd_get_error());
+    P_WARNING("srrd_create: rrd_create_r (%s) failed: %s", filename,
+              rrd_get_error());
   }
 
   sfree(filename_copy);
@@ -360,7 +360,7 @@ static int srrd_create(const char *filename, /* {{{ */
   new_argc = 6 + argc;
   new_argv = malloc((new_argc + 1) * sizeof(*new_argv));
   if (new_argv == NULL) {
-    ERROR("rrdtool plugin: malloc failed.");
+    P_ERROR("srrd_create: malloc failed.");
     return -1;
   }
 
@@ -388,8 +388,8 @@ static int srrd_create(const char *filename, /* {{{ */
   pthread_mutex_unlock(&librrd_lock);
 
   if (status != 0) {
-    WARNING("rrdtool plugin: rrd_create (%s) failed: %s", filename,
-            rrd_get_error());
+    P_WARNING("srrd_create: rrd_create (%s) failed: %s", filename,
+              rrd_get_error());
   }
 
   sfree(new_argv);
@@ -487,10 +487,11 @@ static void *srrd_create_thread(void *targs) /* {{{ */
   status = lock_file(args->filename);
   if (status != 0) {
     if (status == EEXIST)
-      NOTICE("srrd_create_thread: File \"%s\" is already being created.",
-             args->filename);
+      P_NOTICE("srrd_create_thread: File \"%s\" is already being created.",
+               args->filename);
     else
-      ERROR("srrd_create_thread: Unable to lock file \"%s\".", args->filename);
+      P_ERROR("srrd_create_thread: Unable to lock file \"%s\".",
+              args->filename);
     srrd_create_args_destroy(args);
     return 0;
   }
@@ -500,8 +501,8 @@ static void *srrd_create_thread(void *targs) /* {{{ */
   status = srrd_create(tmpfile, args->pdp_step, args->last_up, args->argc,
                        (void *)args->argv);
   if (status != 0) {
-    WARNING("srrd_create_thread: srrd_create (%s) returned status %i.",
-            args->filename, status);
+    P_WARNING("srrd_create_thread: srrd_create (%s) returned status %i.",
+              args->filename, status);
     unlink(tmpfile);
     unlock_file(args->filename);
     srrd_create_args_destroy(args);
@@ -510,8 +511,8 @@ static void *srrd_create_thread(void *targs) /* {{{ */
 
   status = rename(tmpfile, args->filename);
   if (status != 0) {
-    ERROR("srrd_create_thread: rename (\"%s\", \"%s\") failed: %s", tmpfile,
-          args->filename, STRERRNO);
+    P_ERROR("srrd_create_thread: rename (\"%s\", \"%s\") failed: %s", tmpfile,
+            args->filename, STRERRNO);
     unlink(tmpfile);
     unlock_file(args->filename);
     srrd_create_args_destroy(args);
@@ -556,7 +557,7 @@ static int srrd_create_async(const char *filename, /* {{{ */
 
   status = pthread_create(&thread, &attr, srrd_create_thread, args);
   if (status != 0) {
-    ERROR("srrd_create_async: pthread_create failed: %s", STRERROR(status));
+    P_ERROR("srrd_create_async: pthread_create failed: %s", STRERROR(status));
     pthread_attr_destroy(&attr);
     srrd_create_args_destroy(args);
     return status;
@@ -587,12 +588,12 @@ int cu_rrd_create_file(const char *filename, /* {{{ */
     return -1;
 
   if ((rra_num = rra_get(&rra_def, vl, cfg)) < 1) {
-    ERROR("cu_rrd_create_file failed: Could not calculate RRAs");
+    P_ERROR("cu_rrd_create_file failed: Could not calculate RRAs");
     return -1;
   }
 
   if ((ds_num = ds_get(&ds_def, ds, vl, cfg)) < 1) {
-    ERROR("cu_rrd_create_file failed: Could not calculate DSes");
+    P_ERROR("cu_rrd_create_file failed: Could not calculate DSes");
     rra_free(rra_num, rra_def);
     return -1;
   }
@@ -600,7 +601,7 @@ int cu_rrd_create_file(const char *filename, /* {{{ */
   argc = ds_num + rra_num;
 
   if ((argv = malloc(sizeof(*argv) * (argc + 1))) == NULL) {
-    ERROR("cu_rrd_create_file failed: %s", STRERRNO);
+    P_ERROR("cu_rrd_create_file failed: %s", STRERRNO);
     rra_free(rra_num, rra_def);
     ds_free(ds_num, ds_def);
     return -1;
@@ -624,25 +625,25 @@ int cu_rrd_create_file(const char *filename, /* {{{ */
     status = srrd_create_async(filename, stepsize, last_up, argc,
                                (const char **)argv);
     if (status != 0)
-      WARNING("cu_rrd_create_file: srrd_create_async (%s) "
-              "returned status %i.",
-              filename, status);
+      P_WARNING("cu_rrd_create_file: srrd_create_async (%s) "
+                "returned status %i.",
+                filename, status);
   } else /* synchronous */
   {
     status = lock_file(filename);
     if (status != 0) {
       if (status == EEXIST)
-        NOTICE("cu_rrd_create_file: File \"%s\" is already being created.",
-               filename);
+        P_NOTICE("cu_rrd_create_file: File \"%s\" is already being created.",
+                 filename);
       else
-        ERROR("cu_rrd_create_file: Unable to lock file \"%s\".", filename);
+        P_ERROR("cu_rrd_create_file: Unable to lock file \"%s\".", filename);
     } else {
       status =
           srrd_create(filename, stepsize, last_up, argc, (const char **)argv);
 
       if (status != 0) {
-        WARNING("cu_rrd_create_file: srrd_create (%s) returned status %i.",
-                filename, status);
+        P_WARNING("cu_rrd_create_file: srrd_create (%s) returned status %i.",
+                  filename, status);
       } else {
         DEBUG("cu_rrd_create_file: Successfully created RRD file \"%s\".",
               filename);
index c17654b..72cb594 100644 (file)
@@ -184,8 +184,8 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */
     return ENOMEM;
   node->host = NULL;
   node->port = 0;
-  node->timeout.tv_sec = 0;
-  node->timeout.tv_usec = 1000;
+  node->timeout.tv_sec = 1;
+  node->timeout.tv_usec = 0;
   node->conn = NULL;
   node->prefix = NULL;
   node->database = 0;
@@ -213,8 +213,11 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */
       }
     } else if (strcasecmp("Timeout", child->key) == 0) {
       status = cf_util_get_int(child, &timeout);
-      if (status == 0)
-        node->timeout.tv_usec = timeout;
+      if (status == 0) {
+        node->timeout.tv_usec = timeout * 1000;
+        node->timeout.tv_sec = node->timeout.tv_usec / 1000000L;
+        node->timeout.tv_usec %= 1000000L;
+      }
     } else if (strcasecmp("Prefix", child->key) == 0) {
       status = cf_util_get_string(child, &node->prefix);
     } else if (strcasecmp("Database", child->key) == 0) {
index 1578e1c..b35d10e 100644 (file)
@@ -699,21 +699,13 @@ static int wrr_config_node(oconfig_item_t *ci) /* {{{ */
     } else if (strcasecmp("Port", child->key) == 0) {
       host->port = cf_util_get_port_number(child);
       if (host->port == -1) {
-        ERROR("write_riemann plugin: Invalid argument "
-              "configured for the \"Port\" "
-              "option.");
         break;
       }
     } else if (strcasecmp("Protocol", child->key) == 0) {
       char tmp[16];
       status = cf_util_get_string_buffer(child, tmp, sizeof(tmp));
-      if (status != 0) {
-        ERROR("write_riemann plugin: cf_util_get_"
-              "string_buffer failed with "
-              "status %i.",
-              status);
+      if (status != 0)
         break;
-      }
 
       if (strcasecmp("UDP", tmp) == 0)
         host->client_type = RIEMANN_CLIENT_UDP;
@@ -729,31 +721,16 @@ static int wrr_config_node(oconfig_item_t *ci) /* {{{ */
                 tmp);
     } else if (strcasecmp("TLSCAFile", child->key) == 0) {
       status = cf_util_get_string(child, &host->tls_ca_file);
-      if (status != 0) {
-        ERROR("write_riemann plugin: cf_util_get_"
-              "string_buffer failed with "
-              "status %i.",
-              status);
+      if (status != 0)
         break;
-      }
     } else if (strcasecmp("TLSCertFile", child->key) == 0) {
       status = cf_util_get_string(child, &host->tls_cert_file);
-      if (status != 0) {
-        ERROR("write_riemann plugin: cf_util_get_"
-              "string_buffer failed with "
-              "status %i.",
-              status);
+      if (status != 0)
         break;
-      }
     } else if (strcasecmp("TLSKeyFile", child->key) == 0) {
       status = cf_util_get_string(child, &host->tls_key_file);
-      if (status != 0) {
-        ERROR("write_riemann plugin: cf_util_get_"
-              "string_buffer failed with "
-              "status %i.",
-              status);
+      if (status != 0)
         break;
-      }
     } else if (strcasecmp("StoreRates", child->key) == 0) {
       status = cf_util_get_boolean(child, &host->store_rates);
       if (status != 0)
index 4c9f42b..6ea8106 100644 (file)
@@ -1084,12 +1084,8 @@ static int sensu_config_node(oconfig_item_t *ci) /* {{{ */
         break;
     } else if (strcasecmp("Port", child->key) == 0) {
       status = cf_util_get_service(child, &host->service);
-      if (status != 0) {
-        ERROR("write_sensu plugin: Invalid argument "
-              "configured for the \"Port\" "
-              "option.");
+      if (status != 0)
         break;
-      }
     } else if (strcasecmp("StoreRates", child->key) == 0) {
       status = cf_util_get_boolean(child, &host->store_rates);
       if (status != 0)