From: Ruben Kerkhof Date: Wed, 29 Mar 2017 15:29:55 +0000 (+0200) Subject: Merge pull request #2051 from dsilakov/virt_list_domains X-Git-Tag: collectd-5.8.0~200 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=bdcefed10f0dc5add6d61d267c1d773d181c6368;hp=1c5e82a7eefdbcce608951fa5a00c5c5a43a41e6 Merge pull request #2051 from dsilakov/virt_list_domains virt plugin: get domains using virConnectListAllDomains --- diff --git a/configure.ac b/configure.ac index 63cfca77..b6a47dcf 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]] + ) + 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 diff --git a/contrib/redhat/collectd.spec b/contrib/redhat/collectd.spec index 451589d1..bceaaf8e 100644 --- a/contrib/redhat/collectd.spec +++ b/contrib/redhat/collectd.spec @@ -111,6 +111,7 @@ %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} @@ -168,10 +169,12 @@ %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 @@ -230,6 +233,7 @@ %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 @@ -240,16 +244,17 @@ 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 %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 - 5.7.1-6 +- Move recently added plugins to subpackages + +* Sun Mar 05 2017 Ruben Kerkhof - 5.7.1-5 +- Add new ovs_stats plugin + +* Sun Mar 05 2017 Ruben Kerkhof - 5.7.1-4 +- Don't enable XFS support on RHEL6, it is missing for i386 + +* Sun Mar 05 2017 Ruben Kerkhof - 5.7.1-3 +- Add dpdkevents plugin, disabled by default + * Wed Feb 22 2017 Ruben Kerkhof - 5.7.1-2 - Enable XFS support in df plugin - Fix bogus date in changelog diff --git a/docs/BUILD.dpdkstat.md b/docs/BUILD.dpdkstat.md index fe9f0e68..96f1eb95 100644 --- a/docs/BUILD.dpdkstat.md +++ b/docs/BUILD.dpdkstat.md @@ -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 diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 1e88bec3..95ec21cf 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -1027,8 +1027,8 @@ # Address "127.0.0.1" # Socket "/var/run/openvswitch/db.sock" # Interfaces "br0" "veth0" -# SendNotification false -# DispatchValues true +# SendNotification true +# DispatchValues false # # @@ -1138,7 +1138,18 @@ # # +# CollectFileDescriptor true +# CollectContextSwitch true # Process "name" +# ProcessMatch "name" "regex" +# +# CollectFileDescriptor false +# CollectContextSwitch false +# +# +# CollectFileDescriptor false +# CollectContextSwitch true +# # # @@ -1535,6 +1546,7 @@ # Header "X-Custom-Header: custom_value" # SSLVersion "TLSv1" # Format "Command" +# Attribute "key" "value" # only available for KAIROSDB format # Metrics true # Notifications false # StoreRates false diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index da8d7933..697763a5 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -5637,8 +5637,8 @@ B Address "127.0.0.1" Socket "/var/run/openvswitch/db.sock" Interfaces "br0" "veth0" - SendNotification false - DispatchValues true + SendNotification true + DispatchValues false The plugin provides the following configuration options: @@ -5676,12 +5676,12 @@ Default: empty (all interfaces on all bridges are monitored) =item B I 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 I Dispatch the OVS DB interface link status value with configured plugin interval. -Defaults to true. Please note, if B and B +Defaults to false. Please note, if B and B options are false, no OVS information will be provided by the plugin. =back @@ -6528,9 +6528,15 @@ C/var/run/collectd-powerdns>. =item B I 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 must stay below this limit. @@ -8725,6 +8731,15 @@ create output in the I (JSON). When set to KAIROSDB Defaults to B. +=item B I I + +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. + =item B B|B Controls whether I are POSTed to this location. Defaults to B. diff --git a/src/dpdkstat.c b/src/dpdkstat.c index 6b057f21..cfe993cb 100644 --- a/src/dpdkstat.c +++ b/src/dpdkstat.c @@ -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) { diff --git a/src/intel_rdt.c b/src/intel_rdt.c index e2e2e394..fc2a5f17 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -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(); diff --git a/src/ovs_events.c b/src/ovs_events.c index 8c2cd12c..d372b87a 100644 --- a/src/ovs_events.c +++ b/src/ovs_events.c @@ -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) { diff --git a/src/ovs_stats.c b/src/ovs_stats.c index 77dc1f2e..23b7533c 100644 --- a/src/ovs_stats.c +++ b/src/ovs_stats.c @@ -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) { diff --git a/src/processes.c b/src/processes.c index 4f61351a..6e472e60 100644 --- a/src/processes.c +++ b/src/processes.c @@ -32,6 +32,7 @@ * Manuel Sanmartin * Clément Stenac * Cosmin Ioiart + * Pavel Rochnyack **/ #include "collectd.h" @@ -159,12 +160,14 @@ #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 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 " - "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); diff --git a/src/utils_cmd_flush.c b/src/utils_cmd_flush.c index 9e8950bb..25a55122 100644 --- a/src/utils_cmd_flush.c +++ b/src/utils_cmd_flush.c @@ -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++; diff --git a/src/utils_format_kairosdb.c b/src/utils_format_kairosdb.c index 1e54b97c..2a14f0ed 100644 --- a/src/utils_format_kairosdb.c +++ b/src/utils_format_kairosdb.c @@ -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 : */ diff --git a/src/utils_format_kairosdb.h b/src/utils_format_kairosdb.h index 9174318d..b6aa39d4 100644 --- a/src/utils_format_kairosdb.h +++ b/src/utils_format_kairosdb.h @@ -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); diff --git a/src/utils_ovs.c b/src/utils_ovs.c index 57da628e..65e66795 100644 --- a/src/utils_ovs.c +++ b/src/utils_ovs.c @@ -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) diff --git a/src/virt.c b/src/virt.c index 92562c71..c335ae6d 100644 --- a/src/virt.c +++ b/src/virt.c @@ -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; } diff --git a/src/write_http.c b/src/write_http.c index c33ab542..c6efe079 100644 --- a/src/write_http.c +++ b/src/write_http.c @@ -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);