Merge pull request #2051 from dsilakov/virt_list_domains
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Wed, 29 Mar 2017 15:29:55 +0000 (17:29 +0200)
committerGitHub <noreply@github.com>
Wed, 29 Mar 2017 15:29:55 +0000 (17:29 +0200)
virt plugin: get domains using virConnectListAllDomains

16 files changed:
configure.ac
contrib/redhat/collectd.spec
docs/BUILD.dpdkstat.md
src/collectd.conf.in
src/collectd.conf.pod
src/dpdkstat.c
src/intel_rdt.c
src/ovs_events.c
src/ovs_stats.c
src/processes.c
src/utils_cmd_flush.c
src/utils_format_kairosdb.c
src/utils_format_kairosdb.h
src/utils_ovs.c
src/virt.c
src/write_http.c

index 63cfca7..b6a47dc 100644 (file)
@@ -592,6 +592,14 @@ if test "x$ac_system" = "xLinux"; then
   fi
 
   if test "x$have_capability" = "xyes"; then
+    AC_CHECK_DECL([CAP_IS_SUPPORTED],
+      [have_capability="yes"],
+      [have_capability="no (CAP_IS_SUPPORTED not found)"],
+      [[#include <sys/capability.h>]]
+    )
+  fi
+
+  if test "x$have_capability" = "xyes"; then
     AC_DEFINE([HAVE_CAPABILITY], [1], [Define to 1 if you have cap_get_proc() (-lcap).])
   fi
 
@@ -5997,6 +6005,11 @@ if test "x$ac_system" = "xLinux"; then
   if test "x$c_cv_have_clock_boottime_monotonic" = "xyes"; then
     plugin_cpusleep="yes"
   fi
+
+  if test "x$with_libyajl" = "xyes" && test "x$with_libyajl2" = "xyes"; then
+    plugin_ovs_events="yes"
+    plugin_ovs_stats="yes"
+  fi
 fi
 
 if test "x$ac_system" = "xOpenBSD"; then
@@ -6173,11 +6186,6 @@ if test "x$with_libyajl" = "xyes"; then
   plugin_log_logstash="yes"
 fi
 
-if test "x$with_libyajl" = "xyes" && test "x$with_libyajl2" = "xyes"; then
-  plugin_ovs_events="yes"
-  plugin_ovs_stats="yes"
-fi
-
 if test "x$with_libperl" = "xyes" && test "x$c_cv_have_perl_ithreads" = "xyes"; then
   plugin_perl="yes"
 fi
index 451589d..bceaaf8 100644 (file)
 %define with_openldap 0%{!?_without_openldap:1}
 %define with_openvpn 0%{!?_without_openvpn:1}
 %define with_ovs_events 0%{!?_without_ovs_events:1}
+%define with_ovs_stats 0%{!?_without_ovs_stats:1}
 %define with_perl 0%{!?_without_perl:1}
 %define with_pinba 0%{!?_without_pinba:1}
 %define with_ping 0%{!?_without_ping:1}
 %define with_aquaero 0%{!?_without_aquaero:0}
 # plugin barometer disabled, requires a libi2c
 %define with_barometer 0%{!?_without_barometer:0}
-# plugin grpc disabled, requires protobuf-compiler >= 3.0
-%define with_grpc 0%{!?_without_grpc:0}
+# plugin dpdkevents disabled, requires libdpdk
+%define with_dpdkevents 0%{!?_without_dpdkevents:0}
 # plugin dpdkstat disabled, requires libdpdk
 %define with_dpdkstat 0%{!?_without_dpdkstat:0}
+# plugin grpc disabled, requires protobuf-compiler >= 3.0
+%define with_grpc 0%{!?_without_grpc:0}
 # plugin lpar disabled, requires AIX
 %define with_lpar 0%{!?_without_lpar:0}
 # plugin intel_rdt disabled, requires intel-cmt-cat
 %define with_gps 0
 %define with_mqtt 0
 %define with_ovs_events 0
+%define with_ovs_stats 0
 %define with_redis 0
 %define with_rrdcached 0
 %define with_write_redis 0
 Summary:       Statistics collection and monitoring daemon
 Name:          collectd
 Version:       5.7.1
-Release:       2%{?dist}
+Release:       6%{?dist}
 URL:           https://collectd.org
 Source:                https://collectd.org/files/%{name}-%{version}.tar.bz2
 License:       GPLv2
 Group:         System Environment/Daemons
 BuildRoot:     %{_tmppath}/%{name}-%{version}-root
-BuildRequires: libgcrypt-devel, kernel-headers, libcap-devel, which, xfsprogs-devel
+BuildRequires: libgcrypt-devel, kernel-headers, libcap-devel, which
 Vendor:                collectd development team <collectd@verplant.org>
 
 %if 0%{?fedora} || 0%{?rhel} >= 7
+BuildRequires:         xfsprogs-devel
 %{?systemd_requires}
 BuildRequires:         systemd
 %else
@@ -679,6 +684,17 @@ interfaces, dispatches the values to collectd and sends notifications
 whenever a link state change occurs in the OVS database.
 %endif
 
+%if %{with_ovs_stats}
+%package ovs_stats
+Summary:       Open vSwitch statistics plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: yajl-devel
+%description ovs_stats
+This plugin collects statictics of OVS connected bridges and
+interfaces.
+%endif
+
 %if %{with_perl}
 %package perl
 Summary:       Perl plugin for collectd
@@ -1125,6 +1141,12 @@ Collectd utilities
 %define _with_drbd --disable-drbd
 %endif
 
+%if %{with_dpdkevents}
+%define _with_dpdkevents --enable-dpdkevents
+%else
+%define _with_dpdkevents --disable-dpdkevents
+%endif
+
 %if %{with_dpdkstat}
 %define _with_dpdkstat --enable-dpdkstat
 %else
@@ -1467,6 +1489,12 @@ Collectd utilities
 %define _with_ovs_events --disable-ovs_events
 %endif
 
+%if %{with_ovs_stats}
+%define _with_ovs_stats --enable-ovs_stats
+%else
+%define _with_ovs_stats --disable-ovs_stats
+%endif
+
 %if %{with_perl}
 %define _with_perl --enable-perl --with-perl-bindings="INSTALLDIRS=vendor"
 %else
@@ -1843,6 +1871,7 @@ Collectd utilities
        %{?_with_disk} \
        %{?_with_dns} \
        %{?_with_drbd} \
+       %{?_with_dpdkevents} \
        %{?_with_dpdkstat} \
        %{?_with_email} \
        %{?_with_entropy} \
@@ -1899,6 +1928,7 @@ Collectd utilities
        %{?_with_openvpn} \
        %{?_with_oracle} \
        %{?_with_ovs_events} \
+       %{?_with_ovs_stats} \
        %{?_with_perl} \
        %{?_with_pf} \
        %{?_with_pinba} \
@@ -2125,9 +2155,6 @@ fi
 %if %{with_drbd}
 %{_libdir}/%{name}/drbd.so
 %endif
-%if %{with_dpdkstat}
-%{_libdir}/%{name}/dpdkstat.so
-%endif
 %if %{with_ethstat}
 %{_libdir}/%{name}/ethstat.so
 %endif
@@ -2209,9 +2236,6 @@ fi
 %if %{with_olsrd}
 %{_libdir}/%{name}/olsrd.so
 %endif
-%if %{with_ovs_events}
-%{_libdir}/%{name}/ovs_events.so
-%endif
 %if %{with_powerdns}
 %{_libdir}/%{name}/powerdns.so
 %endif
@@ -2389,6 +2413,16 @@ fi
 %{_libdir}/%{name}/dbi.so
 %endif
 
+%if %{with_dpdkevents}
+%files dpdkevents
+%{_libdir}/%{name}/dpdkevents.so
+%endif
+
+%if %{with_dpdkstat}
+%files dpdkstat
+%{_libdir}/%{name}/dpdkstat.so
+%endif
+
 %if %{with_email}
 %files email
 %{_libdir}/%{name}/email.so
@@ -2513,6 +2547,16 @@ fi
 %{_libdir}/%{name}/openldap.so
 %endif
 
+%if %{with_ovs_events}
+%files ovs_events
+%{_libdir}/%{name}/ovs_events.so
+%endif
+
+%if %{with_ovs_stats}
+%files ovs_stats
+%{_libdir}/%{name}/ovs_stats.so
+%endif
+
 %if %{with_perl}
 %files perl
 %{perl_vendorlib}/Collectd.pm
@@ -2632,6 +2676,18 @@ fi
 %doc contrib/
 
 %changelog
+* Sun Mar 05 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-6
+- Move recently added plugins to subpackages
+
+* Sun Mar 05 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-5
+- Add new ovs_stats plugin
+
+* Sun Mar 05 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-4
+- Don't enable XFS support on RHEL6, it is missing for i386
+
+* Sun Mar 05 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-3
+- Add dpdkevents plugin, disabled by default
+
 * Wed Feb 22 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-2
 - Enable XFS support in df plugin
 - Fix bogus date in changelog
index fe9f0e6..96f1eb9 100644 (file)
@@ -208,6 +208,12 @@ See also: http://dpdk.org/doc/guides/prog_guide/multi_proc_support.html
  *  The same PCI device configuration should be passed to the primary process as
     the secondary process uses the same port indexes as the primary.
  *  A blacklist / whitelist of NICs isn't supported yet.
+ *  Plugin initialization time depends on read interval. It requires 5 read
+    cycles to set up internal buffers and states. During that time no statistics
+    are submitted.
+ *  If number of DPDK ports is increased while plugin is running, internal
+    buffers are resized. That requires 3 read cycles and no port statistics
+    are submitted in that time.
 
 ## License
 
index 1e88bec..95ec21c 100644 (file)
 #  Address "127.0.0.1"
 #  Socket "/var/run/openvswitch/db.sock"
 #  Interfaces "br0" "veth0"
-#  SendNotification false
-#  DispatchValues true
+#  SendNotification true
+#  DispatchValues false
 #</Plugin>
 
 #<Plugin ovs_stats>
 #</Plugin>
 
 #<Plugin processes>
+#      CollectFileDescriptor true
+#      CollectContextSwitch true
 #      Process "name"
+#      ProcessMatch "name" "regex"
+#      <Process "collectd">
+#              CollectFileDescriptor false
+#              CollectContextSwitch false
+#      </Process>
+#      <ProcessMatch "name" "regex">
+#              CollectFileDescriptor false
+#              CollectContextSwitch true
+#      </Process>
 #</Plugin>
 
 #<Plugin protocols>
 #              Header "X-Custom-Header: custom_value"
 #              SSLVersion "TLSv1"
 #              Format "Command"
+#              Attribute "key" "value"     # only available for KAIROSDB format
 #              Metrics true
 #              Notifications false
 #              StoreRates false
index da8d793..697763a 100644 (file)
@@ -5637,8 +5637,8 @@ B<Synopsis:>
    Address "127.0.0.1"
    Socket "/var/run/openvswitch/db.sock"
    Interfaces "br0" "veth0"
-   SendNotification false
-   DispatchValues true
+   SendNotification true
+   DispatchValues false
  </Plugin>
 
 The plugin provides the following configuration options:
@@ -5676,12 +5676,12 @@ Default: empty (all interfaces on all bridges are monitored)
 =item B<SendNotification> I<true|false>
 
 If set to true, OVS link notifications (interface status and OVS DB connection
-terminate) are sent to collectd. Default value is false.
+terminate) are sent to collectd. Default value is true.
 
 =item B<DispatchValues> I<true|false>
 
 Dispatch the OVS DB interface link status value with configured plugin interval.
-Defaults to true. Please note, if B<SendNotification> and B<DispatchValues>
+Defaults to false. Please note, if B<SendNotification> and B<DispatchValues>
 options are false, no OVS information will be provided by the plugin.
 
 =back
@@ -6528,9 +6528,15 @@ C<I<prefix>/var/run/collectd-powerdns>.
 =item B<Process> I<Name>
 
 Select more detailed statistics of processes matching this name. The statistics
-collected for these selected processes are size of the resident segment size
-(RSS), user- and system-time used, number of processes and number of threads,
-io data (where available) and minor and major pagefaults.
+collected for these selected processes are:
+ - size of the resident segment size (RSS)
+ - user- and system-time used
+ - number of processes
+ - number of threads
+ - number of open files (under Linux)
+ - io data (where available)
+ - context switches (under Linux)
+ - minor and major pagefaults.
 
 Some platforms have a limit on the length of process names. I<Name> must stay
 below this limit.
@@ -8725,6 +8731,15 @@ create output in the I<JavaScript Object Notation> (JSON). When set to KAIROSDB
 
 Defaults to B<Command>.
 
+=item B<Attribute> I<String> I<String>
+
+Only available for KAIROSDB output format.
+
+Consider the two given strings to be the key and value of an additional tag for
+each metric being sent out.
+
+You can add multiple B<Attribute>.
+
 =item B<Metrics> B<true>|B<false>
 
 Controls whether I<metrics> are POSTed to this location. Defaults to B<true>.
index 6b057f2..cfe993c 100644 (file)
@@ -103,6 +103,8 @@ static void dpdk_stats_default_config(void) {
   for (int i = 0; i < RTE_MAX_ETHPORTS; i++) {
     ec->config.port_name[i][0] = 0;
   }
+  /* Enable all ports by default */
+  ec->config.enabled_port_mask = ~0;
 }
 
 static int dpdk_stats_preinit(void) {
index e2e2e39..fc2a5f1 100644 (file)
@@ -252,14 +252,13 @@ static int cgroup_set(rdt_core_group_t *cg, char *desc, uint64_t *cores,
  *   `item'        Config option containing core groups.
  *   `groups'      Table of core groups to set values in.
  *   `max_groups'  Maximum number of core groups allowed.
- *   `max_core'    Maximum allowed core value.
  *
  * RETURN VALUE
  *   On success, the number of core groups set up. On error, appropriate
  *   negative error value.
  */
 static int oconfig_to_cgroups(oconfig_item_t *item, rdt_core_group_t *groups,
-                              size_t max_groups, uint64_t max_core) {
+                              size_t max_groups) {
   int index = 0;
 
   assert(groups != NULL);
@@ -285,14 +284,6 @@ static int oconfig_to_cgroups(oconfig_item_t *item, rdt_core_group_t *groups,
       return (-EINVAL);
     }
 
-    for (int i = 0; i < n; i++) {
-      if (cores[i] > max_core) {
-        ERROR(RDT_PLUGIN ": Core group (%s) contains invalid core id (%d)",
-              item->values[j].value.string, (int)cores[i]);
-        return (-EINVAL);
-      }
-    }
-
     /* set core group info */
     ret = cgroup_set(&groups[index], item->values[j].value.string, cores, n);
     if (ret < 0)
@@ -395,6 +386,15 @@ static int rdt_default_cgroups(void) {
   return g_rdt->pqos_cpu->num_cores;
 }
 
+static int rdt_is_core_id_valid(int core_id) {
+
+  for (int i = 0; i < g_rdt->pqos_cpu->num_cores; i++)
+    if (core_id == g_rdt->pqos_cpu->cores[i].lcore)
+      return 1;
+
+  return 0;
+}
+
 static int rdt_config_cgroups(oconfig_item_t *item) {
   int n = 0;
   enum pqos_mon_event events = 0;
@@ -413,14 +413,27 @@ static int rdt_config_cgroups(oconfig_item_t *item) {
     DEBUG(RDT_PLUGIN ":  [%d]: %s", j, item->values[j].value.string);
   }
 
-  n = oconfig_to_cgroups(item, g_rdt->cgroups, RDT_MAX_CORES,
-                         g_rdt->pqos_cpu->num_cores - 1);
+  n = oconfig_to_cgroups(item, g_rdt->cgroups, g_rdt->pqos_cpu->num_cores);
   if (n < 0) {
     rdt_free_cgroups();
     ERROR(RDT_PLUGIN ": Error parsing core groups configuration.");
     return (-EINVAL);
   }
 
+  /* validate configured core id values */
+  for (int group_idx = 0; group_idx < n; group_idx++) {
+    for (int core_idx = 0; core_idx < g_rdt->cgroups[group_idx].num_cores;
+         core_idx++) {
+      if (!rdt_is_core_id_valid(g_rdt->cgroups[group_idx].cores[core_idx])) {
+        ERROR(RDT_PLUGIN ": Core group '%s' contains invalid core id '%d'",
+                g_rdt->cgroups[group_idx].desc,
+                (int)g_rdt->cgroups[group_idx].cores[core_idx]);
+        rdt_free_cgroups();
+        return (-EINVAL);
+      }
+    }
+  }
+
   if (n == 0) {
     /* create default core groups if "Cores" config option is empty */
     n = rdt_default_cgroups();
index 8c2cd12..d372b87 100644 (file)
@@ -86,7 +86,8 @@ typedef struct ovs_events_ctx_s ovs_events_ctx_t;
  */
 static ovs_events_ctx_t ovs_events_ctx = {
     .mutex = PTHREAD_MUTEX_INITIALIZER,
-    .config = {.ovs_db_node = "localhost", /* use default OVS DB node */
+    .config = {.send_notification = 1,     /* send notification by default */
+               .ovs_db_node = "localhost", /* use default OVS DB node */
                .ovs_db_serv = "6640"}      /* use default OVS DB service */
 };
 
@@ -227,7 +228,7 @@ static int ovs_events_config_get_interfaces(const oconfig_item_t *ci) {
  * in allocated memory. Returns negative value in case of error.
  */
 static int ovs_events_plugin_config(oconfig_item_t *ci) {
-  _Bool dispatch_values = 1;
+  _Bool dispatch_values = 0;
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
     if (strcasecmp("SendNotification", child->key) == 0) {
index 77dc1f2..23b7533 100644 (file)
@@ -155,7 +155,7 @@ static ovs_stats_config_t ovs_stats_cfg = {
     .ovs_db_serv = "6640",      /* use default OVS DB service */
 };
 
-static const iface_counter ovs_stats_counter_name_to_type(const char *counter) {
+static iface_counter ovs_stats_counter_name_to_type(const char *counter) {
   iface_counter index = not_supported;
 
   if (counter == NULL)
@@ -349,13 +349,15 @@ static int ovs_stats_update_bridge(yajl_val bridge) {
       if (br_ports && YAJL_IS_ARRAY(br_ports)) {
         char *tmp = YAJL_GET_STRING(br_ports->u.array.values[0]);
         if (tmp != NULL && strcmp("set", tmp) == 0) {
-          yajl_val *ports_arr =
-              YAJL_GET_ARRAY(br_ports->u.array.values[1])->values;
-          size_t ports_num = YAJL_GET_ARRAY(br_ports->u.array.values[1])->len;
-
-          for (int i = 0; i < ports_num; i++)
-            ovs_stats_new_port(
-                br, YAJL_GET_STRING(ports_arr[i]->u.array.values[1]));
+          yajl_val *array = YAJL_GET_ARRAY(br_ports)->values;
+          size_t array_len = YAJL_GET_ARRAY(br_ports)->len;
+          if (array != NULL && array_len > 0 && YAJL_IS_ARRAY(array[1])) {
+            yajl_val *ports_arr = YAJL_GET_ARRAY(array[1])->values;
+            size_t ports_num = YAJL_GET_ARRAY(array[1])->len;
+            for (size_t i = 0; i < ports_num && ports_arr != NULL; i++)
+              ovs_stats_new_port(
+                  br, YAJL_GET_STRING(ports_arr[i]->u.array.values[1]));
+          }
         } else
           ovs_stats_new_port(br, YAJL_GET_STRING(br_ports->u.array.values[1]));
       }
@@ -398,7 +400,7 @@ static void ovs_stats_bridge_table_change_cb(yajl_val jupdates) {
   yajl_val bridges = yajl_tree_get(jupdates, path, yajl_t_object);
 
   if (bridges && YAJL_IS_OBJECT(bridges)) {
-    for (int i = 0; i < YAJL_GET_OBJECT(bridges)->len; i++) {
+    for (size_t i = 0; i < YAJL_GET_OBJECT(bridges)->len; i++) {
       yajl_val bridge = YAJL_GET_OBJECT(bridges)->values[i];
       ovs_stats_update_bridge(bridge);
     }
@@ -412,7 +414,7 @@ static void ovs_stats_bridge_table_delete_cb(yajl_val jupdates) {
   yajl_val bridge;
   if (bridges && YAJL_IS_OBJECT(bridges)) {
     pthread_mutex_lock(&g_stats_lock);
-    for (int i = 0; i < YAJL_GET_OBJECT(bridges)->len; i++) {
+    for (size_t i = 0; i < YAJL_GET_OBJECT(bridges)->len; i++) {
       bridge = YAJL_GET_OBJECT(bridges)->values[i];
       ovs_stats_del_bridge(bridge);
     }
@@ -498,7 +500,7 @@ static void ovs_stats_port_table_change_cb(yajl_val jupdates) {
   yajl_val ports = yajl_tree_get(jupdates, path, yajl_t_object);
   yajl_val port;
   if (ports && YAJL_IS_OBJECT(ports)) {
-    for (int i = 0; i < YAJL_GET_OBJECT(ports)->len; i++) {
+    for (size_t i = 0; i < YAJL_GET_OBJECT(ports)->len; i++) {
       port = YAJL_GET_OBJECT(ports)->values[i];
       ovs_stats_update_port(YAJL_GET_OBJECT(ports)->keys[i], port);
     }
@@ -521,7 +523,7 @@ static void ovs_stats_port_table_delete_cb(yajl_val jupdates) {
   yajl_val ports = yajl_tree_get(jupdates, path, yajl_t_object);
   pthread_mutex_lock(&g_stats_lock);
   if (ports && YAJL_IS_OBJECT(ports))
-    for (int i = 0; i < YAJL_GET_OBJECT(ports)->len; i++) {
+    for (size_t i = 0; i < YAJL_GET_OBJECT(ports)->len; i++) {
       ovs_stats_del_port(YAJL_GET_OBJECT(ports)->keys[i]);
     }
   pthread_mutex_unlock(&g_stats_lock);
@@ -535,8 +537,10 @@ static int ovs_stats_update_iface_stats(port_list_t *port, yajl_val stats) {
   char *counter_name = NULL;
   int64_t counter_value = 0;
   if (stats && YAJL_IS_ARRAY(stats))
-    for (int i = 0; i < YAJL_GET_ARRAY(stats)->len; i++) {
+    for (size_t i = 0; i < YAJL_GET_ARRAY(stats)->len; i++) {
       stat = YAJL_GET_ARRAY(stats)->values[i];
+      if (!YAJL_IS_ARRAY(stat))
+        return (-1);
       counter_name = YAJL_GET_STRING(YAJL_GET_ARRAY(stat)->values[0]);
       counter_index = ovs_stats_counter_name_to_type(counter_name);
       counter_value = YAJL_GET_INTEGER(YAJL_GET_ARRAY(stat)->values[1]);
@@ -555,8 +559,10 @@ static int ovs_stats_update_iface_ext_ids(port_list_t *port, yajl_val ext_ids) {
   char *value;
 
   if (ext_ids && YAJL_IS_ARRAY(ext_ids))
-    for (int i = 0; i < YAJL_GET_ARRAY(ext_ids)->len; i++) {
+    for (size_t i = 0; i < YAJL_GET_ARRAY(ext_ids)->len; i++) {
       ext_id = YAJL_GET_ARRAY(ext_ids)->values[i];
+      if (!YAJL_IS_ARRAY(ext_id))
+        return (-1);
       key = YAJL_GET_STRING(YAJL_GET_ARRAY(ext_id)->values[0]);
       value = YAJL_GET_STRING(YAJL_GET_ARRAY(ext_id)->values[1]);
       if (key && value) {
@@ -681,7 +687,7 @@ static void ovs_stats_interface_table_change_cb(yajl_val jupdates) {
   yajl_val ports = yajl_tree_get(jupdates, path, yajl_t_object);
   pthread_mutex_lock(&g_stats_lock);
   if (ports && YAJL_IS_OBJECT(ports))
-    for (int i = 0; i < YAJL_GET_OBJECT(ports)->len; i++)
+    for (size_t i = 0; i < YAJL_GET_OBJECT(ports)->len; i++)
       ovs_stats_update_iface(YAJL_GET_OBJECT(ports)->values[i]);
   pthread_mutex_unlock(&g_stats_lock);
   return;
@@ -875,7 +881,7 @@ static int ovs_stats_plugin_init(void) {
 static int ovs_stats_plugin_read(__attribute__((unused)) user_data_t *ud) {
   bridge_list_t *bridge;
   port_list_t *port;
-  char devname[PORT_NAME_SIZE_MAX];
+  char devname[PORT_NAME_SIZE_MAX * 2];
 
   pthread_mutex_lock(&g_stats_lock);
   for (bridge = g_bridge_list_head; bridge != NULL; bridge = bridge->next) {
index 4f61351..6e472e6 100644 (file)
@@ -32,6 +32,7 @@
  *   Manuel Sanmartin
  *   Clément Stenac <clement.stenac at diwi.org>
  *   Cosmin Ioiart <cioiart at gmail.com>
+ *   Pavel Rochnyack <pavel2000 at ngs.ru>
  **/
 
 #include "collectd.h"
 #endif
 #endif
 
-typedef struct procstat_entry_s {
+#define PROCSTAT_NAME_LEN 256
+typedef struct process_entry_s {
   unsigned long id;
-  unsigned long age;
+  char name[PROCSTAT_NAME_LEN];
 
   unsigned long num_proc;
   unsigned long num_lwp;
+  unsigned long num_fd;
   unsigned long vmem_size;
   unsigned long vmem_rss;
   unsigned long vmem_data;
@@ -188,10 +191,31 @@ typedef struct procstat_entry_s {
   derive_t cswitch_invol;
   _Bool has_cswitch;
 
+  _Bool has_fd;
+} process_entry_t;
+
+typedef struct procstat_entry_s {
+  unsigned long id;
+  unsigned long age;
+
+  derive_t vmem_minflt_counter;
+  derive_t vmem_majflt_counter;
+
+  derive_t cpu_user_counter;
+  derive_t cpu_system_counter;
+
+  /* io data */
+  derive_t io_rchar;
+  derive_t io_wchar;
+  derive_t io_syscr;
+  derive_t io_syscw;
+
+  derive_t cswitch_vol;
+  derive_t cswitch_invol;
+
   struct procstat_entry_s *next;
 } procstat_entry_t;
 
-#define PROCSTAT_NAME_LEN 256
 typedef struct procstat {
   char name[PROCSTAT_NAME_LEN];
 #if HAVE_REGEX_H
@@ -200,6 +224,7 @@ typedef struct procstat {
 
   unsigned long num_proc;
   unsigned long num_lwp;
+  unsigned long num_fd;
   unsigned long vmem_size;
   unsigned long vmem_rss;
   unsigned long vmem_data;
@@ -221,6 +246,9 @@ typedef struct procstat {
   derive_t cswitch_vol;
   derive_t cswitch_invol;
 
+  _Bool report_fd_num;
+  _Bool report_ctx_switch;
+
   struct procstat *next;
   struct procstat_entry_s *instances;
 } procstat_t;
@@ -229,6 +257,7 @@ static procstat_t *list_head_g = NULL;
 
 static _Bool want_init = 1;
 static _Bool report_ctx_switch = 0;
+static _Bool report_fd_num = 0;
 
 #if HAVE_THREAD_INFO
 static mach_port_t port_host_self;
@@ -240,7 +269,7 @@ static mach_msg_type_number_t pset_list_len;
 
 #elif KERNEL_LINUX
 static long pagesize_g;
-static void ps_fill_details(const procstat_t *ps, procstat_entry_t *entry);
+static void ps_fill_details(const procstat_t *ps, process_entry_t *entry);
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKVM_GETPROCS &&                                                  \
@@ -265,7 +294,7 @@ int getargs(void *processBuffer, int bufferLen, char *argsBuffer, int argsLen);
 /* put name of process from config to list_head_g tree
  * list_head_g is a list of 'procstat_t' structs with
  * processes names we want to watch */
-static void ps_list_register(const char *name, const char *regexp) {
+static procstat_t *ps_list_register(const char *name, const char *regexp) {
   procstat_t *new;
   procstat_t *ptr;
   int status;
@@ -273,10 +302,20 @@ static void ps_list_register(const char *name, const char *regexp) {
   new = calloc(1, sizeof(*new));
   if (new == NULL) {
     ERROR("processes plugin: ps_list_register: calloc failed.");
-    return;
+    return (NULL);
   }
   sstrncpy(new->name, name, sizeof(new->name));
 
+  new->io_rchar = -1;
+  new->io_wchar = -1;
+  new->io_syscr = -1;
+  new->io_syscw = -1;
+  new->cswitch_vol = -1;
+  new->cswitch_invol = -1;
+
+  new->report_fd_num = report_fd_num;
+  new->report_ctx_switch = report_ctx_switch;
+
 #if HAVE_REGEX_H
   if (regexp != NULL) {
     DEBUG("ProcessMatch: adding \"%s\" as criteria to process %s.", regexp,
@@ -285,7 +324,7 @@ static void ps_list_register(const char *name, const char *regexp) {
     if (new->re == NULL) {
       ERROR("processes plugin: ps_list_register: malloc failed.");
       sfree(new);
-      return;
+      return (NULL);
     }
 
     status = regcomp(new->re, regexp, REG_EXTENDED | REG_NOSUB);
@@ -294,7 +333,7 @@ static void ps_list_register(const char *name, const char *regexp) {
             regexp);
       sfree(new->re);
       sfree(new);
-      return;
+      return (NULL);
     }
   }
 #else
@@ -305,7 +344,7 @@ static void ps_list_register(const char *name, const char *regexp) {
           "has been disabled at compile time.",
           regexp);
     sfree(new);
-    return;
+    return (NULL);
   }
 #endif
 
@@ -320,7 +359,7 @@ static void ps_list_register(const char *name, const char *regexp) {
       sfree(new->re);
 #endif
       sfree(new);
-      return;
+      return (NULL);
     }
 
     if (ptr->next == NULL)
@@ -331,6 +370,8 @@ static void ps_list_register(const char *name, const char *regexp) {
     list_head_g = new;
   else
     ptr->next = new;
+
+  return (new);
 } /* void ps_list_register */
 
 /* try to match name against entry, returns 1 if success */
@@ -375,13 +416,16 @@ static void ps_update_counter(derive_t *group_counter, derive_t *curr_counter,
   else
     curr_value = new_counter - *curr_counter;
 
+  if (*group_counter == -1)
+    *group_counter = 0;
+
   *curr_counter = new_counter;
   *group_counter += curr_value;
 }
 
 /* add process entry to 'instances' of process 'name' (or refresh it) */
 static void ps_list_add(const char *name, const char *cmdline,
-                        procstat_entry_t *entry) {
+                        process_entry_t *entry) {
   procstat_entry_t *pse;
 
   if (entry->id == 0)
@@ -416,35 +460,32 @@ static void ps_list_add(const char *name, const char *cmdline,
     }
 
     pse->age = 0;
-    pse->num_proc = entry->num_proc;
-    pse->num_lwp = entry->num_lwp;
-    pse->vmem_size = entry->vmem_size;
-    pse->vmem_rss = entry->vmem_rss;
-    pse->vmem_data = entry->vmem_data;
-    pse->vmem_code = entry->vmem_code;
-    pse->stack_size = entry->stack_size;
-    pse->io_rchar = entry->io_rchar;
-    pse->io_wchar = entry->io_wchar;
-    pse->io_syscr = entry->io_syscr;
-    pse->io_syscw = entry->io_syscw;
-    pse->cswitch_vol = entry->cswitch_vol;
-    pse->cswitch_invol = entry->cswitch_invol;
-
-    ps->num_proc += pse->num_proc;
-    ps->num_lwp += pse->num_lwp;
-    ps->vmem_size += pse->vmem_size;
-    ps->vmem_rss += pse->vmem_rss;
-    ps->vmem_data += pse->vmem_data;
-    ps->vmem_code += pse->vmem_code;
-    ps->stack_size += pse->stack_size;
-
-    ps->io_rchar += ((pse->io_rchar == -1) ? 0 : pse->io_rchar);
-    ps->io_wchar += ((pse->io_wchar == -1) ? 0 : pse->io_wchar);
-    ps->io_syscr += ((pse->io_syscr == -1) ? 0 : pse->io_syscr);
-    ps->io_syscw += ((pse->io_syscw == -1) ? 0 : pse->io_syscw);
-
-    ps->cswitch_vol += ((pse->cswitch_vol == -1) ? 0 : pse->cswitch_vol);
-    ps->cswitch_invol += ((pse->cswitch_invol == -1) ? 0 : pse->cswitch_invol);
+
+    ps->num_proc += entry->num_proc;
+    ps->num_lwp += entry->num_lwp;
+    ps->num_fd += entry->num_fd;
+    ps->vmem_size += entry->vmem_size;
+    ps->vmem_rss += entry->vmem_rss;
+    ps->vmem_data += entry->vmem_data;
+    ps->vmem_code += entry->vmem_code;
+    ps->stack_size += entry->stack_size;
+
+    if ((entry->io_rchar != -1) && (entry->io_wchar != -1)) {
+      ps_update_counter(&ps->io_rchar, &pse->io_rchar, entry->io_rchar);
+      ps_update_counter(&ps->io_wchar, &pse->io_wchar, entry->io_wchar);
+    }
+
+    if ((entry->io_syscr != -1) && (entry->io_syscw != -1)) {
+      ps_update_counter(&ps->io_syscr, &pse->io_syscr, entry->io_syscr);
+      ps_update_counter(&ps->io_syscw, &pse->io_syscw, entry->io_syscw);
+    }
+
+    if ((entry->cswitch_vol != -1) && (entry->cswitch_vol != -1)) {
+      ps_update_counter(&ps->cswitch_vol, &pse->cswitch_vol,
+                        entry->cswitch_vol);
+      ps_update_counter(&ps->cswitch_invol, &pse->cswitch_invol,
+                        entry->cswitch_invol);
+    }
 
     ps_update_counter(&ps->vmem_minflt_counter, &pse->vmem_minflt_counter,
                       entry->vmem_minflt_counter);
@@ -466,17 +507,12 @@ static void ps_list_reset(void) {
   for (procstat_t *ps = list_head_g; ps != NULL; ps = ps->next) {
     ps->num_proc = 0;
     ps->num_lwp = 0;
+    ps->num_fd = 0;
     ps->vmem_size = 0;
     ps->vmem_rss = 0;
     ps->vmem_data = 0;
     ps->vmem_code = 0;
     ps->stack_size = 0;
-    ps->io_rchar = -1;
-    ps->io_wchar = -1;
-    ps->io_syscr = -1;
-    ps->io_syscw = -1;
-    ps->cswitch_vol = -1;
-    ps->cswitch_invol = -1;
 
     pse_prev = NULL;
     pse = ps->instances;
@@ -504,6 +540,20 @@ static void ps_list_reset(void) {
   }   /* for (ps = list_head_g; ps != NULL; ps = ps->next) */
 }
 
+static void ps_tune_instance(oconfig_item_t *ci, procstat_t *ps) {
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *c = ci->children + i;
+
+    if (strcasecmp(c->key, "CollectContextSwitch") == 0)
+      cf_util_get_boolean(c, &ps->report_ctx_switch);
+    else if (strcasecmp(c->key, "CollectFileDescriptor") == 0)
+      cf_util_get_boolean(c, &ps->report_fd_num);
+    else {
+      ERROR("processes plugin: Option `%s' not allowed here.", c->key);
+    }
+  } /* for (ci->children) */
+} /* void ps_tune_instance */
+
 /* put all pre-defined 'Process' names from config to list_head_g tree */
 static int ps_config(oconfig_item_t *ci) {
 #if KERNEL_LINUX
@@ -512,6 +562,8 @@ static int ps_config(oconfig_item_t *ci) {
   const size_t max_procname_len = MAXCOMLEN - 1;
 #endif
 
+  procstat_t *ps;
+
   for (int i = 0; i < ci->children_num; ++i) {
     oconfig_item_t *c = ci->children + i;
 
@@ -523,13 +575,6 @@ static int ps_config(oconfig_item_t *ci) {
         continue;
       }
 
-      if (c->children_num != 0) {
-        WARNING("processes plugin: the `Process' config option "
-                "does not expect any child elements -- ignoring "
-                "content (%i elements) of the <Process '%s'> block.",
-                c->children_num, c->values[0].value.string);
-      }
-
 #if KERNEL_LINUX || KERNEL_SOLARIS || KERNEL_FREEBSD
       if (strlen(c->values[0].value.string) > max_procname_len) {
         WARNING("processes plugin: this platform has a %zu character limit "
@@ -539,7 +584,10 @@ static int ps_config(oconfig_item_t *ci) {
       }
 #endif
 
-      ps_list_register(c->values[0].value.string, NULL);
+      ps = ps_list_register(c->values[0].value.string, NULL);
+
+      if (c->children_num != 0 && ps != NULL)
+        ps_tune_instance(c, ps);
     } else if (strcasecmp(c->key, "ProcessMatch") == 0) {
       if ((c->values_num != 2) || (OCONFIG_TYPE_STRING != c->values[0].type) ||
           (OCONFIG_TYPE_STRING != c->values[1].type)) {
@@ -549,18 +597,15 @@ static int ps_config(oconfig_item_t *ci) {
         continue;
       }
 
-      if (c->children_num != 0) {
-        WARNING("processes plugin: the `ProcessMatch' config option "
-                "does not expect any child elements -- ignoring "
-                "content (%i elements) of the <ProcessMatch '%s' '%s'> "
-                "block.",
-                c->children_num, c->values[0].value.string,
-                c->values[1].value.string);
-      }
+      ps = ps_list_register(c->values[0].value.string,
+                            c->values[1].value.string);
 
-      ps_list_register(c->values[0].value.string, c->values[1].value.string);
+      if (c->children_num != 0 && ps != NULL)
+        ps_tune_instance(c, ps);
     } else if (strcasecmp(c->key, "CollectContextSwitch") == 0) {
       cf_util_get_boolean(c, &report_ctx_switch);
+    } else if (strcasecmp(c->key, "CollectFileDescriptor") == 0) {
+      cf_util_get_boolean(c, &report_fd_num);
     } else {
       ERROR("processes plugin: The `%s' configuration option is not "
             "understood and will be ignored.",
@@ -695,7 +740,14 @@ static void ps_submit_proc_list(procstat_t *ps) {
     plugin_dispatch_values(&vl);
   }
 
-  if (report_ctx_switch) {
+  if (ps->num_fd > 0) {
+    sstrncpy(vl.type, "file_handles", sizeof(vl.type));
+    vl.values[0].gauge = ps->num_fd;
+    vl.values_len = 1;
+    plugin_dispatch_values(&vl);
+  }
+
+  if ((ps->cswitch_vol != -1) && (ps->cswitch_invol != -1)) {
     sstrncpy(vl.type, "contextswitch", sizeof(vl.type));
     sstrncpy(vl.type_instance, "voluntary", sizeof(vl.type_instance));
     vl.values[0].derive = ps->cswitch_vol;
@@ -709,7 +761,7 @@ static void ps_submit_proc_list(procstat_t *ps) {
     plugin_dispatch_values(&vl);
   }
 
-  DEBUG("name = %s; num_proc = %lu; num_lwp = %lu; "
+  DEBUG("name = %s; num_proc = %lu; num_lwp = %lu; num_fd = %lu; "
         "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
         "vmem_code = %lu; "
         "vmem_minflt_counter = %" PRIi64 "; vmem_majflt_counter = %" PRIi64 "; "
@@ -717,8 +769,8 @@ static void ps_submit_proc_list(procstat_t *ps) {
         "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; "
         "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; "
         "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 ";",
-        ps->name, ps->num_proc, ps->num_lwp, ps->vmem_size, ps->vmem_rss,
-        ps->vmem_data, ps->vmem_code, ps->vmem_minflt_counter,
+        ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->vmem_size,
+        ps->vmem_rss, ps->vmem_data, ps->vmem_code, ps->vmem_minflt_counter,
         ps->vmem_majflt_counter, ps->cpu_user_counter, ps->cpu_system_counter,
         ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->cswitch_vol,
         ps->cswitch_invol);
@@ -741,7 +793,7 @@ static void ps_submit_fork_rate(derive_t value) {
 
 /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
-static int ps_read_tasks_status(procstat_entry_t *ps) {
+static int ps_read_tasks_status(process_entry_t *ps) {
   char dirname[64];
   DIR *dh;
   char filename[64];
@@ -815,7 +867,7 @@ static int ps_read_tasks_status(procstat_entry_t *ps) {
 } /* int *ps_read_tasks_status */
 
 /* Read data from /proc/pid/status */
-static procstat_t *ps_read_status(long pid, procstat_t *ps) {
+static int ps_read_status(long pid, process_entry_t *ps) {
   FILE *fh;
   char buffer[1024];
   char filename[64];
@@ -828,7 +880,7 @@ static procstat_t *ps_read_status(long pid, procstat_t *ps) {
 
   ssnprintf(filename, sizeof(filename), "/proc/%li/status", pid);
   if ((fh = fopen(filename, "r")) == NULL)
-    return (NULL);
+    return (-1);
 
   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
     unsigned long tmp;
@@ -868,10 +920,10 @@ static procstat_t *ps_read_status(long pid, procstat_t *ps) {
   if (threads != 0)
     ps->num_lwp = threads;
 
-  return (ps);
-} /* procstat_t *ps_read_vmem */
+  return (0);
+} /* int *ps_read_status */
 
-static int ps_read_io(procstat_entry_t *ps) {
+static int ps_read_io(process_entry_t *ps) {
   FILE *fh;
   char buffer[1024];
   char filename[64];
@@ -880,8 +932,10 @@ static int ps_read_io(procstat_entry_t *ps) {
   int numfields;
 
   ssnprintf(filename, sizeof(filename), "/proc/%li/io", ps->id);
-  if ((fh = fopen(filename, "r")) == NULL)
+  if ((fh = fopen(filename, "r")) == NULL) {
+    DEBUG("ps_read_io: Failed to open file `%s'", filename);
     return (-1);
+  }
 
   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
     derive_t *val = NULL;
@@ -920,32 +974,52 @@ static int ps_read_io(procstat_entry_t *ps) {
   return (0);
 } /* int ps_read_io (...) */
 
-static void ps_fill_details(const procstat_t *ps, procstat_entry_t *entry) {
-  if (entry->has_io == 0 && ps_read_io(entry) != 0) {
-    /* no io data */
-    entry->io_rchar = -1;
-    entry->io_wchar = -1;
-    entry->io_syscr = -1;
-    entry->io_syscw = -1;
+static int ps_count_fd(int pid) {
+  char dirname[64];
+  DIR *dh;
+  struct dirent *ent;
+  int count = 0;
+
+  ssnprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid);
 
-    DEBUG("ps_read_process: not get io data for pid %li", entry->id);
+  if ((dh = opendir(dirname)) == NULL) {
+    DEBUG("Failed to open directory `%s'", dirname);
+    return (-1);
   }
-  entry->has_io = 1;
+  while ((ent = readdir(dh)) != NULL) {
+    if (!isdigit((int)ent->d_name[0]))
+      continue;
+    else
+      count++;
+  }
+  closedir(dh);
 
-  if (report_ctx_switch) {
-    if (entry->has_cswitch == 0 && ps_read_tasks_status(entry) != 0) {
-      entry->cswitch_vol = -1;
-      entry->cswitch_invol = -1;
+  return ((count >= 1) ? count : 1);
+} /* int ps_count_fd (pid) */
 
-      DEBUG("ps_read_tasks_status: not get context "
-            "switch data for pid %li",
-            entry->id);
+static void ps_fill_details(const procstat_t *ps, process_entry_t *entry) {
+  if (entry->has_io == 0) {
+    ps_read_io(entry);
+    entry->has_io = 1;
+  }
+
+  if (ps->report_ctx_switch) {
+    if (entry->has_cswitch == 0) {
+      ps_read_tasks_status(entry);
+      entry->has_cswitch = 1;
+    }
+  }
+
+  if (ps->report_fd_num) {
+    int num_fd;
+    if (entry->has_fd == 0 && (num_fd = ps_count_fd(entry->id)) > 0) {
+      entry->num_fd = num_fd;
     }
-    entry->has_cswitch = 1;
+    entry->has_fd = 1;
   }
 } /* void ps_fill_details (...) */
 
-static int ps_read_process(long pid, procstat_t *ps, char *state) {
+static int ps_read_process(long pid, process_entry_t *ps, char *state) {
   char filename[64];
   char buffer[1024];
 
@@ -967,8 +1041,6 @@ static int ps_read_process(long pid, procstat_t *ps, char *state) {
 
   ssize_t status;
 
-  memset(ps, 0, sizeof(procstat_t));
-
   ssnprintf(filename, sizeof(filename), "/proc/%li/stat", pid);
 
   status = read_file_contents(filename, buffer, sizeof(buffer) - 1);
@@ -1023,7 +1095,7 @@ static int ps_read_process(long pid, procstat_t *ps, char *state) {
     ps->num_proc = 0;
   } else {
     ps->num_lwp = strtoul(fields[17], /* endptr = */ NULL, /* base = */ 10);
-    if ((ps_read_status(pid, ps)) == NULL) {
+    if ((ps_read_status(pid, ps)) != 0) {
       /* No VMem data */
       ps->vmem_data = -1;
       ps->vmem_code = -1;
@@ -1068,6 +1140,15 @@ static int ps_read_process(long pid, procstat_t *ps, char *state) {
   ps->vmem_rss = (unsigned long)vmem_rss;
   ps->stack_size = (unsigned long)stack_size;
 
+  /* no data by default. May be filled by ps_fill_details () */
+  ps->io_rchar = -1;
+  ps->io_wchar = -1;
+  ps->io_syscr = -1;
+  ps->io_syscw = -1;
+
+  ps->cswitch_vol = -1;
+  ps->cswitch_invol = -1;
+
   /* success */
   return (0);
 } /* int ps_read_process (...) */
@@ -1239,7 +1320,7 @@ static char *ps_get_cmdline(long pid,
  * The values for input and ouput chars are calculated "by hand"
  * Added a few "solaris" specific process states as well
  */
-static int ps_read_process(long pid, procstat_t *ps, char *state) {
+static int ps_read_process(long pid, process_entry_t *ps, char *state) {
   char filename[64];
   char f_psinfo[64], f_usage[64];
   char *buffer;
@@ -1304,6 +1385,11 @@ static int ps_read_process(long pid, procstat_t *ps, char *state) {
   ps->stack_size = myStatus->pr_stksize;
 
   /*
+   * TODO: File descriptor count for Solaris
+   */
+  ps->num_fd = 0;
+
+  /*
    * Calculating input/ouput chars
    * Formula used is total chars / total blocks => chars/block
    * then convert input/output blocks to chars
@@ -1444,7 +1530,7 @@ static int ps_read(void) {
   int blocked = 0;
 
   procstat_t *ps;
-  procstat_entry_t pse;
+  process_entry_t pse;
 
   ps_list_reset();
 
@@ -1526,6 +1612,14 @@ static int ps_read(void) {
         pse.vmem_data = 0;
         pse.vmem_code = 0;
 
+        pse.io_rchar = -1;
+        pse.io_wchar = -1;
+        pse.io_syscr = -1;
+        pse.io_syscw = -1;
+
+        /* File descriptor count not implemented */
+        pse.num_fd = 0;
+
         pse.vmem_minflt_counter = task_events_info.cow_faults;
         pse.vmem_majflt_counter = task_events_info.faults;
 
@@ -1657,8 +1751,7 @@ static int ps_read(void) {
   char cmdline[CMDLINE_BUFFER_SIZE];
 
   int status;
-  procstat_t ps;
-  procstat_entry_t pse;
+  process_entry_t pse;
   char state;
 
   running = sleeping = zombies = stopped = paging = blocked = 0;
@@ -1677,38 +1770,15 @@ static int ps_read(void) {
     if ((pid = atol(ent->d_name)) < 1)
       continue;
 
-    status = ps_read_process(pid, &ps, &state);
+    memset(&pse, 0, sizeof(pse));
+    pse.id = pid;
+
+    status = ps_read_process(pid, &pse, &state);
     if (status != 0) {
       DEBUG("ps_read_process failed: %i", status);
       continue;
     }
 
-    memset(&pse, 0, sizeof(pse));
-    pse.id = pid;
-    pse.age = 0;
-
-    pse.num_proc = ps.num_proc;
-    pse.num_lwp = ps.num_lwp;
-    pse.vmem_size = ps.vmem_size;
-    pse.vmem_rss = ps.vmem_rss;
-    pse.vmem_data = ps.vmem_data;
-    pse.vmem_code = ps.vmem_code;
-    pse.stack_size = ps.stack_size;
-
-    pse.vmem_minflt_counter = ps.vmem_minflt_counter;
-    pse.vmem_majflt_counter = ps.vmem_majflt_counter;
-
-    pse.cpu_user_counter = ps.cpu_user_counter;
-    pse.cpu_system_counter = ps.cpu_system_counter;
-
-    pse.io_rchar = ps.io_rchar;
-    pse.io_wchar = ps.io_wchar;
-    pse.io_syscr = ps.io_syscr;
-    pse.io_syscw = ps.io_syscw;
-
-    pse.cswitch_vol = ps.cswitch_vol;
-    pse.cswitch_invol = ps.cswitch_invol;
-
     switch (state) {
     case 'R':
       running++;
@@ -1730,8 +1800,8 @@ static int ps_read(void) {
       break;
     }
 
-    ps_list_add(ps.name, ps_get_cmdline(pid, ps.name, cmdline, sizeof(cmdline)),
-                &pse);
+    ps_list_add(pse.name,
+                ps_get_cmdline(pid, pse.name, cmdline, sizeof(cmdline)), &pse);
   }
 
   closedir(proc);
@@ -1764,7 +1834,7 @@ static int ps_read(void) {
   struct kinfo_proc *proc_ptr = NULL;
   int count; /* returns number of processes */
 
-  procstat_entry_t pse;
+  process_entry_t pse;
 
   ps_list_reset();
 
@@ -1814,8 +1884,8 @@ static int ps_read(void) {
         }
       } /* if (process has argument list) */
 
+      memset(&pse, 0, sizeof(pse));
       pse.id = procs[i].ki_pid;
-      pse.age = 0;
 
       pse.num_proc = 1;
       pse.num_lwp = procs[i].ki_numthreads;
@@ -1850,6 +1920,9 @@ static int ps_read(void) {
       pse.io_syscr = -1;
       pse.io_syscw = -1;
 
+      /* file descriptor count not implemented */
+      pse.num_fd = 0;
+
       /* context switch counters not implemented */
       pse.cswitch_vol = -1;
       pse.cswitch_invol = -1;
@@ -1911,7 +1984,7 @@ static int ps_read(void) {
   struct kinfo_proc *proc_ptr = NULL;
   int count; /* returns number of processes */
 
-  procstat_entry_t pse;
+  process_entry_t pse;
 
   ps_list_reset();
 
@@ -1963,7 +2036,6 @@ static int ps_read(void) {
 
       memset(&pse, 0, sizeof(pse));
       pse.id = procs[i].p_pid;
-      pse.age = 0;
 
       pse.num_proc = 1;
       pse.num_lwp = 1; /* XXX: accumulate p_tid values for a single p_pid ? */
@@ -1987,6 +2059,9 @@ static int ps_read(void) {
       pse.io_syscr = -1;
       pse.io_syscw = -1;
 
+      /* file descriptor count not implemented */
+      pse.num_fd = 0;
+
       /* context switch counters not implemented */
       pse.cswitch_vol = -1;
       pse.cswitch_invol = -1;
@@ -2045,7 +2120,7 @@ static int ps_read(void) {
   pid_t pindex = 0;
   int nprocs;
 
-  procstat_entry_t pse;
+  process_entry_t pse;
 
   ps_list_reset();
   while ((nprocs = getprocs64(procentry, sizeof(struct procentry64),
@@ -2085,8 +2160,9 @@ static int ps_read(void) {
         }
       }
 
+      memset(&pse, 0, sizeof(pse));
+
       pse.id = procentry[i].pi_pid;
-      pse.age = 0;
       pse.num_lwp = procentry[i].pi_thcount;
       pse.num_proc = 1;
 
@@ -2127,7 +2203,6 @@ static int ps_read(void) {
       pse.cpu_user_counter = procentry[i].pi_ru.ru_utime.tv_sec * 1000000 +
                              procentry[i].pi_ru.ru_utime.tv_usec / 1000;
 
-      pse.cpu_system = 0;
       /* tv_usec is nanosec ??? */
       pse.cpu_system_counter = procentry[i].pi_ru.ru_stime.tv_sec * 1000000 +
                                procentry[i].pi_ru.ru_stime.tv_usec / 1000;
@@ -2137,7 +2212,7 @@ static int ps_read(void) {
 
       pse.vmem_size = procentry[i].pi_tsize + procentry[i].pi_dvm * pagesize;
       pse.vmem_rss = (procentry[i].pi_drss + procentry[i].pi_trss) * pagesize;
-      /* Not supported */
+      /* Not supported/implemented */
       pse.vmem_data = 0;
       pse.vmem_code = 0;
       pse.stack_size = 0;
@@ -2147,6 +2222,8 @@ static int ps_read(void) {
       pse.io_syscr = -1;
       pse.io_syscw = -1;
 
+      pse.num_fd = 0;
+
       pse.cswitch_vol = -1;
       pse.cswitch_invol = -1;
 
@@ -2199,8 +2276,7 @@ static int ps_read(void) {
 
   while ((ent = readdir(proc)) != NULL) {
     long pid;
-    struct procstat ps;
-    procstat_entry_t pse;
+    process_entry_t pse;
     char *endptr;
 
     if (!isdigit((int)ent->d_name[0]))
@@ -2210,38 +2286,15 @@ static int ps_read(void) {
     if (*endptr != 0) /* value didn't completely parse as a number */
       continue;
 
-    status = ps_read_process(pid, &ps, &state);
+    memset(&pse, 0, sizeof(pse));
+    pse.id = pid;
+
+    status = ps_read_process(pid, &pse, &state);
     if (status != 0) {
       DEBUG("ps_read_process failed: %i", status);
       continue;
     }
 
-    memset(&pse, 0, sizeof(pse));
-    pse.id = pid;
-    pse.age = 0;
-
-    pse.num_proc = ps.num_proc;
-    pse.num_lwp = ps.num_lwp;
-    pse.vmem_size = ps.vmem_size;
-    pse.vmem_rss = ps.vmem_rss;
-    pse.vmem_data = ps.vmem_data;
-    pse.vmem_code = ps.vmem_code;
-    pse.stack_size = ps.stack_size;
-
-    pse.vmem_minflt_counter = ps.vmem_minflt_counter;
-    pse.vmem_majflt_counter = ps.vmem_majflt_counter;
-
-    pse.cpu_user_counter = ps.cpu_user_counter;
-    pse.cpu_system_counter = ps.cpu_system_counter;
-
-    pse.io_rchar = ps.io_rchar;
-    pse.io_wchar = ps.io_wchar;
-    pse.io_syscr = ps.io_syscr;
-    pse.io_syscw = ps.io_syscw;
-
-    pse.cswitch_vol = -1;
-    pse.cswitch_invol = -1;
-
     switch (state) {
     case 'R':
       running++;
@@ -2269,8 +2322,8 @@ static int ps_read(void) {
       break;
     }
 
-    ps_list_add(ps.name, ps_get_cmdline(pid, ps.name, cmdline, sizeof(cmdline)),
-                &pse);
+    ps_list_add(pse.name,
+                ps_get_cmdline(pid, pse.name, cmdline, sizeof(cmdline)), &pse);
   } /* while(readdir) */
   closedir(proc);
 
index 9e8950b..25a5512 100644 (file)
@@ -136,23 +136,21 @@ cmd_status_t cmd_handle_flush(FILE *fh, char *buffer) {
 
     for (size_t j = 0; (j == 0) || (j < cmd.cmd.flush.identifiers_num); j++) {
       char *identifier = NULL;
-      char buffer[1024];
-      int status;
+      char buf[1024];
 
       if (cmd.cmd.flush.identifiers_num != 0) {
         identifier_t *id = cmd.cmd.flush.identifiers + j;
-        if (format_name(buffer, sizeof(buffer), id->host, id->plugin,
+        if (format_name(buf, sizeof(buf), id->host, id->plugin,
                         id->plugin_instance, id->type,
                         id->type_instance) != 0) {
           error++;
           continue;
         }
-        identifier = buffer;
+        identifier = buf;
       }
 
-      status = plugin_flush(plugin, DOUBLE_TO_CDTIME_T(cmd.cmd.flush.timeout),
-                            identifier);
-      if (status == 0)
+      if (plugin_flush(plugin, DOUBLE_TO_CDTIME_T(cmd.cmd.flush.timeout),
+                       identifier) == 0)
         success++;
       else
         error++;
index 1e54b97..2a14f0e 100644 (file)
@@ -181,7 +181,9 @@ static int values_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */
 
 static int value_list_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */
                                   const data_set_t *ds, const value_list_t *vl,
-                                  int store_rates) {
+                                  int store_rates,
+                                  char const *const *http_attrs,
+                                  size_t http_attrs_num) {
   char temp[512];
   size_t offset = 0;
   int status;
@@ -231,6 +233,11 @@ static int value_list_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */
     BUFFER_ADD(", \"tags\":\{");
 
     BUFFER_ADD("\"host\": \"%s\"", vl->host);
+    for (size_t j = 0; j < http_attrs_num; j += 2) {
+      BUFFER_ADD(", \"%s\":", http_attrs[j]);
+      BUFFER_ADD(" \"%s\"", http_attrs[j + 1]);
+    }
+
     if (strlen(vl->plugin_instance))
       BUFFER_ADD_KEYVAL("plugin_instance", vl->plugin_instance);
     BUFFER_ADD_KEYVAL("type", vl->type);
@@ -252,11 +259,13 @@ static int value_list_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */
 static int format_kairosdb_value_list_nocheck(
     char *buffer, /* {{{ */
     size_t *ret_buffer_fill, size_t *ret_buffer_free, const data_set_t *ds,
-    const value_list_t *vl, int store_rates, size_t temp_size) {
+    const value_list_t *vl, int store_rates, size_t temp_size,
+    char const *const *http_attrs, size_t http_attrs_num) {
   char temp[temp_size];
   int status;
 
-  status = value_list_to_kairosdb(temp, sizeof(temp), ds, vl, store_rates);
+  status = value_list_to_kairosdb(temp, sizeof(temp), ds, vl, store_rates,
+                                  http_attrs, http_attrs_num);
   if (status != 0)
     return (status);
   temp_size = strlen(temp);
@@ -324,7 +333,8 @@ int format_kairosdb_finalize(char *buffer, /* {{{ */
 int format_kairosdb_value_list(char *buffer, /* {{{ */
                                size_t *ret_buffer_fill, size_t *ret_buffer_free,
                                const data_set_t *ds, const value_list_t *vl,
-                               int store_rates) {
+                               int store_rates, char const *const *http_attrs,
+                               size_t http_attrs_num) {
   if ((buffer == NULL) || (ret_buffer_fill == NULL) ||
       (ret_buffer_free == NULL) || (ds == NULL) || (vl == NULL))
     return (-EINVAL);
@@ -334,5 +344,7 @@ int format_kairosdb_value_list(char *buffer, /* {{{ */
 
   return (format_kairosdb_value_list_nocheck(
       buffer, ret_buffer_fill, ret_buffer_free, ds, vl, store_rates,
-      (*ret_buffer_free) - 2));
+      (*ret_buffer_free) - 2, http_attrs, http_attrs_num));
 } /* }}} int format_kairosdb_value_list */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
index 9174318..b6aa39d 100644 (file)
@@ -39,7 +39,9 @@ int format_kairosdb_initialize(char *buffer, size_t *ret_buffer_fill,
                                size_t *ret_buffer_free);
 int format_kairosdb_value_list(char *buffer, size_t *ret_buffer_fill,
                                size_t *ret_buffer_free, const data_set_t *ds,
-                               const value_list_t *vl, int store_rates);
+                               const value_list_t *vl, int store_rates,
+                               char const *const *http_attrs,
+                               size_t http_attrs_num);
 int format_kairosdb_finalize(char *buffer, size_t *ret_buffer_fill,
                              size_t *ret_buffer_free);
 
index 57da628..65e6679 100644 (file)
@@ -330,6 +330,9 @@ static yajl_gen_status ovs_yajl_gen_val(yajl_gen jgen, yajl_val jval) {
   size_t obj_len = 0;
   yajl_gen_status yajl_gen_ret = yajl_gen_status_ok;
 
+  if (jval == NULL)
+    return yajl_gen_generation_complete;
+
   if (YAJL_IS_STRING(jval))
     OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, YAJL_GET_STRING(jval));
   else if (YAJL_IS_DOUBLE(jval))
@@ -566,7 +569,11 @@ static int ovs_db_json_data_process(ovs_db_t *pdb, const char *data,
 
   /* get method name */
   if ((jval = yajl_tree_get(jnode, method_path, yajl_t_string)) != NULL) {
-    method = YAJL_GET_STRING(jval);
+    if ((method = YAJL_GET_STRING(jval)) == NULL) {
+      yajl_tree_free(jnode);
+      sfree(sjson);
+      return (-1);
+    }
     if (strcmp("echo", method) == 0) {
       /* echo request from the server */
       if (ovs_db_table_echo_cb(pdb, jnode) < 0)
index 92562c7..c335ae6 100644 (file)
@@ -414,7 +414,7 @@ static void memory_stats_submit(gauge_t value, virDomainPtr dom,
                                "minor_fault",    "unused",   "available",
                                "actual_balloon", "rss"};
 
-  if ((tag_index < 0) || (tag_index >= STATIC_ARRAY_SIZE(tags))) {
+  if ((tag_index < 0) || (tag_index >= (int)STATIC_ARRAY_SIZE(tags))) {
     ERROR("virt plugin: Array index out of bounds: tag_index = %d", tag_index);
     return;
   }
index c33ab54..c6efe07 100644 (file)
@@ -81,6 +81,9 @@ struct wh_callback_s {
 };
 typedef struct wh_callback_s wh_callback_t;
 
+static char **http_attrs;
+static size_t http_attrs_num;
+
 static void wh_log_http_error(wh_callback_t *cb) {
   if (!cb->log_http_error)
     return;
@@ -468,9 +471,9 @@ static int wh_write_kairosdb(const data_set_t *ds,
     }
   }
 
-  status = format_kairosdb_value_list(cb->send_buffer, &cb->send_buffer_fill,
-                                      &cb->send_buffer_free, ds, vl,
-                                      cb->store_rates);
+  status = format_kairosdb_value_list(
+      cb->send_buffer, &cb->send_buffer_fill, &cb->send_buffer_free, ds, vl,
+      cb->store_rates, (char const *const *)http_attrs, http_attrs_num);
   if (status == -ENOMEM) {
     status = wh_flush_nolock(/* timeout = */ 0, cb);
     if (status != 0) {
@@ -479,9 +482,9 @@ static int wh_write_kairosdb(const data_set_t *ds,
       return (status);
     }
 
-    status = format_kairosdb_value_list(cb->send_buffer, &cb->send_buffer_fill,
-                                        &cb->send_buffer_free, ds, vl,
-                                        cb->store_rates);
+    status = format_kairosdb_value_list(
+        cb->send_buffer, &cb->send_buffer_fill, &cb->send_buffer_free, ds, vl,
+        cb->store_rates, (char const *const *)http_attrs, http_attrs_num);
   }
   if (status != 0) {
     pthread_mutex_unlock(&cb->send_lock);
@@ -703,7 +706,34 @@ static int wh_config_node(oconfig_item_t *ci) /* {{{ */
       status = cf_util_get_boolean(child, &cb->log_http_error);
     else if (strcasecmp("Header", child->key) == 0)
       status = wh_config_append_string("Header", &cb->headers, child);
-    else {
+    else if (strcasecmp("Attribute", child->key) == 0) {
+      char *key = NULL;
+      char *val = NULL;
+
+      if (child->values_num != 2) {
+        WARNING("write_http plugin: Attribute need both a key and a value.");
+        break;
+      }
+      if (child->values[0].type != OCONFIG_TYPE_STRING ||
+          child->values[1].type != OCONFIG_TYPE_STRING) {
+        WARNING("write_http plugin: Attribute needs string arguments.");
+        break;
+      }
+      if ((key = strdup(child->values[0].value.string)) == NULL) {
+        WARNING("cannot allocate memory for attribute key.");
+        break;
+      }
+      if ((val = strdup(child->values[1].value.string)) == NULL) {
+        WARNING("cannot allocate memory for attribute value.");
+        sfree(key);
+        break;
+      }
+      strarray_add(&http_attrs, &http_attrs_num, key);
+      strarray_add(&http_attrs, &http_attrs_num, val);
+      DEBUG("write_http plugin: got attribute: %s => %s", key, val);
+      sfree(key);
+      sfree(val);
+    } else {
       ERROR("write_http plugin: Invalid configuration "
             "option: %s.",
             child->key);