From: Ruben Kerkhof Date: Mon, 10 Apr 2017 08:27:31 +0000 (+0200) Subject: Merge pull request #2168 from maryamtahhan/feat_libvirt_upstream X-Git-Tag: collectd-5.8.0~197 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=9eb3efd17e10c3bd59aa227d8d11fe60d6d4f303;hp=9d534e1f24505fa5a5042a1db2d5dbd3030e5263;p=collectd.git Merge pull request #2168 from maryamtahhan/feat_libvirt_upstream virt: add support for new metrics --- diff --git a/Makefile.am b/Makefile.am index c0334723..1f18d231 100644 --- a/Makefile.am +++ b/Makefile.am @@ -114,6 +114,7 @@ noinst_LTLIBRARIES = \ libformat_graphite.la \ libformat_json.la \ libheap.la \ + libignorelist.la \ liblatency.la \ liblookup.la \ libmetadata.la \ @@ -199,8 +200,6 @@ collectd_SOURCES = \ src/daemon/utils_cache.h \ src/daemon/utils_complain.c \ src/daemon/utils_complain.h \ - src/daemon/utils_ignorelist.c \ - src/daemon/utils_ignorelist.h \ src/daemon/utils_llist.c \ src/daemon/utils_llist.h \ src/daemon/utils_random.c \ @@ -331,6 +330,10 @@ libheap_la_SOURCES = \ src/daemon/utils_heap.c \ src/daemon/utils_heap.h +libignorelist_la_SOURCES = \ + src/utils_ignorelist.c \ + src/utils_ignorelist.h + libmetadata_la_SOURCES = \ src/daemon/meta_data.c \ src/daemon/meta_data.h @@ -340,13 +343,11 @@ libplugin_mock_la_SOURCES = \ src/daemon/utils_cache_mock.c \ src/daemon/utils_complain.c \ src/daemon/utils_complain.h \ - src/daemon/utils_ignorelist.c \ - src/daemon/utils_ignorelist.h \ src/daemon/utils_time.c \ src/daemon/utils_time.h libplugin_mock_la_CPPFLAGS = $(AM_CPPFLAGS) -DMOCK_TIME -libplugin_mock_la_LIBADD = libcommon.la $(COMMON_LIBS) +libplugin_mock_la_LIBADD = libcommon.la libignorelist.la $(COMMON_LIBS) libformat_graphite_la_SOURCES = \ src/utils_format_graphite.c \ @@ -602,7 +603,7 @@ if BUILD_PLUGIN_CGROUPS pkglib_LTLIBRARIES += cgroups.la cgroups_la_SOURCES = src/cgroups.c cgroups_la_LDFLAGS = $(PLUGIN_LDFLAGS) -cgroups_la_LIBADD = libmount.la +cgroups_la_LIBADD = libignorelist.la libmount.la endif if BUILD_PLUGIN_CHRONY @@ -719,7 +720,7 @@ if BUILD_PLUGIN_DF pkglib_LTLIBRARIES += df.la df_la_SOURCES = src/df.c df_la_LDFLAGS = $(PLUGIN_LDFLAGS) -df_la_LIBADD = libmount.la +df_la_LIBADD = libignorelist.la libmount.la endif if BUILD_PLUGIN_DISK @@ -728,7 +729,7 @@ disk_la_SOURCES = src/disk.c disk_la_CFLAGS = $(AM_CFLAGS) disk_la_CPPFLAGS = $(AM_CPPFLAGS) disk_la_LDFLAGS = $(PLUGIN_LDFLAGS) -disk_la_LIBADD = +disk_la_LIBADD = libignorelist.la if BUILD_WITH_LIBKSTAT disk_la_LIBADD += -lkstat endif @@ -888,7 +889,7 @@ pkglib_LTLIBRARIES += interface.la interface_la_SOURCES = src/interface.c interface_la_CFLAGS = $(AM_CFLAGS) interface_la_LDFLAGS = $(PLUGIN_LDFLAGS) -interface_la_LIBADD = +interface_la_LIBADD = libignorelist.la if BUILD_WITH_LIBSTATGRAB interface_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS) interface_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS) @@ -924,7 +925,7 @@ pkglib_LTLIBRARIES += ipmi.la ipmi_la_SOURCES = src/ipmi.c ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS) ipmi_la_LDFLAGS = $(PLUGIN_LDFLAGS) -ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS) +ipmi_la_LIBADD = libignorelist.la $(BUILD_WITH_OPENIPMI_LIBS) endif if BUILD_PLUGIN_IPVS @@ -941,6 +942,7 @@ if BUILD_PLUGIN_IRQ pkglib_LTLIBRARIES += irq.la irq_la_SOURCES = src/irq.c irq_la_LDFLAGS = $(PLUGIN_LDFLAGS) +irq_la_LIBADD = libignorelist.la endif if BUILD_PLUGIN_JAVA @@ -1013,6 +1015,7 @@ madwifi_la_SOURCES = \ src/madwifi.c \ src/madwifi.h madwifi_la_LDFLAGS = $(PLUGIN_LDFLAGS) +madwifi_la_LIBADD = libignorelist.la endif if BUILD_PLUGIN_MATCH_EMPTY_COUNTER @@ -1065,6 +1068,7 @@ if BUILD_PLUGIN_MD pkglib_LTLIBRARIES += md.la md_la_SOURCES = src/md.c md_la_LDFLAGS = $(PLUGIN_LDFLAGS) +md_la_LIBADD = libignorelist.la endif if BUILD_PLUGIN_MEMCACHEC @@ -1114,7 +1118,7 @@ pkglib_LTLIBRARIES += mic.la mic_la_SOURCES = src/mic.c mic_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_MIC_CPPFLAGS) mic_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_MIC_LDFLAGS) -mic_la_LIBADD = $(BUILD_WITH_MIC_LIBS) +mic_la_LIBADD = libignorelist.la $(BUILD_WITH_MIC_LIBS) endif if BUILD_PLUGIN_MODBUS @@ -1152,7 +1156,7 @@ pkglib_LTLIBRARIES += netapp.la netapp_la_SOURCES = src/netapp.c netapp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBNETAPP_CPPFLAGS) netapp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBNETAPP_LDFLAGS) -netapp_la_LIBADD = $(LIBNETAPP_LIBS) +netapp_la_LIBADD = libignorelist.la $(LIBNETAPP_LIBS) endif if BUILD_PLUGIN_NETLINK @@ -1257,8 +1261,8 @@ if BUILD_PLUGIN_ONEWIRE pkglib_LTLIBRARIES += onewire.la onewire_la_SOURCES = src/onewire.c onewire_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOWCAPI_CPPFLAGS) -onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS) onewire_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBOWCAPI_LDFLAGS) +onewire_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBOWCAPI_LIBS) endif if BUILD_PLUGIN_OPENLDAP @@ -1396,6 +1400,7 @@ if BUILD_PLUGIN_PROTOCOLS pkglib_LTLIBRARIES += protocols.la protocols_la_SOURCES = src/protocols.c protocols_la_LDFLAGS = $(PLUGIN_LDFLAGS) +protocols_la_LIBADD = libignorelist.la endif if BUILD_PLUGIN_REDIS @@ -1441,7 +1446,7 @@ pkglib_LTLIBRARIES += sensors.la sensors_la_SOURCES = src/sensors.c sensors_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBSENSORS_CPPFLAGS) sensors_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBSENSORS_LDFLAGS) -sensors_la_LIBADD = $(BUILD_WITH_LIBSENSORS_LIBS) +sensors_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBSENSORS_LIBS) endif if BUILD_PLUGIN_SERIAL @@ -1464,7 +1469,7 @@ pkglib_LTLIBRARIES += smart.la smart_la_SOURCES = src/smart.c smart_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBATASMART_CPPFLAGS) $(BUILD_WITH_LIBUDEV_CPPFLAGS) smart_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBATASMART_LDFLAGS) $(BUILD_WITH_LIBUDEV_LDFLAGS) -smart_la_LIBADD = $(BUILD_WITH_LIBATASMART_LIBS) $(BUILD_WITH_LIBUDEV_LIBS) +smart_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBATASMART_LIBS) $(BUILD_WITH_LIBUDEV_LIBS) endif endif @@ -1606,6 +1611,7 @@ if BUILD_PLUGIN_THERMAL pkglib_LTLIBRARIES += thermal.la thermal_la_SOURCES = src/thermal.c thermal_la_LDFLAGS = $(PLUGIN_LDFLAGS) +thermal_la_LIBADD = libignorelist.la endif if BUILD_PLUGIN_THRESHOLD @@ -1683,8 +1689,8 @@ pkglib_LTLIBRARIES += virt.la virt_la_SOURCES = src/virt.c virt_la_CFLAGS = $(AM_CFLAGS) \ $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS) -virt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS) virt_la_LDFLAGS = $(PLUGIN_LDFLAGS) +virt_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS) # TODO: enable once we support only modern libvirts which depends on libnl-3 # the libvirt on wheezy is linked in libnl v1, and there is a small leak here, @@ -1758,9 +1764,8 @@ endif if BUILD_PLUGIN_WRITE_MONGODB pkglib_LTLIBRARIES += write_mongodb.la write_mongodb_la_SOURCES = src/write_mongodb.c -write_mongodb_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMONGOC_CPPFLAGS) +write_mongodb_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMONGOC_CFLAGS) write_mongodb_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMONGOC_LDFLAGS) -write_mongodb_la_LIBADD = -lmongoc endif if BUILD_PLUGIN_WRITE_PROMETHEUS diff --git a/build.sh b/build.sh index 465eff9d..40f5361d 100755 --- a/build.sh +++ b/build.sh @@ -18,12 +18,7 @@ EOF done } -check_for_application lex bison autoheader aclocal automake autoconf - -# Actually we don't need the pkg-config executable, but we need the M4 macros. -# We check for `pkg-config' here and hope that M4 macros will then be -# available, too. -check_for_application pkg-config +check_for_application lex bison autoheader aclocal automake autoconf pkg-config libtoolize="" libtoolize --version >/dev/null 2>/dev/null diff --git a/configure.ac b/configure.ac index 3b932ca3..320572d0 100644 --- a/configure.ac +++ b/configure.ac @@ -3310,52 +3310,62 @@ AC_ARG_WITH([libmongoc], else if test "x$withval" = "xno"; then with_libmongoc="no" else - with_libmongoc="yes" - LIBMONGOC_CPPFLAGS="$LIBMONGOC_CPPFLAGS -I$withval/include" - LIBMONGOC_LDFLAGS="$LIBMONGOC_LDFLAGS -L$withval/lib" + with_libmongoc="no" fi; fi ], [with_libmongoc="yes"] ) -SAVE_CPPFLAGS="$CPPFLAGS" -SAVE_LDFLAGS="$LDFLAGS" - -CPPFLAGS="$CPPFLAGS $LIBMONGOC_CPPFLAGS" -LDFLAGS="$LDFLAGS $LIBMONGOC_LDFLAGS" +if test "x$with_libmongoc" = "xyes"; then + PKG_CHECK_MODULES([LIBMONGOC], [libmongoc-1.0], + [with_libmongoc="yes"], + [with_libmongoc="no (pkg-config could not find libmongoc)"] + ) +fi if test "x$with_libmongoc" = "xyes"; then - if test "x$LIBMONGOC_CPPFLAGS" != "x"; then - AC_MSG_NOTICE([libmongoc CPPFLAGS: $LIBMONGOC_CPPFLAGS]) + SAVE_CPPFLAGS="$CPPFLAGS" + + CPPFLAGS="$CPPFLAGS $LIBMONGOC_CFLAGS" + + if test "x$CPPFLAGS" != "x"; then + AC_MSG_NOTICE([libmongoc CPPFLAGS: $LIBMONGOC_CFLAGS]) fi - AC_CHECK_HEADERS([mongo.h], + AC_CHECK_HEADERS([mongoc.h], [with_libmongoc="yes"], - [with_libmongoc="no ('mongo.h' not found)"], - [[#define MONGO_HAVE_STDINT 1]] + [with_libmongoc="no ('mongoc.h' not found)"] ) + + CPPFLAGS="$SAVE_CPPFLAGS" fi if test "x$with_libmongoc" = "xyes"; then + SAVE_CPPFLAGS="$CPPFLAGS" + SAVE_LDFLAGS="$LDFLAGS" + + CPPFLAGS="$CPPFLAGS $LIBMONGOC_CFLAGS" + LDFLAGS="$LDFLAGS $LIBMONGOC_LDFLAGS" + if test "x$LIBMONGOC_LDFLAGS" != "x"; then AC_MSG_NOTICE([libmongoc LDFLAGS: $LIBMONGOC_LDFLAGS]) fi - AC_CHECK_LIB([mongoc], [mongo_run_command], + AC_CHECK_LIB([mongoc-1.0], [mongoc_init], [with_libmongoc="yes"], - [with_libmongoc="no (symbol 'mongo_run_command' not found)"] + [with_libmongoc="no (symbol 'mongoc_init' not found)"] ) -fi -CPPFLAGS="$SAVE_CPPFLAGS" -LDFLAGS="$SAVE_LDFLAGS" + CPPFLAGS="$SAVE_CPPFLAGS" + LDFLAGS="$SAVE_LDFLAGS" +fi if test "x$with_libmongoc" = "xyes"; then - BUILD_WITH_LIBMONGOC_CPPFLAGS="$LIBMONGOC_CPPFLAGS" + BUILD_WITH_LIBMONGOC_CFLAGS="$LIBMONGOC_CFLAGS" BUILD_WITH_LIBMONGOC_LDFLAGS="$LIBMONGOC_LDFLAGS" fi -AC_SUBST([BUILD_WITH_LIBMONGOC_CPPFLAGS]) +AC_SUBST([BUILD_WITH_LIBMONGOC_CFLAGS]) AC_SUBST([BUILD_WITH_LIBMONGOC_LDFLAGS]) # }}} @@ -6005,6 +6015,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 @@ -6181,11 +6196,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/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 6a5307ed..e2d6aafa 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 af7961e9..6a7a9176 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. @@ -8763,6 +8769,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/daemon/utils_ignorelist.c b/src/daemon/utils_ignorelist.c deleted file mode 100644 index 9cf6aa1e..00000000 --- a/src/daemon/utils_ignorelist.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * collectd - src/utils_ignorelist.c - * Copyright (C) 2006 Lubos Stanek - * Copyright (C) 2008 Florian Forster - * - * This program is free software; you can redistribute it and/ - * or modify it under the terms of the GNU General Public Li- - * cence as published by the Free Software Foundation; either - * version 2 of the Licence, or any later version. - * - * This program is distributed in the hope that it will be use- - * ful, but WITHOUT ANY WARRANTY; without even the implied war- - * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public Licence for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: - * Lubos Stanek - * Florian Forster - **/ -/** - * ignorelist handles plugin's list of configured collectable - * entries with global ignore action - **/ -/** - * Usage: - * - * Define plugin's global pointer variable of type ignorelist_t: - * ignorelist_t *myconfig_ignore; - * If you know the state of the global ignore (IgnoreSelected), - * allocate the variable with: - * myconfig_ignore = ignorelist_create (YourKnownIgnore); - * If you do not know the state of the global ignore, - * initialize the global variable and set the ignore flag later: - * myconfig_ignore = ignorelist_init (); - * Append single entries in your cf_register'ed callback function: - * ignorelist_add (myconfig_ignore, newentry); - * When you hit the IgnoreSelected config option, - * offer it to the list: - * ignorelist_ignore (myconfig_ignore, instantly_got_value_of_ignore); - * That is all for the ignorelist initialization. - * Later during read and write (plugin's registered functions) get - * the information whether this entry would be collected or not: - * if (ignorelist_match (myconfig_ignore, thisentry)) - * return; - **/ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include "common.h" -#include "plugin.h" -#include "utils_ignorelist.h" - -/* - * private prototypes - */ -struct ignorelist_item_s { -#if HAVE_REGEX_H - regex_t *rmatch; /* regular expression entry identification */ -#endif - char *smatch; /* string entry identification */ - struct ignorelist_item_s *next; -}; -typedef struct ignorelist_item_s ignorelist_item_t; - -struct ignorelist_s { - int ignore; /* ignore entries */ - ignorelist_item_t *head; /* pointer to the first entry */ -}; - -/* *** *** *** ********************************************* *** *** *** */ -/* *** *** *** *** *** *** private functions *** *** *** *** *** *** */ -/* *** *** *** ********************************************* *** *** *** */ - -static inline void ignorelist_append(ignorelist_t *il, - ignorelist_item_t *item) { - assert((il != NULL) && (item != NULL)); - - item->next = il->head; - il->head = item; -} - -#if HAVE_REGEX_H -static int ignorelist_append_regex(ignorelist_t *il, const char *re_str) { - regex_t *re; - ignorelist_item_t *entry; - int status; - - re = calloc(1, sizeof(*re)); - if (re == NULL) { - ERROR("ignorelist_append_regex: calloc failed."); - return (ENOMEM); - } - - status = regcomp(re, re_str, REG_EXTENDED); - if (status != 0) { - char errbuf[1024]; - (void)regerror(status, re, errbuf, sizeof(errbuf)); - ERROR("utils_ignorelist: regcomp failed: %s", errbuf); - ERROR("ignorelist_append_regex: Compiling regular expression \"%s\" " - "failed: %s", - re_str, errbuf); - sfree(re); - return (status); - } - - entry = calloc(1, sizeof(*entry)); - if (entry == NULL) { - ERROR("ignorelist_append_regex: calloc failed."); - regfree(re); - sfree(re); - return (ENOMEM); - } - entry->rmatch = re; - - ignorelist_append(il, entry); - return (0); -} /* int ignorelist_append_regex */ -#endif - -static int ignorelist_append_string(ignorelist_t *il, const char *entry) { - ignorelist_item_t *new; - - /* create new entry */ - if ((new = calloc(1, sizeof(*new))) == NULL) { - ERROR("cannot allocate new entry"); - return (1); - } - new->smatch = sstrdup(entry); - - /* append new entry */ - ignorelist_append(il, new); - - return (0); -} /* int ignorelist_append_string(ignorelist_t *il, const char *entry) */ - -#if HAVE_REGEX_H -/* - * check list for entry regex match - * return 1 if found - */ -static int ignorelist_match_regex(ignorelist_item_t *item, const char *entry) { - assert((item != NULL) && (item->rmatch != NULL) && (entry != NULL) && - (strlen(entry) > 0)); - - /* match regex */ - if (regexec(item->rmatch, entry, 0, NULL, 0) == 0) - return (1); - - return (0); -} /* int ignorelist_match_regex (ignorelist_item_t *item, const char *entry) */ -#endif - -/* - * check list for entry string match - * return 1 if found - */ -static int ignorelist_match_string(ignorelist_item_t *item, const char *entry) { - assert((item != NULL) && (item->smatch != NULL) && (entry != NULL) && - (strlen(entry) > 0)); - - if (strcmp(entry, item->smatch) == 0) - return (1); - - return (0); -} /* int ignorelist_match_string (ignorelist_item_t *item, const char *entry) */ - -/* *** *** *** ******************************************** *** *** *** */ -/* *** *** *** *** *** *** public functions *** *** *** *** *** *** */ -/* *** *** *** ******************************************** *** *** *** */ - -/* - * create the ignorelist_t with known ignore state - * return pointer to ignorelist_t - */ -ignorelist_t *ignorelist_create(int invert) { - ignorelist_t *il; - - il = calloc(1, sizeof(*il)); - if (il == NULL) - return NULL; - - /* - * ->ignore == 0 => collect - * ->ignore == 1 => ignore - */ - il->ignore = invert ? 0 : 1; - - return (il); -} /* ignorelist_t *ignorelist_create (int ignore) */ - -/* - * free memory used by ignorelist_t - */ -void ignorelist_free(ignorelist_t *il) { - ignorelist_item_t *this; - ignorelist_item_t *next; - - if (il == NULL) - return; - - for (this = il->head; this != NULL; this = next) { - next = this->next; -#if HAVE_REGEX_H - if (this->rmatch != NULL) { - regfree(this->rmatch); - sfree(this->rmatch); - this->rmatch = NULL; - } -#endif - if (this->smatch != NULL) { - sfree(this->smatch); - this->smatch = NULL; - } - sfree(this); - } - - sfree(il); -} /* void ignorelist_destroy (ignorelist_t *il) */ - -/* - * set ignore state of the ignorelist_t - */ -void ignorelist_set_invert(ignorelist_t *il, int invert) { - if (il == NULL) { - DEBUG("ignore call with ignorelist_t == NULL"); - return; - } - - il->ignore = invert ? 0 : 1; -} /* void ignorelist_set_invert (ignorelist_t *il, int ignore) */ - -/* - * append entry into ignorelist_t - * return 0 for success - */ -int ignorelist_add(ignorelist_t *il, const char *entry) { - size_t len; - - if (il == NULL) { - DEBUG("add called with ignorelist_t == NULL"); - return (1); - } - - len = strlen(entry); - - /* append nothing */ - if (len == 0) { - DEBUG("not appending: empty entry"); - return (1); - } - -#if HAVE_REGEX_H - /* regex string is enclosed in "/.../" */ - if ((len > 2) && (entry[0] == '/') && entry[len - 1] == '/') { - char *copy; - int status; - - /* skip leading slash */ - copy = strdup(entry + 1); - if (copy == NULL) - return ENOMEM; - - /* trim trailing slash */ - copy[strlen(copy) - 1] = 0; - - status = ignorelist_append_regex(il, copy); - sfree(copy); - return status; - } -#endif - - return ignorelist_append_string(il, entry); -} /* int ignorelist_add (ignorelist_t *il, const char *entry) */ - -/* - * check list for entry - * return 1 for ignored entry - */ -int ignorelist_match(ignorelist_t *il, const char *entry) { - /* if no entries, collect all */ - if ((il == NULL) || (il->head == NULL)) - return (0); - - if ((entry == NULL) || (strlen(entry) == 0)) - return (0); - - /* traverse list and check entries */ - for (ignorelist_item_t *traverse = il->head; traverse != NULL; - traverse = traverse->next) { -#if HAVE_REGEX_H - if (traverse->rmatch != NULL) { - if (ignorelist_match_regex(traverse, entry)) - return (il->ignore); - } else -#endif - { - if (ignorelist_match_string(traverse, entry)) - return (il->ignore); - } - } /* for traverse */ - - return (1 - il->ignore); -} /* int ignorelist_match (ignorelist_t *il, const char *entry) */ diff --git a/src/daemon/utils_ignorelist.h b/src/daemon/utils_ignorelist.h deleted file mode 100644 index a7fa86d5..00000000 --- a/src/daemon/utils_ignorelist.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * collectd - src/utils_ignorelist.h - * Copyright (C) 2006 Lubos Stanek - * - * This program is free software; you can redistribute it and/ - * or modify it under the terms of the GNU General Public Li- - * cence as published by the Free Software Foundation; either - * version 2 of the Licence, or any later version. - * - * This program is distributed in the hope that it will be use- - * ful, but WITHOUT ANY WARRANTY; without even the implied war- - * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public Licence for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: - * Lubos Stanek - **/ -/** - * ignorelist handles plugin's list of configured collectable - * entries with global ignore action - **/ - -#ifndef UTILS_IGNORELIST_H -#define UTILS_IGNORELIST_H 1 - -#include "collectd.h" - -#if HAVE_REGEX_H -#include -#endif - -/* public prototypes */ - -struct ignorelist_s; -typedef struct ignorelist_s ignorelist_t; - -/* - * create the ignorelist_t with known ignore state - * return pointer to ignorelist_t - */ -ignorelist_t *ignorelist_create(int invert); - -/* - * free memory used by ignorelist_t - */ -void ignorelist_free(ignorelist_t *il); - -/* - * set ignore state of the ignorelist_t - */ -void ignorelist_set_invert(ignorelist_t *il, int invert); - -/* - * append entry to ignorelist_t - * returns zero on success, non-zero upon failure. - */ -int ignorelist_add(ignorelist_t *il, const char *entry); - -/* - * check list for entry - * return 1 for ignored entry - */ -int ignorelist_match(ignorelist_t *il, const char *entry); - -#endif /* UTILS_IGNORELIST_H */ 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 1641e875..23b7533c 100644 --- a/src/ovs_stats.c +++ b/src/ovs_stats.c @@ -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 (size_t 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])); } @@ -537,6 +539,8 @@ static int ovs_stats_update_iface_stats(port_list_t *port, yajl_val stats) { if (stats && YAJL_IS_ARRAY(stats)) 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]); @@ -557,6 +561,8 @@ static int ovs_stats_update_iface_ext_ids(port_list_t *port, yajl_val ext_ids) { if (ext_ids && YAJL_IS_ARRAY(ext_ids)) 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) { 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_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_ignorelist.c b/src/utils_ignorelist.c new file mode 100644 index 00000000..9cf6aa1e --- /dev/null +++ b/src/utils_ignorelist.c @@ -0,0 +1,309 @@ +/** + * collectd - src/utils_ignorelist.c + * Copyright (C) 2006 Lubos Stanek + * Copyright (C) 2008 Florian Forster + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Lubos Stanek + * Florian Forster + **/ +/** + * ignorelist handles plugin's list of configured collectable + * entries with global ignore action + **/ +/** + * Usage: + * + * Define plugin's global pointer variable of type ignorelist_t: + * ignorelist_t *myconfig_ignore; + * If you know the state of the global ignore (IgnoreSelected), + * allocate the variable with: + * myconfig_ignore = ignorelist_create (YourKnownIgnore); + * If you do not know the state of the global ignore, + * initialize the global variable and set the ignore flag later: + * myconfig_ignore = ignorelist_init (); + * Append single entries in your cf_register'ed callback function: + * ignorelist_add (myconfig_ignore, newentry); + * When you hit the IgnoreSelected config option, + * offer it to the list: + * ignorelist_ignore (myconfig_ignore, instantly_got_value_of_ignore); + * That is all for the ignorelist initialization. + * Later during read and write (plugin's registered functions) get + * the information whether this entry would be collected or not: + * if (ignorelist_match (myconfig_ignore, thisentry)) + * return; + **/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "common.h" +#include "plugin.h" +#include "utils_ignorelist.h" + +/* + * private prototypes + */ +struct ignorelist_item_s { +#if HAVE_REGEX_H + regex_t *rmatch; /* regular expression entry identification */ +#endif + char *smatch; /* string entry identification */ + struct ignorelist_item_s *next; +}; +typedef struct ignorelist_item_s ignorelist_item_t; + +struct ignorelist_s { + int ignore; /* ignore entries */ + ignorelist_item_t *head; /* pointer to the first entry */ +}; + +/* *** *** *** ********************************************* *** *** *** */ +/* *** *** *** *** *** *** private functions *** *** *** *** *** *** */ +/* *** *** *** ********************************************* *** *** *** */ + +static inline void ignorelist_append(ignorelist_t *il, + ignorelist_item_t *item) { + assert((il != NULL) && (item != NULL)); + + item->next = il->head; + il->head = item; +} + +#if HAVE_REGEX_H +static int ignorelist_append_regex(ignorelist_t *il, const char *re_str) { + regex_t *re; + ignorelist_item_t *entry; + int status; + + re = calloc(1, sizeof(*re)); + if (re == NULL) { + ERROR("ignorelist_append_regex: calloc failed."); + return (ENOMEM); + } + + status = regcomp(re, re_str, REG_EXTENDED); + if (status != 0) { + char errbuf[1024]; + (void)regerror(status, re, errbuf, sizeof(errbuf)); + ERROR("utils_ignorelist: regcomp failed: %s", errbuf); + ERROR("ignorelist_append_regex: Compiling regular expression \"%s\" " + "failed: %s", + re_str, errbuf); + sfree(re); + return (status); + } + + entry = calloc(1, sizeof(*entry)); + if (entry == NULL) { + ERROR("ignorelist_append_regex: calloc failed."); + regfree(re); + sfree(re); + return (ENOMEM); + } + entry->rmatch = re; + + ignorelist_append(il, entry); + return (0); +} /* int ignorelist_append_regex */ +#endif + +static int ignorelist_append_string(ignorelist_t *il, const char *entry) { + ignorelist_item_t *new; + + /* create new entry */ + if ((new = calloc(1, sizeof(*new))) == NULL) { + ERROR("cannot allocate new entry"); + return (1); + } + new->smatch = sstrdup(entry); + + /* append new entry */ + ignorelist_append(il, new); + + return (0); +} /* int ignorelist_append_string(ignorelist_t *il, const char *entry) */ + +#if HAVE_REGEX_H +/* + * check list for entry regex match + * return 1 if found + */ +static int ignorelist_match_regex(ignorelist_item_t *item, const char *entry) { + assert((item != NULL) && (item->rmatch != NULL) && (entry != NULL) && + (strlen(entry) > 0)); + + /* match regex */ + if (regexec(item->rmatch, entry, 0, NULL, 0) == 0) + return (1); + + return (0); +} /* int ignorelist_match_regex (ignorelist_item_t *item, const char *entry) */ +#endif + +/* + * check list for entry string match + * return 1 if found + */ +static int ignorelist_match_string(ignorelist_item_t *item, const char *entry) { + assert((item != NULL) && (item->smatch != NULL) && (entry != NULL) && + (strlen(entry) > 0)); + + if (strcmp(entry, item->smatch) == 0) + return (1); + + return (0); +} /* int ignorelist_match_string (ignorelist_item_t *item, const char *entry) */ + +/* *** *** *** ******************************************** *** *** *** */ +/* *** *** *** *** *** *** public functions *** *** *** *** *** *** */ +/* *** *** *** ******************************************** *** *** *** */ + +/* + * create the ignorelist_t with known ignore state + * return pointer to ignorelist_t + */ +ignorelist_t *ignorelist_create(int invert) { + ignorelist_t *il; + + il = calloc(1, sizeof(*il)); + if (il == NULL) + return NULL; + + /* + * ->ignore == 0 => collect + * ->ignore == 1 => ignore + */ + il->ignore = invert ? 0 : 1; + + return (il); +} /* ignorelist_t *ignorelist_create (int ignore) */ + +/* + * free memory used by ignorelist_t + */ +void ignorelist_free(ignorelist_t *il) { + ignorelist_item_t *this; + ignorelist_item_t *next; + + if (il == NULL) + return; + + for (this = il->head; this != NULL; this = next) { + next = this->next; +#if HAVE_REGEX_H + if (this->rmatch != NULL) { + regfree(this->rmatch); + sfree(this->rmatch); + this->rmatch = NULL; + } +#endif + if (this->smatch != NULL) { + sfree(this->smatch); + this->smatch = NULL; + } + sfree(this); + } + + sfree(il); +} /* void ignorelist_destroy (ignorelist_t *il) */ + +/* + * set ignore state of the ignorelist_t + */ +void ignorelist_set_invert(ignorelist_t *il, int invert) { + if (il == NULL) { + DEBUG("ignore call with ignorelist_t == NULL"); + return; + } + + il->ignore = invert ? 0 : 1; +} /* void ignorelist_set_invert (ignorelist_t *il, int ignore) */ + +/* + * append entry into ignorelist_t + * return 0 for success + */ +int ignorelist_add(ignorelist_t *il, const char *entry) { + size_t len; + + if (il == NULL) { + DEBUG("add called with ignorelist_t == NULL"); + return (1); + } + + len = strlen(entry); + + /* append nothing */ + if (len == 0) { + DEBUG("not appending: empty entry"); + return (1); + } + +#if HAVE_REGEX_H + /* regex string is enclosed in "/.../" */ + if ((len > 2) && (entry[0] == '/') && entry[len - 1] == '/') { + char *copy; + int status; + + /* skip leading slash */ + copy = strdup(entry + 1); + if (copy == NULL) + return ENOMEM; + + /* trim trailing slash */ + copy[strlen(copy) - 1] = 0; + + status = ignorelist_append_regex(il, copy); + sfree(copy); + return status; + } +#endif + + return ignorelist_append_string(il, entry); +} /* int ignorelist_add (ignorelist_t *il, const char *entry) */ + +/* + * check list for entry + * return 1 for ignored entry + */ +int ignorelist_match(ignorelist_t *il, const char *entry) { + /* if no entries, collect all */ + if ((il == NULL) || (il->head == NULL)) + return (0); + + if ((entry == NULL) || (strlen(entry) == 0)) + return (0); + + /* traverse list and check entries */ + for (ignorelist_item_t *traverse = il->head; traverse != NULL; + traverse = traverse->next) { +#if HAVE_REGEX_H + if (traverse->rmatch != NULL) { + if (ignorelist_match_regex(traverse, entry)) + return (il->ignore); + } else +#endif + { + if (ignorelist_match_string(traverse, entry)) + return (il->ignore); + } + } /* for traverse */ + + return (1 - il->ignore); +} /* int ignorelist_match (ignorelist_t *il, const char *entry) */ diff --git a/src/utils_ignorelist.h b/src/utils_ignorelist.h new file mode 100644 index 00000000..a7fa86d5 --- /dev/null +++ b/src/utils_ignorelist.h @@ -0,0 +1,69 @@ +/** + * collectd - src/utils_ignorelist.h + * Copyright (C) 2006 Lubos Stanek + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Lubos Stanek + **/ +/** + * ignorelist handles plugin's list of configured collectable + * entries with global ignore action + **/ + +#ifndef UTILS_IGNORELIST_H +#define UTILS_IGNORELIST_H 1 + +#include "collectd.h" + +#if HAVE_REGEX_H +#include +#endif + +/* public prototypes */ + +struct ignorelist_s; +typedef struct ignorelist_s ignorelist_t; + +/* + * create the ignorelist_t with known ignore state + * return pointer to ignorelist_t + */ +ignorelist_t *ignorelist_create(int invert); + +/* + * free memory used by ignorelist_t + */ +void ignorelist_free(ignorelist_t *il); + +/* + * set ignore state of the ignorelist_t + */ +void ignorelist_set_invert(ignorelist_t *il, int invert); + +/* + * append entry to ignorelist_t + * returns zero on success, non-zero upon failure. + */ +int ignorelist_add(ignorelist_t *il, const char *entry); + +/* + * check list for entry + * return 1 for ignored entry + */ +int ignorelist_match(ignorelist_t *il, const char *entry); + +#endif /* UTILS_IGNORELIST_H */ 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 11131139..140b4883 100644 --- a/src/virt.c +++ b/src/virt.c @@ -1795,6 +1795,18 @@ static int lv_instance_include_domain(struct lv_read_instance *inst, return 0; } +/* + virConnectListAllDomains() appeared in 0.10.2 + Note that LIBVIR_CHECK_VERSION appeared a year later, so + in some systems which actually have virConnectListAllDomains() + we can't detect this. + */ +#ifdef LIBVIR_CHECK_VERSION +# if LIBVIR_CHECK_VERSION(0,10,2) +# define HAVE_LIST_ALL_DOMAINS 1 +# endif +#endif + static int refresh_lists(struct lv_read_instance *inst) { struct lv_read_state *state = &inst->read_state; int n; @@ -1808,6 +1820,10 @@ static int refresh_lists(struct lv_read_instance *inst) { lv_clean_read_state(state); if (n > 0) { +#ifdef HAVE_LIST_ALL_DOMAINS + virDomainPtr *domains; + n = virConnectListAllDomains (conn, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE); +#else int *domids; /* Get list of domains. */ @@ -1818,15 +1834,18 @@ static int refresh_lists(struct lv_read_instance *inst) { } n = virConnectListDomains(conn, domids, n); +#endif + if (n < 0) { VIRT_ERROR(conn, "reading list of domains"); +#ifndef HAVE_LIST_ALL_DOMAINS sfree(domids); +#endif return -1; } /* Fetch each domain and add it to the list, unless ignore. */ for (int i = 0; i < n; ++i) { - virDomainPtr dom = NULL; const char *name; char *xml = NULL; xmlDocPtr xml_doc = NULL; @@ -1836,12 +1855,17 @@ static int refresh_lists(struct lv_read_instance *inst) { virDomainInfo info; int status; +#ifdef HAVE_LIST_ALL_DOMAINS + virDomainPtr dom = domains[i]; +#else + virDomainPtr dom = NULL; dom = virDomainLookupByID(conn, domids[i]); if (dom == NULL) { VIRT_ERROR(conn, "virDomainLookupByID"); /* Could be that the domain went away -- ignore it anyway. */ continue; } +#endif name = virDomainGetName(dom); if (name == NULL) { @@ -1982,7 +2006,11 @@ static int refresh_lists(struct lv_read_instance *inst) { sfree(xml); } +#ifdef HAVE_LIST_ALL_DOMAINS + sfree (domains); +#else sfree(domids); +#endif } DEBUG(PLUGIN_NAME " plugin#%s: refreshing" 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); diff --git a/src/write_mongodb.c b/src/write_mongodb.c index 10f78322..66dc8e07 100644 --- a/src/write_mongodb.c +++ b/src/write_mongodb.c @@ -3,6 +3,7 @@ * Copyright (C) 2010-2013 Florian Forster * Copyright (C) 2010 Akkarit Sangpetch * Copyright (C) 2012 Chris Lundquist + * Copyright (C) 2017 Saikrishna Arcot * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -26,6 +27,7 @@ * Florian Forster * Akkarit Sangpetch * Chris Lundquist + * Saikrishna Arcot **/ #include "collectd.h" @@ -34,13 +36,7 @@ #include "plugin.h" #include "utils_cache.h" -#define MONGO_HAVE_STDINT 1 -#include - -#if (MONGO_MAJOR == 0) && (MONGO_MINOR < 8) -#define bson_alloc() bson_create() -#define bson_dealloc(b) bson_dispose(b) -#endif +#include struct wm_node_s { char name[DATA_MAX_NAME_LEN]; @@ -55,8 +51,10 @@ struct wm_node_s { char *passwd; _Bool store_rates; + _Bool connected; - mongo conn[1]; + mongoc_client_t *client; + mongoc_database_t *database; pthread_mutex_t lock; }; typedef struct wm_node_s wm_node_t; @@ -64,170 +62,235 @@ typedef struct wm_node_s wm_node_t; /* * Functions */ -static bson *wm_create_bson(const data_set_t *ds, /* {{{ */ - const value_list_t *vl, _Bool store_rates) { - bson *ret; +static bson_t *wm_create_bson(const data_set_t *ds, /* {{{ */ + const value_list_t *vl, _Bool store_rates) { + bson_t *ret; + bson_t subarray; gauge_t *rates; - ret = bson_alloc(); /* matched by bson_dealloc() */ - if (ret == NULL) { - ERROR("write_mongodb plugin: bson_create failed."); - return (NULL); + ret = bson_new(); + if (!ret) { + ERROR("write_mongodb plugin: bson_new failed."); + return NULL; } if (store_rates) { rates = uc_get_rate(ds, vl); if (rates == NULL) { ERROR("write_mongodb plugin: uc_get_rate() failed."); - return (NULL); + bson_free(ret); + return NULL; } } else { rates = NULL; } - bson_init(ret); /* matched by bson_destroy() */ - bson_append_date(ret, "time", (bson_date_t)CDTIME_T_TO_MS(vl->time)); - bson_append_string(ret, "host", vl->host); - bson_append_string(ret, "plugin", vl->plugin); - bson_append_string(ret, "plugin_instance", vl->plugin_instance); - bson_append_string(ret, "type", vl->type); - bson_append_string(ret, "type_instance", vl->type_instance); + BSON_APPEND_DATE_TIME(ret, "timestamp", CDTIME_T_TO_MS(vl->time)); + BSON_APPEND_UTF8(ret, "host", vl->host); + BSON_APPEND_UTF8(ret, "plugin", vl->plugin); + BSON_APPEND_UTF8(ret, "plugin_instance", vl->plugin_instance); + BSON_APPEND_UTF8(ret, "type", vl->type); + BSON_APPEND_UTF8(ret, "type_instance", vl->type_instance); - bson_append_start_array(ret, "values"); /* {{{ */ + BSON_APPEND_ARRAY_BEGIN(ret, "values", &subarray); /* {{{ */ for (int i = 0; i < ds->ds_num; i++) { char key[16]; ssnprintf(key, sizeof(key), "%i", i); if (ds->ds[i].type == DS_TYPE_GAUGE) - bson_append_double(ret, key, vl->values[i].gauge); + BSON_APPEND_DOUBLE(&subarray, key, vl->values[i].gauge); else if (store_rates) - bson_append_double(ret, key, (double)rates[i]); + BSON_APPEND_DOUBLE(&subarray, key, (double)rates[i]); else if (ds->ds[i].type == DS_TYPE_COUNTER) - bson_append_long(ret, key, vl->values[i].counter); + BSON_APPEND_INT64(&subarray, key, vl->values[i].counter); else if (ds->ds[i].type == DS_TYPE_DERIVE) - bson_append_long(ret, key, vl->values[i].derive); + BSON_APPEND_INT64(&subarray, key, vl->values[i].derive); else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) - bson_append_long(ret, key, vl->values[i].absolute); - else - assert(23 == 42); + BSON_APPEND_INT64(&subarray, key, vl->values[i].absolute); + else { + ERROR("write_mongodb plugin: Unknown ds_type %d for index %d", + ds->ds[i].type, i); + bson_free(ret); + return NULL; + } } - bson_append_finish_array(ret); /* }}} values */ + bson_append_array_end(ret, &subarray); /* }}} values */ - bson_append_start_array(ret, "dstypes"); /* {{{ */ + BSON_APPEND_ARRAY_BEGIN(ret, "dstypes", &subarray); /* {{{ */ for (int i = 0; i < ds->ds_num; i++) { char key[16]; ssnprintf(key, sizeof(key), "%i", i); if (store_rates) - bson_append_string(ret, key, "gauge"); + BSON_APPEND_UTF8(&subarray, key, "gauge"); else - bson_append_string(ret, key, DS_TYPE_TO_STRING(ds->ds[i].type)); + BSON_APPEND_UTF8(&subarray, key, DS_TYPE_TO_STRING(ds->ds[i].type)); } - bson_append_finish_array(ret); /* }}} dstypes */ + bson_append_array_end(ret, &subarray); /* }}} dstypes */ - bson_append_start_array(ret, "dsnames"); /* {{{ */ + BSON_APPEND_ARRAY_BEGIN(ret, "dsnames", &subarray); /* {{{ */ for (int i = 0; i < ds->ds_num; i++) { char key[16]; ssnprintf(key, sizeof(key), "%i", i); - bson_append_string(ret, key, ds->ds[i].name); + BSON_APPEND_UTF8(&subarray, key, ds->ds[i].name); } - bson_append_finish_array(ret); /* }}} dsnames */ - - bson_finish(ret); + bson_append_array_end(ret, &subarray); /* }}} dsnames */ sfree(rates); - return (ret); + + size_t error_location; + if (!bson_validate(ret, BSON_VALIDATE_UTF8, &error_location)) { + ERROR("write_mongodb plugin: Error in generated BSON document " + "at byte %zu", error_location); + bson_free(ret); + return NULL; + } + + return ret; } /* }}} bson *wm_create_bson */ -static int wm_write(const data_set_t *ds, /* {{{ */ - const value_list_t *vl, user_data_t *ud) { - wm_node_t *node = ud->data; - char collection_name[512]; - bson *bson_record; - int status; +static int wm_initialize(wm_node_t *node) /* {{{ */ +{ + char *uri; + size_t uri_length; + char const *format_string; - ssnprintf(collection_name, sizeof(collection_name), "collectd.%s", - vl->plugin); + if (node->connected) { + return 0; + } - bson_record = wm_create_bson(ds, vl, node->store_rates); - if (bson_record == NULL) - return (ENOMEM); + INFO("write_mongodb plugin: Connecting to [%s]:%i", + (node->host != NULL) ? node->host : "localhost", + (node->port != 0) ? node->port : MONGOC_DEFAULT_PORT); + + if ((node->db != NULL) && (node->user != NULL) && (node->passwd != NULL)) { + format_string = "mongodb://%s:%s@%s:%d/?authSource=%s"; + uri_length = strlen(format_string) + strlen(node->user) + + strlen(node->passwd) + strlen(node->host) + 5 + + strlen(node->db) + 1; + if ((uri = calloc(sizeof(char), uri_length)) == NULL) { + ERROR("write_mongodb plugin: Not enough memory to assemble " + "authentication string."); + mongoc_client_destroy(node->client); + node->client = NULL; + node->connected = 0; + return -1; + } + ssnprintf(uri, uri_length, format_string, node->user, node->passwd, + node->host, node->port, node->db); - pthread_mutex_lock(&node->lock); + node->client = mongoc_client_new(uri); + if (!node->client) { + ERROR("write_mongodb plugin: Authenticating to [%s]%i for database " + "\"%s\" as user \"%s\" failed.", + (node->host != NULL) ? node->host : "localhost", + (node->port != 0) ? node->port : MONGOC_DEFAULT_PORT, node->db, + node->user); + node->connected = 0; + sfree(uri); + return -1; + } + } else { + format_string = "mongodb://%s:%d"; + uri_length = strlen(format_string) + strlen(node->host) + 5 + 1; + if ((uri = calloc(sizeof(char), uri_length)) == NULL) { + ERROR("write_mongodb plugin: Not enough memory to assemble " + "authentication string."); + mongoc_client_destroy(node->client); + node->client = NULL; + node->connected = 0; + return -1; + } + snprintf(uri, uri_length, format_string, node->host, node->port); - if (!mongo_is_connected(node->conn)) { - INFO("write_mongodb plugin: Connecting to [%s]:%i", - (node->host != NULL) ? node->host : "localhost", - (node->port != 0) ? node->port : MONGO_DEFAULT_PORT); - status = mongo_connect(node->conn, node->host, node->port); - if (status != MONGO_OK) { + node->client = mongoc_client_new(uri); + if (!node->client) { ERROR("write_mongodb plugin: Connecting to [%s]:%i failed.", (node->host != NULL) ? node->host : "localhost", - (node->port != 0) ? node->port : MONGO_DEFAULT_PORT); - mongo_destroy(node->conn); - pthread_mutex_unlock(&node->lock); - return (-1); + (node->port != 0) ? node->port : MONGOC_DEFAULT_PORT); + node->connected = 0; + sfree(uri); + return -1; } + } + sfree(uri); + + node->database = mongoc_client_get_database(node->client, "collectd"); + if (!node->database) { + ERROR("write_mongodb plugin: error creating/getting database"); + mongoc_client_destroy(node->client); + node->client = NULL; + node->connected = 0; + return -1; + } - if ((node->db != NULL) && (node->user != NULL) && (node->passwd != NULL)) { - status = mongo_cmd_authenticate(node->conn, node->db, node->user, - node->passwd); - if (status != MONGO_OK) { - ERROR("write_mongodb plugin: Authenticating to [%s]%i for database " - "\"%s\" as user \"%s\" failed.", - (node->host != NULL) ? node->host : "localhost", - (node->port != 0) ? node->port : MONGO_DEFAULT_PORT, node->db, - node->user); - mongo_destroy(node->conn); - pthread_mutex_unlock(&node->lock); - return (-1); - } - } + node->connected = 1; + return 0; +} /* }}} int wm_initialize */ - if (node->timeout > 0) { - status = mongo_set_op_timeout(node->conn, node->timeout); - if (status != MONGO_OK) { - WARNING("write_mongodb plugin: mongo_set_op_timeout(%i) failed: %s", - node->timeout, node->conn->errstr); - } - } +static int wm_write(const data_set_t *ds, /* {{{ */ + const value_list_t *vl, user_data_t *ud) { + wm_node_t *node = ud->data; + mongoc_collection_t *collection = NULL; + bson_t *bson_record; + bson_error_t error; + int status; + + bson_record = wm_create_bson(ds, vl, node->store_rates); + if (!bson_record) { + ERROR("write_mongodb plugin: error making insert bson"); + return -1; } - /* Assert if the connection has been established */ - assert(mongo_is_connected(node->conn)); - -#if MONGO_MINOR >= 6 - /* There was an API change in 0.6.0 as linked below */ - /* https://github.com/mongodb/mongo-c-driver/blob/master/HISTORY.md */ - status = mongo_insert(node->conn, collection_name, bson_record, NULL); -#else - status = mongo_insert(node->conn, collection_name, bson_record); -#endif - - if (status != MONGO_OK) { - ERROR("write_mongodb plugin: error inserting record: %d", node->conn->err); - if (node->conn->err != MONGO_BSON_INVALID) - ERROR("write_mongodb plugin: %s", node->conn->errstr); - else - ERROR("write_mongodb plugin: Invalid BSON structure, error = %#x", - (unsigned int)bson_record->err); + pthread_mutex_lock(&node->lock); + if (wm_initialize(node) < 0) { + ERROR("write_mongodb plugin: error making connection to server"); + pthread_mutex_unlock(&node->lock); + bson_free(bson_record); + return -1; + } - /* Disconnect except on data errors. */ - if ((node->conn->err != MONGO_BSON_INVALID) && - (node->conn->err != MONGO_BSON_NOT_FINISHED)) - mongo_destroy(node->conn); + collection = + mongoc_client_get_collection(node->client, "collectd", vl->plugin); + if (!collection) { + ERROR("write_mongodb plugin: error creating/getting collection"); + mongoc_database_destroy(node->database); + mongoc_client_destroy(node->client); + node->database = NULL; + node->client = NULL; + node->connected = 0; + pthread_mutex_unlock(&node->lock); + bson_free(bson_record); + return -1; } - pthread_mutex_unlock(&node->lock); + status = mongoc_collection_insert(collection, MONGOC_INSERT_NONE, bson_record, + NULL, &error); + + if (!status) { + ERROR("write_mongodb plugin: error inserting record: %s", error.message); + mongoc_database_destroy(node->database); + mongoc_client_destroy(node->client); + node->database = NULL; + node->client = NULL; + node->connected = 0; + pthread_mutex_unlock(&node->lock); + bson_free(bson_record); + mongoc_collection_destroy(collection); + return -1; + } /* free our resource as not to leak memory */ - bson_destroy(bson_record); /* matches bson_init() */ - bson_dealloc(bson_record); /* matches bson_alloc() */ + mongoc_collection_destroy(collection); - return (0); + pthread_mutex_unlock(&node->lock); + + bson_free(bson_record); + + return 0; } /* }}} int wm_write */ static void wm_config_free(void *ptr) /* {{{ */ @@ -237,8 +300,11 @@ static void wm_config_free(void *ptr) /* {{{ */ if (node == NULL) return; - if (mongo_is_connected(node->conn)) - mongo_destroy(node->conn); + mongoc_database_destroy(node->database); + mongoc_client_destroy(node->client); + node->database = NULL; + node->client = NULL; + node->connected = 0; sfree(node->host); sfree(node); @@ -252,7 +318,7 @@ static int wm_config_node(oconfig_item_t *ci) /* {{{ */ node = calloc(1, sizeof(*node)); if (node == NULL) return (ENOMEM); - mongo_init(node->conn); + mongoc_init(); node->host = NULL; node->store_rates = 1; pthread_mutex_init(&node->lock, /* attr = */ NULL);