Merge branch 'ff/statsd'
authorFlorian Forster <octo@collectd.org>
Wed, 2 Dec 2015 09:49:36 +0000 (10:49 +0100)
committerFlorian Forster <octo@collectd.org>
Wed, 2 Dec 2015 09:49:36 +0000 (10:49 +0100)
38 files changed:
.travis.yml
bindings/java/org/collectd/java/GenericJMXConfValue.java
configure.ac
contrib/redhat/collectd.spec
src/Makefile.am
src/amqp.c
src/bind.c
src/ceph.c
src/ceph_test.c [new file with mode: 0644]
src/collectd-java.pod
src/collectd.conf.in
src/collectd.conf.pod
src/csv.c
src/curl_json.c
src/daemon/Makefile.am
src/daemon/plugin.c
src/daemon/plugin_mock.c
src/daemon/utils_time.c
src/daemon/utils_time.h
src/daemon/utils_time_mock.c [deleted file]
src/fhcount.c
src/filecount.c
src/irq.c
src/modbus.c
src/mqtt.c
src/notify_nagios.c [new file with mode: 0644]
src/perl.c
src/postgresql.c
src/powerdns.c
src/processes.c
src/redis.c
src/rrdtool.c
src/snmp.c
src/testing.h
src/varnish.c
src/write_kafka.c
src/write_redis.c
version-gen.sh

index 09adb4d..435669b 100644 (file)
@@ -1,25 +1,55 @@
-sudo: false
+sudo: required
+dist: trusty
 compiler:
   - gcc
   - clang
-addons:
-  apt:
-    packages:
-      - iptables-dev
-      - libcap-dev
-      - libdbi-dev
-      - libhiredis-dev
-      - libnfnetlink-dev
-      - libnotify-dev
-      - libpcap-dev
-      - libperl-dev
-      - libprotobuf-c0-dev
-      - librrd-dev
-      - libsnmp-dev
-      - libudev-dev
-      - libvarnishapi-dev
-      - libyajl-dev
-      - linux-libc-dev
-      - protobuf-c-compiler
 language: c
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq --no-install-recommends
+      libatasmart-dev
+      libcap-dev
+      libcurl4-gnutls-dev
+      libdbi0-dev
+      libesmtp-dev
+      libganglia1-dev
+      libgcrypt11-dev
+      libglib2.0-dev
+      libhiredis-dev
+      libi2c-dev
+      libldap2-dev
+      libltdl-dev
+      liblvm2-dev
+      libmemcached-dev
+      libmnl-dev
+      libmodbus-dev
+      libmosquitto0-dev
+      libmysqlclient-dev
+      libnotify-dev
+      libopenipmi-dev
+      liboping-dev
+      libow-dev
+      libpcap-dev
+      libperl-dev
+      libpq-dev
+      libprotobuf-c0-dev
+      librabbitmq-dev
+      librdkafka-dev
+      librrd-dev
+      libsensors4-dev
+      libsigrok-dev
+      libsnmp-dev
+      libstatgrab-dev
+      libtokyocabinet-dev
+      libtokyotyrant-dev
+      libudev-dev
+      libupsclient-dev
+      libvarnish-dev
+      libvirt-dev
+      libxml2-dev
+      libyajl-dev
+      linux-libc-dev
+      perl
+      protobuf-c-compiler
+      python-dev
 script: sh build.sh && ./configure && make distcheck
index 4b42c91..25b70d4 100644 (file)
@@ -28,6 +28,7 @@ package org.collectd.java;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Collection;
 import java.util.Set;
 import java.util.Iterator;
 import java.util.ArrayList;
@@ -39,6 +40,7 @@ import javax.management.MBeanServerConnection;
 import javax.management.ObjectName;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
 import javax.management.openmbean.InvalidKeyException;
 
 import org.collectd.api.Collectd;
@@ -68,6 +70,7 @@ class GenericJMXConfValue
   private List<String> _attributes;
   private String _instance_prefix;
   private List<String> _instance_from;
+  private String _plugin_name;
   private boolean _is_table;
 
   /**
@@ -295,6 +298,46 @@ class GenericJMXConfValue
     {
       if (value instanceof CompositeData)
         return (queryAttributeRecursive ((CompositeData) value, attrName));
+      else if (value instanceof TabularData)
+        return (queryAttributeRecursive ((TabularData) value, attrName));
+      else
+        return (null);
+    }
+  } /* }}} queryAttributeRecursive */
+
+  private Object queryAttributeRecursive (TabularData parent, /* {{{ */
+      List<String> attrName)
+  {
+    String key;
+    Object value = null;
+
+    key = attrName.remove (0);
+
+    TabularData tabularData = (TabularData) parent;
+    Collection<CompositeData> table =
+        (Collection<CompositeData>)tabularData.values();
+    for (CompositeData compositeData : table)
+    {
+      if (key.equals(compositeData.get("key")))
+      {
+        value = compositeData.get("value");
+      }
+    }
+    if (null == value)
+    {
+      return (null);
+    }
+
+    if (attrName.size () == 0)
+    {
+      return (value);
+    }
+    else
+    {
+      if (value instanceof CompositeData)
+        return (queryAttributeRecursive ((CompositeData) value, attrName));
+      else if (value instanceof TabularData)
+        return (queryAttributeRecursive ((TabularData) value, attrName));
       else
         return (null);
     }
@@ -341,6 +384,8 @@ class GenericJMXConfValue
     {
       if (value instanceof CompositeData)
         return (queryAttributeRecursive((CompositeData) value, attrNameList));
+      else if (value instanceof TabularData)
+        return (queryAttributeRecursive((TabularData) value, attrNameList));
       else if (value instanceof OpenType)
       {
         OpenType ot = (OpenType) value;
@@ -351,7 +396,7 @@ class GenericJMXConfValue
       else
       {
         Collectd.logError ("GenericJMXConfValue: Received object of "
-            + "unknown class.");
+            + "unknown class. " + attrName + " " + ((value == null)?"null":value.getClass().getName()));
         return (null);
       }
     }
@@ -436,6 +481,7 @@ class GenericJMXConfValue
     this._attributes = new ArrayList<String> ();
     this._instance_prefix = null;
     this._instance_from = new ArrayList<String> ();
+    this._plugin_name = null;
     this._is_table = false;
 
     /*
@@ -485,6 +531,12 @@ class GenericJMXConfValue
         if (tmp != null)
           this._instance_from.add (tmp);
       }
+      else if (child.getKey ().equalsIgnoreCase ("PluginName"))
+      {
+        String tmp = getConfigString (child);
+        if (tmp != null)
+          this._plugin_name = tmp;
+      }
       else
         throw (new IllegalArgumentException ("Unknown option: "
               + child.getKey ()));
@@ -538,6 +590,10 @@ class GenericJMXConfValue
 
     vl = new ValueList (pd);
     vl.setType (this._ds_name);
+    if (this._plugin_name != null)
+    {
+      vl.setPlugin (this._plugin_name);
+    }
 
     /*
      * Build the instnace prefix from the fixed string prefix and the
index 606c4ef..2a9b84a 100644 (file)
@@ -57,12 +57,23 @@ AC_PROG_YACC
 PKG_PROG_PKG_CONFIG
 
 AC_CHECK_PROG([have_protoc_c], [protoc-c], [yes], [no])
-AC_CHECK_HEADERS([google/protobuf-c/protobuf-c.h],
-                 [have_protobuf_c_h="yes"],
-                 [have_protobuf_c_h="no"])
-if test "x$have_protoc_c" = "xyes" && test "x$have_protobuf_c_h" != "xyes"
+if test "x$have_protoc_c" = "xno"
 then
-       have_protoc_c="no (unable to find <google/protobuf-c/protobuf-c.h>)"
+       have_protoc_c="no (protoc-c compiler not found)"
+fi
+
+if test "x$have_protoc_c" = "xyes"
+then
+       AC_CHECK_HEADERS([protobuf-c/protobuf-c.h google/protobuf-c/protobuf-c.h],
+                        [have_protoc_c="yes"; break],
+                        [have_protoc_c="no (<google/protobuf-c/protobuf-c.h> not found)"])
+fi
+if test "x$have_protoc_c" = "xyes"
+then
+       AC_CHECK_LIB([protobuf-c], [protobuf_c_message_pack],
+                    [have_protoc_c="yes"],
+                    [have_protoc_c="no (libprotobuf-c not found)"])
+
 fi
 AM_CONDITIONAL(HAVE_PROTOC_C, test "x$have_protoc_c" = "xyes")
 
@@ -2025,12 +2036,6 @@ then
                GCRYPT_CPPFLAGS=`"$with_libgcrypt_config" --cflags 2>/dev/null`
        fi
 
-       if test "x$GCRYPT_LDFLAGS" = "x"
-       then
-               gcrypt_exec_prefix=`"$with_libgcrypt_config" --exec-prefix 2>/dev/null`
-               GCRYPT_LDFLAGS="-L$gcrypt_exec_prefix/lib"
-       fi
-
        if test "x$GCRYPT_LIBS" = "x"
        then
                GCRYPT_LIBS=`"$with_libgcrypt_config" --libs 2>/dev/null`
@@ -2039,8 +2044,10 @@ fi
 
 SAVE_CPPFLAGS="$CPPFLAGS"
 SAVE_LDFLAGS="$LDFLAGS"
+SAVE_LIBS="$LIBS"
 CPPFLAGS="$CPPFLAGS $GCRYPT_CPPFLAGS"
 LDFLAGS="$LDFLAGS $GCRYPT_LDFLAGS"
+LIBS="$LIBS $GCRYPT_LIBS"
 
 if test "x$with_libgcrypt" = "xyes"
 then
@@ -2055,23 +2062,14 @@ fi
 
 if test "x$with_libgcrypt" = "xyes"
 then
-       if test "x$GCRYPT_LDFLAGS" != "x"
-       then
-               AC_MSG_NOTICE([gcrypt LDFLAGS: $GCRYPT_LDFLAGS])
-       fi
        AC_CHECK_LIB(gcrypt, gcry_md_hash_buffer,
                [with_libgcrypt="yes"],
                [with_libgcrypt="no (symbol gcry_md_hash_buffer not found)"])
-
-       if test "$with_libgcrypt" != "no"; then
-               m4_ifdef([AM_PATH_LIBGCRYPT],[AM_PATH_LIBGCRYPT(1:1.2.0,,with_libgcrypt="no (version 1.2.0+ required)")])
-               GCRYPT_CPPFLAGS="$LIBGCRYPT_CPPFLAGS $LIBGCRYPT_CFLAGS"
-               GCRYPT_LIBS="$LIBGCRYPT_LIBS"
-       fi
 fi
 
 CPPFLAGS="$SAVE_CPPFLAGS"
 LDFLAGS="$SAVE_LDFLAGS"
+LIBS="$SAVE_LIBS"
 
 if test "x$with_libgcrypt" = "xyes"
 then
@@ -5710,6 +5708,7 @@ AC_PLUGIN([nfs],         [$plugin_nfs],        [NFS statistics])
 AC_PLUGIN([nginx],       [$with_libcurl],      [nginx statistics])
 AC_PLUGIN([notify_desktop], [$with_libnotify], [Desktop notifications])
 AC_PLUGIN([notify_email], [$with_libesmtp],    [Email notifier])
+AC_PLUGIN([notify_nagios], [yes],              [Nagios notification plugin])
 AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
 AC_PLUGIN([numa],        [$plugin_numa],       [NUMA virtual memory statistics])
 AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
@@ -6109,6 +6108,7 @@ Configuration:
     nginx . . . . . . . . $enable_nginx
     notify_desktop  . . . $enable_notify_desktop
     notify_email  . . . . $enable_notify_email
+    notify_nagios . . . . $enable_notify_nagios
     ntpd  . . . . . . . . $enable_ntpd
     numa  . . . . . . . . $enable_numa
     nut . . . . . . . . . $enable_nut
index 2252181..4dfcc9a 100644 (file)
 %define with_nginx 0%{!?_without_nginx:1}
 %define with_notify_desktop 0%{!?_without_notify_desktop:1}
 %define with_notify_email 0%{!?_without_notify_email:1}
+%define with_notify_nagios 0%{!?_without_notify_nagios:1}
 %define with_ntpd 0%{!?_without_ntpd:1}
 %define with_numa 0%{!?_without_numa:1}
 %define with_nut 0%{!?_without_nut:1}
@@ -1233,6 +1234,12 @@ Collectd utilities
 %define _with_notify_email --disable-notify_email
 %endif
 
+%if %{with_notify_nagios}
+%define _with_notify_nagios --enable-notify_nagios
+%else
+%define _with_notify_nagios --disable-notify_nagios
+%endif
+
 %if %{with_ntpd}
 %define _with_ntpd --enable-ntpd
 %else
@@ -1711,6 +1718,7 @@ Collectd utilities
        %{?_with_memory} \
        %{?_with_network} \
        %{?_with_nfs} \
+       %{?_with_notify_nagios} \
        %{?_with_ntpd} \
        %{?_with_numa} \
        %{?_with_olsrd} \
@@ -1977,6 +1985,9 @@ fi
 %if %{with_nfs}
 %{_libdir}/%{name}/nfs.so
 %endif
+%if %{with_notify_nagios}
+%{_libdir}/%{name}/notify_nagios.so
+%endif
 %if %{with_ntpd}
 %{_libdir}/%{name}/ntpd.so
 %endif
@@ -2370,7 +2381,7 @@ fi
 %changelog
 #* TODO: next feature release changelog
 #- New upstream version
-#- New plugins enabled by default: mqtt
+#- New plugins enabled by default: mqtt, notify_nagios
 #- New plugins disabled by default: zone
 #
 * Wed May 27 2015 Marc Fournier <marc.fournier@camptocamp.com> 5.5.0-1
index 199adcf..6267a31 100644 (file)
@@ -28,7 +28,7 @@ liblatency_la_SOURCES = utils_latency.c utils_latency.h
 check_PROGRAMS += test_utils_latency
 TESTS += test_utils_latency
 test_utils_latency_SOURCES = utils_latency_test.c testing.h
-test_utils_latency_LDADD = liblatency.la daemon/libcommon.la daemon/libplugin_mock.la -lm
+test_utils_latency_LDADD = liblatency.la daemon/libplugin_mock.la -lm
 
 noinst_LTLIBRARIES += liblookup.la
 liblookup_la_SOURCES = utils_vl_lookup.c utils_vl_lookup.h
@@ -36,7 +36,7 @@ liblookup_la_LIBADD = daemon/libavltree.la
 check_PROGRAMS += test_utils_vl_lookup
 TESTS += test_utils_vl_lookup
 test_utils_vl_lookup_SOURCES = utils_vl_lookup_test.c testing.h
-test_utils_vl_lookup_LDADD = liblookup.la daemon/libcommon.la daemon/libplugin_mock.la
+test_utils_vl_lookup_LDADD = liblookup.la daemon/libplugin_mock.la
 if BUILD_WITH_LIBKSTAT
 test_utils_vl_lookup_LDADD += -lkstat
 endif
@@ -46,7 +46,7 @@ libmount_la_SOURCES = utils_mount.c utils_mount.h
 check_PROGRAMS += test_utils_mount
 TESTS += test_utils_mount
 test_utils_mount_SOURCES = utils_mount_test.c testing.h
-test_utils_mount_LDADD = libmount.la daemon/libcommon.la daemon/libplugin_mock.la
+test_utils_mount_LDADD = libmount.la daemon/libplugin_mock.la
 if BUILD_WITH_LIBKSTAT
 test_utils_mount_LDADD += -lkstat
 endif
@@ -738,6 +738,12 @@ notify_email_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 notify_email_la_LIBADD = -lesmtp -lssl -lcrypto -lpthread
 endif
 
+if BUILD_PLUGIN_NOTIFY_NAGIOS
+pkglib_LTLIBRARIES += notify_nagios.la
+notify_nagios_la_SOURCES = notify_nagios.c
+notify_nagios_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
 if BUILD_PLUGIN_NTPD
 pkglib_LTLIBRARIES += ntpd.la
 ntpd_la_SOURCES = ntpd.c
@@ -1366,25 +1372,30 @@ EXTRA_DIST +=   collectd.conf.pod \
                echo "$@ has some POD errors!"; false; \
        fi
 
+AM_V_PROTOC_C = $(am__v_PROTOC_C_@AM_V@)
+am__v_PROTOC_C_ = $(am__v_PROTOC_C_@AM_DEFAULT_V@)
+am__v_PROTOC_C_0 = @echo "  PROTOC-C    " $@;
+am__v_PROTOC_C_1 =
+
 # Protocol buffer for the "pinba" plugin.
 EXTRA_DIST += pinba.proto
-if HAVE_PROTOC_C
+if BUILD_PLUGIN_PINBA
 CLEANFILES += pinba.pb-c.c pinba.pb-c.h
 BUILT_SOURCES += pinba.pb-c.c pinba.pb-c.h
 
 pinba.pb-c.c pinba.pb-c.h: pinba.proto
-       protoc-c -I$(srcdir) --c_out . $(srcdir)/pinba.proto
+       $(AM_V_PROTOC_C)protoc-c -I$(srcdir) --c_out . $(srcdir)/pinba.proto
 endif
 
 # Protocol buffer for the "write_riemann" plugin.
 EXTRA_DIST += riemann.proto
-if HAVE_PROTOC_C
+if BUILD_PLUGIN_WRITE_RIEMANN
 CLEANFILES += riemann.pb-c.c riemann.pb-c.h
 
 BUILT_SOURCES += riemann.pb-c.c riemann.pb-c.h
 
 riemann.pb-c.c riemann.pb-c.h: riemann.proto
-       protoc-c -I$(srcdir) --c_out . $(srcdir)/riemann.proto
+       $(AM_V_PROTOC_C)protoc-c -I$(srcdir) --c_out . $(srcdir)/riemann.proto
 endif
 
 install-exec-hook:
@@ -1405,4 +1416,11 @@ uninstall-hook:
        rm -f $(DESTDIR)$(sysconfdir)/collectd.conf
        rm -f $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
 
-
+if BUILD_PLUGIN_CEPH
+test_plugin_ceph_SOURCES = ceph_test.c
+test_plugin_ceph_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+test_plugin_ceph_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+test_plugin_ceph_LDADD = daemon/libcommon.la daemon/libplugin_mock.la $(BUILD_WITH_LIBYAJL_LIBS)
+check_PROGRAMS += test_plugin_ceph
+TESTS += test_plugin_ceph
+endif
index aba4f01..4206bdc 100644 (file)
@@ -199,11 +199,11 @@ static char *camqp_strerror (camqp_config_t *conf, /* {{{ */
     switch (r.reply_type)
     {
         case AMQP_RESPONSE_NORMAL:
-            sstrncpy (buffer, "Success", sizeof (buffer));
+            sstrncpy (buffer, "Success", buffer_size);
             break;
 
         case AMQP_RESPONSE_NONE:
-            sstrncpy (buffer, "Missing RPC reply type", sizeof (buffer));
+            sstrncpy (buffer, "Missing RPC reply type", buffer_size);
             break;
 
         case AMQP_RESPONSE_LIBRARY_EXCEPTION:
@@ -215,7 +215,7 @@ static char *camqp_strerror (camqp_config_t *conf, /* {{{ */
                 return (sstrerror (r.library_error, buffer, buffer_size));
 #endif
             else
-                sstrncpy (buffer, "End of stream", sizeof (buffer));
+                sstrncpy (buffer, "End of stream", buffer_size);
             break;
 
         case AMQP_RESPONSE_SERVER_EXCEPTION:
index 06b4ace..9fb3ec4 100644 (file)
@@ -1666,7 +1666,7 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
   if (tmp->name == NULL)
   {
     ERROR ("bind plugin: strdup failed.");
-    free (tmp);
+    sfree (views);
     return (-1);
   }
 
index 419ca6e..d762754 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/ceph.c
  * Copyright (C) 2011  New Dream Network
+ * Copyright (C) 2015  Florian octo Forster
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Colin McCabe <cmccabe@alumni.cmu.edu>
- *   Dennis Zou <yunzou@cisco.com>
- *   Dan Ryder <daryder@cisco.com>
+ *   Colin McCabe <cmccabe at alumni.cmu.edu>
+ *   Dennis Zou <yunzou at cisco.com>
+ *   Dan Ryder <daryder at cisco.com>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #define _DEFAULT_SOURCE
@@ -419,140 +421,140 @@ static void ceph_daemon_free(struct ceph_daemon *d)
     sfree(d);
 }
 
-/**
- * Compact ds name by removing special characters and trimming length to
- * DATA_MAX_NAME_LEN if necessary
- */
-static void compact_ds_name(char *source, char *dest)
+/* compact_ds_name removed the special characters ":", "_", "-" and "+" from the
+ * intput string. Characters following these special characters are capitalized.
+ * Trailing "+" and "-" characters are replaces with the strings "Plus" and
+ * "Minus". */
+static int compact_ds_name (char *buffer, size_t buffer_size, char const *src)
 {
-    int keys_num = 0, i;
-    char *save_ptr = NULL, *tmp_ptr = source;
-    char *keys[16];
-    char len_str[3];
-    char tmp[DATA_MAX_NAME_LEN];
-    size_t key_chars_remaining = (DATA_MAX_NAME_LEN-1);
-    int reserved = 0;
-    int offset = 0;
-    memset(tmp, 0, sizeof(tmp));
-    if(source == NULL || dest == NULL || source[0] == '\0' || dest[0] != '\0')
-    {
-        return;
-    }
-    size_t src_len = strlen(source);
-    snprintf(len_str, sizeof(len_str), "%zu", src_len);
-    unsigned char append_status = 0x0;
-    append_status |= (source[src_len - 1] == '-') ? 0x1 : 0x0;
-    append_status |= (source[src_len - 1] == '+') ? 0x2 : 0x0;
-    while ((keys[keys_num] = strtok_r(tmp_ptr, ":_-+", &save_ptr)) != NULL)
-    {
-        tmp_ptr = NULL;
-        /** capitalize 1st char **/
-        keys[keys_num][0] = toupper(keys[keys_num][0]);
-        keys_num++;
-        if(keys_num >= 16)
-        {
-            break;
-        }
-    }
-    /** concatenate each part of source string **/
-    for(i = 0; i < keys_num; i++)
-    {
-        strncat(tmp, keys[i], key_chars_remaining);
-        key_chars_remaining -= strlen(keys[i]);
-    }
-    tmp[DATA_MAX_NAME_LEN - 1] = '\0';
-    /** to coordinate limitation of length of type_instance
-     *  we will truncate ds_name
-     *  when the its length is more than
-     *  DATA_MAX_NAME_LEN
-     */
-    if(strlen(tmp) > DATA_MAX_NAME_LEN - 1)
+    char *src_copy;
+    size_t src_len;
+    char *ptr = buffer;
+    size_t ptr_size = buffer_size;
+    _Bool append_plus = 0;
+    _Bool append_minus = 0;
+
+    if ((buffer == NULL) || (buffer_size <= strlen ("Minus")) || (src == NULL))
+      return EINVAL;
+
+    src_copy = strdup (src);
+    src_len = strlen(src);
+
+    /* Remove trailing "+" and "-". */
+    if (src_copy[src_len - 1] == '+')
     {
-        append_status |= 0x4;
-        /** we should reserve space for
-         * len_str
-         */
-        reserved += 2;
+        append_plus = 1;
+        src_len--;
+        src_copy[src_len] = 0;
     }
-    if(append_status & 0x1)
+    else if (src_copy[src_len - 1] == '-')
     {
-        /** we should reserve space for
-         * "Minus"
-         */
-        reserved += 5;
+        append_minus = 1;
+        src_len--;
+        src_copy[src_len] = 0;
     }
-    if(append_status & 0x2)
+
+    /* Split at special chars, capitalize first character, append to buffer. */
+    char *dummy = src_copy;
+    char *token;
+    char *save_ptr = NULL;
+    while ((token = strtok_r (dummy, ":_-+", &save_ptr)) != NULL)
     {
-        /** we should reserve space for
-         * "Plus"
-         */
-        reserved += 4;
+        size_t len;
+
+        dummy = NULL;
+
+        token[0] = toupper ((int) token[0]);
+
+        assert (ptr_size > 1);
+
+        len = strlen (token);
+        if (len >= ptr_size)
+            len = ptr_size - 1;
+
+        assert (len > 0);
+        assert (len < ptr_size);
+
+        sstrncpy (ptr, token, len + 1);
+        ptr += len;
+        ptr_size -= len;
+
+        assert (*ptr == 0);
+        if (ptr_size <= 1)
+            break;
     }
-    snprintf(dest, DATA_MAX_NAME_LEN - reserved, "%s", tmp);
-    offset = strlen(dest);
-    switch (append_status)
+
+    /* Append "Plus" or "Minus" if "+" or "-" has been stripped above. */
+    if (append_plus || append_minus)
     {
-        case 0x1:
-            memcpy(dest + offset, "Minus", 5);
-            break;
-        case 0x2:
-            memcpy(dest + offset, "Plus", 5);
-            break;
-        case 0x4:
-            memcpy(dest + offset, len_str, 2);
-            break;
-        case 0x5:
-            memcpy(dest + offset, "Minus", 5);
-            memcpy(dest + offset + 5, len_str, 2);
-            break;
-        case 0x6:
-            memcpy(dest + offset, "Plus", 4);
-            memcpy(dest + offset + 4, len_str, 2);
-            break;
-        default:
-            break;
+        char const *append = "Plus";
+        if (append_minus)
+            append = "Minus";
+
+        size_t offset = buffer_size - (strlen (append) + 1);
+        if (offset > strlen (buffer))
+            offset = strlen (buffer);
+
+        sstrncpy (buffer + offset, append, buffer_size - offset);
     }
+
+    sfree (src_copy);
+    return 0;
+}
+
+static _Bool has_suffix (char const *str, char const *suffix)
+{
+    size_t str_len = strlen (str);
+    size_t suffix_len = strlen (suffix);
+    size_t offset;
+
+    if (suffix_len > str_len)
+        return 0;
+    offset = str_len - suffix_len;
+
+    if (strcmp (str + offset, suffix) == 0)
+        return 1;
+
+    return 0;
+}
+
+/* count_parts returns the number of elements a "foo.bar.baz" style key has. */
+static size_t count_parts (char const *key)
+{
+    char const *ptr;
+    size_t parts_num = 0;
+
+    for (ptr = key; ptr != NULL; ptr = strchr (ptr + 1, '.'))
+        parts_num++;
+
+    return parts_num;
 }
 
 /**
  * Parse key to remove "type" if this is for schema and initiate compaction
  */
-static int parse_keys(const char *key_str, char *ds_name)
+static int parse_keys (char *buffer, size_t buffer_size, const char *key_str)
 {
-    char *ptr, *rptr;
-    size_t ds_name_len = 0;
-    /**
-     * allow up to 100 characters before compaction - compact_ds_name will not
-     * allow more than DATA_MAX_NAME_LEN chars
-     */
-    int max_str_len = 100;
-    char tmp_ds_name[max_str_len];
-    memset(tmp_ds_name, 0, sizeof(tmp_ds_name));
-    if(ds_name == NULL || key_str == NULL ||  key_str[0] == '\0' ||
-                                                            ds_name[0] != '\0')
-    {
-        return -1;
-    }
-    if((ptr = strchr(key_str, '.')) == NULL
-            || (rptr = strrchr(key_str, '.')) == NULL)
+    char tmp[2 * buffer_size];
+
+    if (buffer == NULL || buffer_size == 0 || key_str == NULL || strlen (key_str) == 0)
+        return EINVAL;
+
+    if ((count_parts (key_str) > 2) && has_suffix (key_str, ".type"))
     {
-        memcpy(tmp_ds_name, key_str, max_str_len - 1);
-        goto compact;
-    }
+        /* strip ".type" suffix iff the key has more than two parts. */
+        size_t sz = strlen (key_str) - strlen (".type") + 1;
 
-    ds_name_len = (rptr - ptr) > max_str_len ? max_str_len : (rptr - ptr);
-    if((ds_name_len == 0) || strncmp(rptr + 1, "type", 4))
-    { /** copy whole key **/
-        memcpy(tmp_ds_name, key_str, max_str_len - 1);
+        if (sz > sizeof (tmp))
+            sz = sizeof (tmp);
+        sstrncpy (tmp, key_str, sz);
     }
     else
-    {/** more than two keys **/
-        memcpy(tmp_ds_name, key_str, ((rptr - key_str) > (max_str_len - 1) ?
-                (max_str_len - 1) : (rptr - key_str)));
+    {
+        sstrncpy (tmp, key_str, sizeof (tmp));
     }
 
-    compact: compact_ds_name(tmp_ds_name, ds_name);
-    return 0;
+    return compact_ds_name (buffer, buffer_size, tmp);
 }
 
 /**
@@ -604,7 +606,7 @@ static int ceph_daemon_add_ds_entry(struct ceph_daemon *d, const char *name,
             ((pc_type & PERFCOUNTER_LATENCY) ? DSET_LATENCY : DSET_BYTES);
     d->ds_types[d->ds_num] = type;
 
-    if(parse_keys(name, ds_name))
+    if (parse_keys(ds_name, sizeof (ds_name), name))
     {
         return 1;
     }
@@ -956,7 +958,7 @@ static int node_handler_fetch_data(void *arg, const char *val, const char *key)
     char ds_name[DATA_MAX_NAME_LEN];
     memset(ds_name, 0, sizeof(ds_name));
 
-    if(parse_keys(key, ds_name))
+    if (parse_keys (ds_name, sizeof (ds_name), key))
     {
         return 1;
     }
@@ -1082,6 +1084,7 @@ static int cconn_connect(struct cconn *io)
     {
         ERROR("ceph plugin: cconn_connect: connect(%d) failed: error %d",
             fd, err);
+        close(fd);
         return err;
     }
 
@@ -1091,6 +1094,7 @@ static int cconn_connect(struct cconn *io)
         err = -errno;
         ERROR("ceph plugin: cconn_connect: fcntl(%d, O_NONBLOCK) error %d",
             fd, err);
+        close(fd);
         return err;
     }
     io->asok = fd;
diff --git a/src/ceph_test.c b/src/ceph_test.c
new file mode 100644 (file)
index 0000000..d6c7231
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * collectd - src/ceph_test.c
+ * Copyright (C) 2015      Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "ceph.c" /* sic */
+#include "testing.h"
+
+DEF_TEST(parse_keys)
+{
+  struct {
+    char *str;
+    char *want;
+  } cases[] = {
+    {"WBThrottle.bytes_dirtied.description.bytes_wb.description.ios_dirtied.description.ios_wb.type", "WBThrottle.bytesDirtied.description.bytesWb.description.iosDirt"},
+    {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
+    {"foo:bar", "FooBar"},
+    {"foo:bar+", "FooBarPlus"},
+    {"foo:bar-", "FooBarMinus"},
+    {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+", "AaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPlus"},
+    {"aa.bb.cc.dd.ee.ff", "Aa.bb.cc.dd.ee.ff"},
+    {"aa.bb.cc.dd.ee.ff.type", "Aa.bb.cc.dd.ee.ff"},
+    {"aa.type", "Aa.type"},
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++)
+  {
+    char got[DATA_MAX_NAME_LEN];
+
+    CHECK_ZERO (parse_keys (got, sizeof (got), cases[i].str));
+    EXPECT_EQ_STR (cases[i].want, got);
+  }
+
+  return 0;
+}
+
+int main (void)
+{
+  RUN_TEST(parse_keys);
+
+  END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
index aade08a..afa7e48 100644 (file)
@@ -620,6 +620,11 @@ sets the type instance instead. I<(optional)>
 Works like the option of the same name directly beneath the I<MBean> block, but
 sets the type instance instead. I<(optional)>
 
+=item B<PluginName> I<name>
+
+When set, overrides the default setting for the I<plugin> field
+(C<GenericJMX>).
+
 =item B<Table> B<true>|B<false>
 
 Set this to true if the returned attribute is a I<composite type>. If set to
index b275ce1..63bdb23 100644 (file)
 #@BUILD_PLUGIN_NGINX_TRUE@LoadPlugin nginx
 #@BUILD_PLUGIN_NOTIFY_DESKTOP_TRUE@LoadPlugin notify_desktop
 #@BUILD_PLUGIN_NOTIFY_EMAIL_TRUE@LoadPlugin notify_email
+#@BUILD_PLUGIN_NOTIFY_NAGIOS_TRUE@LoadPlugin notify_nagios
 #@BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
 #@BUILD_PLUGIN_NUMA_TRUE@LoadPlugin numa
 #@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
 #      Recipient "email2@domain2.com"
 #</Plugin>
 
+#<Plugin notify_nagios>
+#      CommandFile "/usr/local/nagios/var/rw/nagios.cmd"
+#</Plugin>
+
 #<Plugin ntpd>
 #      Host "localhost"
 #      Port 123
index 624cf41..9e2f652 100644 (file)
@@ -4436,6 +4436,21 @@ Default: C<Collectd notify: %s@%s>
 
 =back
 
+=head2 Plugin C<notify_nagios>
+
+The I<notify_nagios> plugin writes notifications to Nagios' I<command file> as
+a I<passive service check result>.
+
+Available configuration options:
+
+=over 4
+
+=item B<CommandFile> I<Path>
+
+Sets the I<command file> to write to. Defaults to F</usr/local/nagios/var/rw/nagios.cmd>.
+
+=back
+
 =head2 Plugin C<ntpd>
 
 =over 4
index 15494f4..7b513e7 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -64,13 +64,16 @@ static int value_list_to_string (char *buffer, int buffer_len,
                                && (ds->ds[i].type != DS_TYPE_GAUGE)
                                && (ds->ds[i].type != DS_TYPE_DERIVE)
                                && (ds->ds[i].type != DS_TYPE_ABSOLUTE))
+               {
+                       sfree (rates);
                        return (-1);
+               }
 
-               if (ds->ds[i].type == DS_TYPE_GAUGE) 
+               if (ds->ds[i].type == DS_TYPE_GAUGE)
                {
                        status = ssnprintf (buffer + offset, buffer_len - offset,
                                        ",%lf", vl->values[i].gauge);
-               } 
+               }
                else if (store_rates != 0)
                {
                        if (rates == NULL)
index 510d9b6..69d45e3 100644 (file)
@@ -131,17 +131,11 @@ static size_t cj_curl_callback (void *buf, /* {{{ */
     return (len);
 #endif
 
-  if (status != yajl_status_ok)
-  {
-    unsigned char *msg =
-      yajl_get_error(db->yajl, /* verbose = */ 1,
-          /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
-    ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
-    yajl_free_error(db->yajl, msg);
-    return (0); /* abort write callback */
-  }
-
-  return (len);
+  unsigned char *msg = yajl_get_error(db->yajl, /* verbose = */ 1,
+        /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
+  ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
+  yajl_free_error(db->yajl, msg);
+  return (0); /* abort write callback */
 } /* }}} size_t cj_curl_callback */
 
 static int cj_get_type (cj_key_t *key)
index 3d50029..cdd927b 100644 (file)
@@ -48,8 +48,10 @@ libheap_la_SOURCES = utils_heap.c utils_heap.h
 
 libmetadata_la_SOURCES = meta_data.c meta_data.h
 
-libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c utils_time_mock.c
-libplugin_mock_la_LIBADD = $(COMMON_LIBS)
+libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c \
+                           utils_time.c utils_time.h
+libplugin_mock_la_CPPFLAGS = $(AM_CPPFLAGS) -DMOCK_TIME
+libplugin_mock_la_LIBADD = $(COMMON_LIBS) libcommon.la
 
 collectd_SOURCES = collectd.c collectd.h \
                   configfile.c configfile.h \
@@ -94,7 +96,7 @@ check_PROGRAMS = test_common test_meta_data test_utils_avltree test_utils_heap t
 TESTS          = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_time test_utils_subst
 
 test_common_SOURCES = common_test.c ../testing.h
-test_common_LDADD = libcommon.la libplugin_mock.la
+test_common_LDADD = libplugin_mock.la
 
 test_meta_data_SOURCES = meta_data_test.c ../testing.h
 test_meta_data_LDADD = libmetadata.la libplugin_mock.la
@@ -109,4 +111,4 @@ test_utils_time_SOURCES = utils_time_test.c ../testing.h
 
 test_utils_subst_SOURCES = utils_subst_test.c ../testing.h \
                           utils_subst.c utils_subst.h
-test_utils_subst_LDADD = libcommon.la libplugin_mock.la
+test_utils_subst_LDADD = libplugin_mock.la
index 831e3fb..0919bdf 100644 (file)
@@ -288,7 +288,7 @@ static int register_callback (llist_t **list, /* {{{ */
                {
                        ERROR ("plugin: register_callback: "
                                        "llentry_create failed.");
-                       free (key);
+                       sfree (key);
                        destroy_callback (cf);
                        return (-1);
                }
@@ -358,9 +358,9 @@ static void log_list_callbacks (llist_t **list, /* {{{ */
                *str = '\0';
                strjoin(str, len, keys, n, "', '");
                INFO("%s ['%s']", comment, str);
-               free(str);
+               sfree (str);
        }
-       free(keys);
+       sfree (keys);
 } /* }}} void log_list_callbacks */
 
 static int create_register_callback (llist_t **list, /* {{{ */
@@ -483,7 +483,9 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
        {
                read_func_t *rf;
                plugin_ctx_t old_ctx;
+               cdtime_t start;
                cdtime_t now;
+               cdtime_t elapsed;
                int status;
                int rf_type;
                int rc;
@@ -562,6 +564,8 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
 
                DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name);
 
+               start = cdtime ();
+
                old_ctx = plugin_set_ctx (rf->rf_ctx);
 
                if (rf_type == RF_SIMPLE)
@@ -605,8 +609,22 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                /* update the ``next read due'' field */
                now = cdtime ();
 
+               /* calculate the time spent in the read function */
+               elapsed = (now - start);
+
+               if (elapsed > rf->rf_effective_interval)
+                       WARNING ("plugin_read_thread: read-function of the `%s' plugin took %.3f "
+                               "seconds, which is above its read interval (%.3f seconds). You might "
+                               "want to adjust the `Interval' or `ReadThreads' settings.",
+                               rf->rf_name, CDTIME_T_TO_DOUBLE(elapsed),
+                               CDTIME_T_TO_DOUBLE(rf->rf_effective_interval));
+
+               DEBUG ("plugin_read_thread: read-function of the `%s' plugin took "
+                               "%.6f seconds.",
+                               rf->rf_name, CDTIME_T_TO_DOUBLE(elapsed));
+
                DEBUG ("plugin_read_thread: Effective interval of the "
-                               "%s plugin is %.3f seconds.",
+                               "`%s' plugin is %.3f seconds.",
                                rf->rf_name,
                                CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
 
@@ -623,7 +641,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                        rf->rf_next_read = now;
                }
 
-               DEBUG ("plugin_read_thread: Next read of the %s plugin at %.3f.",
+               DEBUG ("plugin_read_thread: Next read of the `%s' plugin at %.3f.",
                                rf->rf_name,
                                CDTIME_T_TO_DOUBLE (rf->rf_next_read));
 
@@ -941,17 +959,17 @@ static void stop_write_threads (void) /* {{{ */
  */
 void plugin_set_dir (const char *dir)
 {
-       if (plugindir != NULL)
-               free (plugindir);
+       sfree (plugindir);
 
        if (dir == NULL)
-               plugindir = NULL;
-       else if ((plugindir = strdup (dir)) == NULL)
        {
-               char errbuf[1024];
-               ERROR ("strdup failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               plugindir = NULL;
+               return;
        }
+
+       plugindir = strdup (dir);
+       if (plugindir == NULL)
+               ERROR ("plugin_set_dir: strdup(\"%s\") failed", dir);
 }
 
 static _Bool plugin_is_loaded (char const *name)
@@ -1319,8 +1337,8 @@ static void plugin_flush_timeout_callback_free (void *data)
 
        if (cb == NULL) return;
 
-       sfree(cb->name);
-       sfree(cb);
+       sfree (cb->name);
+       sfree (cb);
 } /* static void plugin_flush_callback_free */
 
 static char *plugin_flush_callback_name (const char *name)
@@ -1371,7 +1389,7 @@ int plugin_register_flush (const char *name,
                if (cb == NULL)
                {
                        ERROR ("plugin_register_flush: malloc failed.");
-                       sfree(flush_name);
+                       sfree (flush_name);
                        return (-1);
                }
 
@@ -1379,8 +1397,8 @@ int plugin_register_flush (const char *name,
                if (cb->name == NULL)
                {
                        ERROR ("plugin_register_flush: strdup failed.");
-                       sfree(cb);
-                       sfree(flush_name);
+                       sfree (cb);
+                       sfree (flush_name);
                        return (-1);
                }
                cb->timeout = ctx.flush_timeout;
@@ -1395,11 +1413,11 @@ int plugin_register_flush (const char *name,
                        /* interval  = */ ctx.flush_interval,
                        /* user data = */ &ud);
 
-               sfree(flush_name);
+               sfree (flush_name);
                if (status != 0)
                {
-                       sfree(cb->name);
-                       sfree(cb);
+                       sfree (cb->name);
+                       sfree (cb);
                        return status;
                }
        }
@@ -1469,7 +1487,7 @@ int plugin_register_data_set (const data_set_t *ds)
                        * ds->ds_num);
        if (ds_copy->ds == NULL)
        {
-               free (ds_copy);
+               sfree (ds_copy);
                return (-1);
        }
 
@@ -1633,7 +1651,7 @@ int plugin_unregister_flush (const char *name)
                if (flush_name != NULL)
                {
                        plugin_unregister_read(flush_name);
-                       sfree(flush_name);
+                       sfree (flush_name);
                }
        }
 
@@ -2197,7 +2215,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
                         * don't get confused.. */
                        if (saved_values != NULL)
                        {
-                               free (vl->values);
+                               sfree (vl->values);
                                vl->values     = saved_values;
                                vl->values_len = saved_values_len;
                        }
@@ -2226,7 +2244,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
         * confused.. */
        if (saved_values != NULL)
        {
-               free (vl->values);
+               sfree (vl->values);
                vl->values     = saved_values;
                vl->values_len = saved_values_len;
        }
@@ -2712,7 +2730,11 @@ int plugin_notification_meta_free (notification_meta_t *n)
 
     if (this->type == NM_TYPE_STRING)
     {
-      free ((char *)this->nm_value.nm_string);
+      /* Assign to a temporary variable to work around nm_string's const
+       * modifier. */
+      void *tmp = (void *) this->nm_value.nm_string;
+
+      sfree (tmp);
       this->nm_value.nm_string = NULL;
     }
     sfree (this);
@@ -2819,7 +2841,7 @@ static void *plugin_thread_start (void *arg)
 
        plugin_set_ctx (plugin_thread->ctx);
 
-       free (plugin_thread);
+       sfree (plugin_thread);
 
        return start_routine (plugin_arg);
 } /* void *plugin_thread_start */
index f7bf1c0..b6efa3a 100644 (file)
 kstat_ctl_t *kc = NULL;
 #endif /* HAVE_LIBKSTAT */
 
+char hostname_g[] = "example.com";
+
+int plugin_register_complex_config (const char *type, int (*callback) (oconfig_item_t *))
+{
+  return ENOTSUP;
+}
+
+int plugin_register_init (const char *name, plugin_init_cb callback)
+{
+  return ENOTSUP;
+}
+
+int plugin_register_read (const char *name, int (*callback) (void))
+{
+  return ENOTSUP;
+}
+
+int plugin_register_shutdown (const char *name, int (*callback) (void))
+{
+  return ENOTSUP;
+}
+
+int plugin_dispatch_values (value_list_t const *vl)
+{
+  return ENOTSUP;
+}
+
 void plugin_log (int level, char const *format, ...)
 {
   char buffer[1024];
@@ -42,4 +69,9 @@ void plugin_log (int level, char const *format, ...)
   printf ("plugin_log (%i, \"%s\");\n", level, buffer);
 }
 
+cdtime_t plugin_get_interval (void)
+{
+  return TIME_T_TO_CDTIME_T (10);
+}
+
 /* vim: set sw=2 sts=2 et : */
index 5d905d9..7f482da 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_time.c
- * Copyright (C) 2010       Florian octo Forster
+ * Copyright (C) 2010-2015  Florian octo Forster
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -21,7 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *   Florian octo Forster <ff at octo.it>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
 #include "plugin.h"
 #include "common.h"
 
-#if HAVE_CLOCK_GETTIME
+#ifndef DEFAULT_MOCK_TIME
+# define DEFAULT_MOCK_TIME 1542455354518929408ULL
+#endif
+
+#ifdef MOCK_TIME
+cdtime_t cdtime_mock = (cdtime_t) MOCK_TIME;
+
+cdtime_t cdtime (void)
+{
+  return cdtime_mock;
+}
+#else /* !MOCK_TIME */
+# if HAVE_CLOCK_GETTIME
 cdtime_t cdtime (void) /* {{{ */
 {
   int status;
@@ -46,7 +58,7 @@ cdtime_t cdtime (void) /* {{{ */
 
   return (TIMESPEC_TO_CDTIME_T (&ts));
 } /* }}} cdtime_t cdtime */
-#else
+# else /* !HAVE_CLOCK_GETTIME */
 /* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
 cdtime_t cdtime (void) /* {{{ */
 {
@@ -64,43 +76,88 @@ cdtime_t cdtime (void) /* {{{ */
 
   return (TIMEVAL_TO_CDTIME_T (&tv));
 } /* }}} cdtime_t cdtime */
+# endif
 #endif
 
-size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t) /* {{{ */
+/* format_zone reads time zone information from "extern long timezone", exported
+ * by <time.h>, and formats it according to RFC 3339. This differs from
+ * strftime()'s "%z" format by including a colon between hour and minute. */
+static void format_zone (char *buffer, size_t buffer_size) /* {{{ */
+{
+  _Bool east = 0;
+  long hours;
+  long minutes;
+
+  minutes = timezone / 60;
+  if (minutes == 0) {
+    sstrncpy (buffer, "Z", buffer_size);
+    return;
+  }
+
+  if (minutes < 0)
+  {
+    east = 1;
+    minutes = minutes * (-1);
+  }
+
+  hours = minutes / 60;
+  minutes = minutes % 60;
+
+  ssnprintf (buffer, buffer_size, "%s%02ld:%02ld",
+             (east ? "+" : "-"), hours, minutes);
+} /* }}} int format_zone */
+
+static int format_rfc3339 (char *buffer, size_t buffer_size, cdtime_t t, _Bool print_nano) /* {{{ */
 {
   struct timespec t_spec;
   struct tm t_tm;
-
+  char base[20]; /* 2006-01-02T15:04:05 */
+  char nano[11]; /* .999999999 */
+  char zone[7];  /* +00:00 */
+  char *fields[] = {base, nano, zone};
   size_t len;
 
   CDTIME_T_TO_TIMESPEC (t, &t_spec);
   NORMALIZE_TIMESPEC (t_spec);
 
-  if (localtime_r ((time_t *)&t_spec.tv_sec, &t_tm) == NULL) {
+  if (localtime_r (&t_spec.tv_sec, &t_tm) == NULL) {
     char errbuf[1024];
-    ERROR ("cdtime_to_iso8601: localtime_r failed: %s",
-        sstrerror (errno, errbuf, sizeof (errbuf)));
-    return (0);
+    int status = errno;
+    ERROR ("format_rfc3339: localtime_r failed: %s",
+        sstrerror (status, errbuf, sizeof (errbuf)));
+    return (status);
   }
 
-  len = strftime (s, max, "%Y-%m-%dT%H:%M:%S", &t_tm);
+  len = strftime (base, sizeof (base), "%Y-%m-%dT%H:%M:%S", &t_tm);
   if (len == 0)
-    return 0;
+    return ENOMEM;
 
-  if (max - len > 2) {
-    int n = snprintf (s + len, max - len, ".%09i", (int)t_spec.tv_nsec);
-    len += (n < 0) ? 0
-      : (((size_t) n) < (max - len)) ? ((size_t) n)
-      : (max - len);
-  }
+  if (print_nano)
+    ssnprintf (nano, sizeof (nano), ".%09ld", (long) t_spec.tv_nsec);
+  else
+    sstrncpy (nano, "", sizeof (nano));
 
-  if (max - len > 3) {
-    size_t n = strftime (s + len, max - len, "%z", &t_tm);
-    len += (n < max - len) ? n : max - len;
-  }
+  format_zone (zone, sizeof (zone));
+
+  if (strjoin (buffer, buffer_size, fields, STATIC_ARRAY_SIZE (fields), "") < 0)
+    return ENOMEM;
+  return 0;
+} /* }}} int cdtime_to_rfc3339nano */
+
+int rfc3339 (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
+{
+  if (buffer_size < RFC3339_SIZE)
+    return ENOMEM;
+
+  return format_rfc3339 (buffer, buffer_size, t, 0);
+} /* }}} size_t cdtime_to_rfc3339 */
+
+int rfc3339nano (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
+{
+  if (buffer_size < RFC3339NANO_SIZE)
+    return ENOMEM;
 
-  s[max - 1] = '\0';
-  return len;
-} /* }}} size_t cdtime_to_iso8601 */
+  return format_rfc3339 (buffer, buffer_size, t, 1);
+} /* }}} size_t cdtime_to_rfc3339nano */
 
 /* vim: set sw=2 sts=2 et fdm=marker : */
index 6566a73..9e98040 100644 (file)
 
 #include "collectd.h"
 
+#ifdef TESTING_H
+/* cdtime_mock is the time returned by cdtime() when build with
+ * -DMOCK_TIME */
+extern cdtime_t cdtime_mock;
+#endif
+
 /*
  * "cdtime_t" is a 64bit unsigned integer. The time is stored at a 2^-30 second
  * resolution, i.e. the most significant 34 bit are used to store the time in
 
 cdtime_t cdtime (void);
 
-/* format a cdtime_t value in ISO 8601 format:
- * returns the number of characters written to the string (not including the
- * terminating null byte or 0 on error; the function ensures that the string
- * is null terminated */
-size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t);
+#define RFC3339_SIZE     26
+#define RFC3339NANO_SIZE 36
+
+/* rfc3339 formats a cdtime_t time in RFC 3339 format with second precision. */
+int rfc3339 (char *buffer, size_t buffer_size, cdtime_t t);
+
+/* rfc3339nano formats a cdtime_t time in RFC 3339 format with nanosecond
+ * precision. */
+int rfc3339nano (char *buffer, size_t buffer_size, cdtime_t t);
 
 #endif /* UTILS_TIME_H */
 /* vim: set sw=2 sts=2 et : */
diff --git a/src/daemon/utils_time_mock.c b/src/daemon/utils_time_mock.c
deleted file mode 100644 (file)
index 217515e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * collectd - src/tests/mock/utils_time.c
- * Copyright (C) 2013       Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *   Florian octo Forster <octo at collectd.org>
- */
-
-#include "utils_time.h"
-
-cdtime_t cdtime (void)
-{
-  return ((cdtime_t) 1542455354518929408ULL);
-}
-
index 4c409b5..666dacc 100644 (file)
@@ -98,6 +98,7 @@ static int fhcount_read(void) {
   }
   if (fgets(buffer, buffer_len, fp) == NULL) {
     ERROR("fhcount: fgets: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+    fclose(fp);
     return(EXIT_FAILURE);
   }
   fclose(fp);
index 47caf93..9ea8af7 100644 (file)
@@ -356,6 +356,7 @@ static int fc_config_add_dir (oconfig_item_t *ci)
   if (dir->path == NULL)
   {
     ERROR ("filecount plugin: strdup failed.");
+    sfree (dir);
     return (-1);
   }
 
index 6afacf0..93f3f53 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
@@ -120,6 +120,7 @@ static int irq_read (void)
        } else {
                ERROR ("irq plugin: unable to get CPU count from first line "
                                "of /proc/interrupts");
+               fclose (fh);
                return (-1);
        }
 
index cfc6331..d2b0a53 100644 (file)
@@ -942,9 +942,15 @@ static int mb_config_add_host (oconfig_item_t *ci) /* {{{ */
 
   status = cf_util_get_string_buffer (ci, host->host, sizeof (host->host));
   if (status != 0)
+  {
+    sfree (host);
     return (status);
+  }
   if (host->host[0] == 0)
+  {
+    sfree (host);
     return (EINVAL);
+  }
 
   for (i = 0; i < ci->children_num; i++)
   {
index 7003fcc..8bc412c 100644 (file)
@@ -221,6 +221,7 @@ static void on_message (
     if (payload == NULL)
     {
         ERROR ("mqtt plugin: malloc for payload buffer failed.");
+        sfree (vl.values);
         return;
     }
     memmove (payload, msg->payload, msg->payloadlen);
@@ -728,7 +729,7 @@ static int mqtt_config_subscriber (oconfig_item_t *ci)
             ERROR ("mqtt plugin: Unknown config option: %s", child->key);
     }
 
-    tmp = realloc (subscribers, sizeof (*subscribers) * subscribers_num);
+    tmp = realloc (subscribers, sizeof (*subscribers) * (subscribers_num + 1) );
     if (tmp == NULL)
     {
         ERROR ("mqtt plugin: realloc failed.");
diff --git a/src/notify_nagios.c b/src/notify_nagios.c
new file mode 100644 (file)
index 0000000..1f4182b
--- /dev/null
@@ -0,0 +1,170 @@
+/**
+ * collectd - src/notify_nagios.c
+ * Copyright (C) 2015       Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ */
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "configfile.h"
+
+#define NAGIOS_OK       0
+#define NAGIOS_WARNING  1
+#define NAGIOS_CRITICAL 2
+#define NAGIOS_UNKNOWN  3
+
+#ifndef NAGIOS_COMMAND_FILE
+# define NAGIOS_COMMAND_FILE "/usr/local/nagios/var/rw/nagios.cmd"
+#endif
+
+static char *nagios_command_file;
+
+static int nagios_config (oconfig_item_t *ci) /* {{{ */
+{
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("CommandFile", child->key) == 0)
+      cf_util_get_string (child, &nagios_command_file);
+    else
+      WARNING ("notify_nagios plugin: Ignoring unknown config option \"%s\".",
+          child->key);
+  }
+
+  return 0;
+} /* }}} nagios_config */
+
+static int nagios_print (char const *buffer) /* {{{ */
+{
+  char const *file = NAGIOS_COMMAND_FILE;
+  int fd;
+  int status;
+  struct flock lock;
+
+  if (nagios_command_file != NULL)
+    file = nagios_command_file;
+
+  fd = open (file, O_WRONLY | O_APPEND);
+  if (fd < 0)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Opening \"%s\" failed: %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    return status;
+  }
+
+  memset (&lock, 0, sizeof (lock));
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_END;
+  lock.l_start = 0;
+  lock.l_len = 0; /* to end of file */
+
+  status = fcntl (fd, F_GETLK, &lock);
+  if (status != 0)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Failed to acquire write lock on \"%s\": %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    close (fd);
+    return status;
+  }
+
+  status = (int) lseek (fd, 0, SEEK_END);
+  if (status == -1)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Seeking to end of \"%s\" failed: %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    close (fd);
+    return status;
+  }
+
+  status = (int) swrite (fd, buffer, strlen (buffer));
+  if (status != 0)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Writing to \"%s\" failed: %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    close (fd);
+    return status;
+  }
+
+  close (fd);
+  return status;
+} /* }}} int nagios_print */
+
+static int nagios_notify (const notification_t *n, /* {{{ */
+    __attribute__((unused)) user_data_t *user_data)
+{
+  char svc_description[4 * DATA_MAX_NAME_LEN];
+  char buffer[4096];
+  int code;
+  int status;
+
+  status = format_name (svc_description, (int) sizeof (svc_description),
+      /* host */ "", n->plugin, n->plugin_instance, n->type, n->type_instance);
+  if (status != 0)
+  {
+    ERROR ("notify_nagios plugin: Formatting service name failed.");
+    return status;
+  }
+
+  switch (n->severity)
+  {
+    case NOTIF_OKAY:
+      code = NAGIOS_OK;
+      break;
+    case NOTIF_WARNING:
+      code = NAGIOS_WARNING;
+      break;
+    case NOTIF_FAILURE:
+      code = NAGIOS_CRITICAL;
+      break;
+    default:
+      code = NAGIOS_UNKNOWN;
+      break;
+  }
+
+  ssnprintf (buffer, sizeof (buffer),
+      "[%.0f] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
+      CDTIME_T_TO_DOUBLE (n->time), n->host, &svc_description[1], code,
+      n->message);
+
+  return nagios_print (buffer);
+} /* }}} int nagios_notify */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("notify_nagios", nagios_config);
+  plugin_register_notification ("notify_nagios", nagios_notify, NULL);
+} /* void module_register (void) */
+
+/* vim: set sw=2 sts=2 ts=8 et : */
index 0a98684..cf09586 100644 (file)
@@ -1199,7 +1199,10 @@ static void c_ithread_destructor (void *arg)
 
        /* the ithread no longer exists */
        if (NULL == t)
+       {
+               pthread_mutex_unlock (&perl_threads->mutex);
                return;
+       }
 
        c_ithread_destroy (ithread);
 
index bef3490..e68fd32 100644 (file)
@@ -826,7 +826,7 @@ static int c_psql_write (const data_set_t *ds, const value_list_t *vl,
 {
        c_psql_database_t *db;
 
-       char time_str[32];
+       char time_str[RFC3339NANO_SIZE];
        char values_name_str[1024];
        char values_type_str[1024];
        char values_str[1024];
@@ -845,8 +845,8 @@ static int c_psql_write (const data_set_t *ds, const value_list_t *vl,
        assert (db->database != NULL);
        assert (db->writers != NULL);
 
-       if (cdtime_to_iso8601 (time_str, sizeof (time_str), vl->time) == 0) {
-               log_err ("c_psql_write: Failed to convert time to ISO 8601 format");
+       if (rfc3339nano (time_str, sizeof (time_str), vl->time) != 0) {
+               log_err ("c_psql_write: Failed to convert time to RFC 3339 format");
                return -1;
        }
 
index 1050e7f..0400f3d 100644 (file)
@@ -145,7 +145,7 @@ user-msec             number of CPU milliseconds spent in 'user' mode
 
 const char* const default_server_fields[] = /* {{{ */
 {
-  "latency"
+  "latency",
   "packetcache-hit",
   "packetcache-miss",
   "packetcache-size",
index d094e73..4f98c01 100644 (file)
@@ -1436,6 +1436,12 @@ static int ps_read_process(long pid, procstat_t *ps, char *state)
        ps->io_syscr = myUsage->pr_sysc;
        ps->io_syscw = myUsage->pr_sysc;
 
+       /*
+        * TODO: context switch counters for Solaris
+   */
+       ps->cswitch_vol   = -1;
+       ps->cswitch_invol = -1;
+
 
        /*
         * TODO: Find way of setting BLOCKED and PAGING status
@@ -1673,6 +1679,10 @@ static int ps_read (void)
 
                                pse.cpu_user_counter = task_absolutetime_info.total_user;
                                pse.cpu_system_counter = task_absolutetime_info.total_system;
+
+                               /* context switch counters not implemented */
+                               pse.cswitch_vol   = -1;
+                               pse.cswitch_invol = -1;
                        }
 
                        status = task_threads (task_list[task], &thread_list,
@@ -2026,6 +2036,10 @@ static int ps_read (void)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
 
+                       /* context switch counters not implemented */
+                       pse.cswitch_vol   = -1;
+                       pse.cswitch_invol = -1;
+
                        ps_list_add (procs[i].ki_comm, have_cmdline ? cmdline : NULL, &pse);
 
                        switch (procs[i].ki_stat)
@@ -2159,7 +2173,8 @@ static int ps_read (void)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
 
-                       pse.cswitch_vol = -1;
+                       /* context switch counters not implemented */
+                       pse.cswitch_vol   = -1;
                        pse.cswitch_invol = -1;
 
                        ps_list_add (procs[i].p_comm, have_cmdline ? cmdline : NULL, &pse);
@@ -2308,6 +2323,9 @@ static int ps_read (void)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
 
+                       pse.cswitch_vol   = -1;
+                       pse.cswitch_invol = -1;
+
                        ps_list_add (cmdline, cargs, &pse);
                } /* for (i = 0 .. nprocs) */
 
index 7864ead..a40d2cd 100644 (file)
@@ -141,7 +141,7 @@ static redis_query_t *redis_config_query (oconfig_item_t *ci) /* {{{ */
      * Default to a gauge type.
      */
     (void)strncpy(rq->type, "gauge", sizeof(rq->type));
-    (void)strncpy(rq->instance, rq->query, sizeof(rq->instance));
+    (void)sstrncpy(rq->instance, rq->query, sizeof(rq->instance));
     replace_special(rq->instance, sizeof(rq->instance));
 
     for (i = 0; i < ci->children_num; i++) {
index 764d6d6..e093f2b 100644 (file)
@@ -733,7 +733,10 @@ static int rrd_cache_insert (const char *filename,
        {
                rc = malloc (sizeof (*rc));
                if (rc == NULL)
+               {
+                       pthread_mutex_unlock (&cache_lock);
                        return (-1);
+               }
                rc->values_num = 0;
                rc->values = NULL;
                rc->first_value = 0;
index 6a03a19..9f4714d 100644 (file)
@@ -655,7 +655,10 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
 
   status = cf_util_get_string(ci, &hd->name);
   if (status != 0)
+  {
+    sfree (hd);
     return status;
+  }
 
   hd->sess_handle = NULL;
   hd->interval = 0;
@@ -1780,8 +1783,6 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 static int csnmp_read_host (user_data_t *ud)
 {
   host_definition_t *host;
-  cdtime_t time_start;
-  cdtime_t time_end;
   int status;
   int success;
   int i;
@@ -1791,8 +1792,6 @@ static int csnmp_read_host (user_data_t *ud)
   if (host->interval == 0)
     host->interval = plugin_get_interval ();
 
-  time_start = cdtime ();
-
   if (host->sess_handle == NULL)
     csnmp_host_open_session (host);
 
@@ -1813,16 +1812,6 @@ static int csnmp_read_host (user_data_t *ud)
       success++;
   }
 
-  time_end = cdtime ();
-  if ((time_end - time_start) > host->interval)
-  {
-    WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
-        "seconds, but reading all values takes %.3f seconds.",
-        host->name,
-        CDTIME_T_TO_DOUBLE (host->interval),
-        CDTIME_T_TO_DOUBLE (time_end - time_start));
-  }
-
   if (success == 0)
     return (-1);
 
index 0c415e4..c0a9e88 100644 (file)
@@ -24,6 +24,9 @@
  *   Florian octo Forster <octo at collectd.org>
  */
 
+#ifndef TESTING_H
+#define TESTING_H 1
+
 #include <inttypes.h>
 
 static int fail_count__ = 0;
@@ -109,3 +112,5 @@ static int check_count__ = 0;
   status_ = (long) (expr); \
   OK1(status_ == 0L, #expr); \
 } while (0)
+
+#endif /* TESTING_H */
index c6c4df0..65562d3 100644 (file)
@@ -588,6 +588,7 @@ static int varnish_read (user_data_t *ud) /* {{{ */
 {
        struct VSM_data *vd;
        const c_varnish_stats_t *stats;
+       _Bool ok;
 
        user_config_t *conf;
 
@@ -617,10 +618,11 @@ static int varnish_read (user_data_t *ud) /* {{{ */
        }
 
 #if HAVE_VARNISH_V3
-       if (VSC_Open (vd, /* diag = */ 1))
+       ok = (VSC_Open (vd, /* diag = */ 1) == 0);
 #else /* if HAVE_VARNISH_V4 */
-       if (VSM_Open (vd))
+       ok = (VSM_Open (vd) == 0);
 #endif
+       if (!ok)
        {
                VSM_Delete (vd);
                ERROR ("varnish plugin: Unable to open connection.");
index 775e2e0..a5977ab 100644 (file)
@@ -44,7 +44,7 @@ struct kafka_topic_context {
 #define KAFKA_FORMAT_JSON        0
 #define KAFKA_FORMAT_COMMAND     1
 #define KAFKA_FORMAT_GRAPHITE    2
-    uint8_t                     format;
+    uint8_t                      format;
     unsigned int                 graphite_flags;
     _Bool                        store_rates;
     rd_kafka_topic_conf_t       *conf;
@@ -52,12 +52,12 @@ struct kafka_topic_context {
     rd_kafka_conf_t             *kafka_conf;
     rd_kafka_t                  *kafka;
     int                          has_key;
-    uint32_t                    key;
+    uint32_t                     key;
     char                        *prefix;
     char                        *postfix;
     char                         escape_char;
     char                        *topic_name;
-    pthread_mutex_t            lock;
+    pthread_mutex_t              lock;
 };
 
 static int kafka_handle(struct kafka_topic_context *);
@@ -81,7 +81,7 @@ static int32_t kafka_partition(const rd_kafka_topic_t *rkt,
 {
     uint32_t key = *((uint32_t *)keydata );
     uint32_t target = key % partition_cnt;
-    int32_t   i = partition_cnt;
+    int32_t  i = partition_cnt;
 
     while (--i > 0 && !rd_kafka_topic_partition_available(rkt, target)) {
         target = (target + 1) % partition_cnt;
@@ -106,37 +106,37 @@ static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */
 
         if ((ctx->kafka = rd_kafka_new(RD_KAFKA_PRODUCER, conf,
                                     errbuf, sizeof(errbuf))) == NULL) {
-               ERROR("write_kafka plugin: cannot create kafka handle.");
-               return 1;
+            ERROR("write_kafka plugin: cannot create kafka handle.");
+            return 1;
         }
 
-       rd_kafka_conf_destroy(ctx->kafka_conf);
-       ctx->kafka_conf = NULL;
+        rd_kafka_conf_destroy(ctx->kafka_conf);
+        ctx->kafka_conf = NULL;
 
-       INFO ("write_kafka plugin: created KAFKA handle : %s", rd_kafka_name(ctx->kafka));
+        INFO ("write_kafka plugin: created KAFKA handle : %s", rd_kafka_name(ctx->kafka));
 
 #ifdef HAVE_LIBRDKAFKA_LOGGER
-       rd_kafka_set_logger(ctx->kafka, kafka_log);
+        rd_kafka_set_logger(ctx->kafka, kafka_log);
 #endif
     }
 
     if (ctx->topic == NULL ) {
-       if ((topic_conf = rd_kafka_topic_conf_dup(ctx->conf)) == NULL) {
+        if ((topic_conf = rd_kafka_topic_conf_dup(ctx->conf)) == NULL) {
             ERROR("write_kafka plugin: cannot duplicate kafka topic config");
             return 1;
-       }
+        }
 
-       if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
-                                                       topic_conf)) == NULL) {
-               ERROR("write_kafka plugin: cannot create topic : %s\n", 
-                       rd_kafka_err2str(rd_kafka_errno2err(errno)));
-               return errno;
-       }
+        if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
+                                            topic_conf)) == NULL) {
+            ERROR("write_kafka plugin: cannot create topic : %s\n",
+            rd_kafka_err2str(rd_kafka_errno2err(errno)));
+            return errno;
+        }
 
-       rd_kafka_topic_conf_destroy(ctx->conf);
-       ctx->conf = NULL;
+        rd_kafka_topic_conf_destroy(ctx->conf);
+        ctx->conf = NULL;
 
-       INFO ("write_kafka plugin: handle created for topic : %s", rd_kafka_topic_name(ctx->topic));
+        INFO ("write_kafka plugin: handle created for topic : %s", rd_kafka_topic_name(ctx->topic));
     }
 
     return(0);
@@ -144,16 +144,16 @@ static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */
 } /* }}} int kafka_handle */
 
 static int kafka_write(const data_set_t *ds, /* {{{ */
-             const value_list_t *vl,
-             user_data_t *ud)
+          const value_list_t *vl,
+          user_data_t *ud)
 {
-       int                      status = 0;
-    uint32_t    key;
-    char         buffer[8192];
-    size_t bfree = sizeof(buffer);
-    size_t bfill = 0;
-    size_t blen = 0;
-       struct kafka_topic_context      *ctx = ud->data;
+    int      status = 0;
+    uint32_t key;
+    char     buffer[8192];
+    size_t   bfree = sizeof(buffer);
+    size_t   bfill = 0;
+    size_t   blen = 0;
+    struct   kafka_topic_context  *ctx = ud->data;
 
     if ((ds == NULL) || (vl == NULL) || (ctx == NULL))
         return EINVAL;
@@ -177,7 +177,6 @@ static int kafka_write(const data_set_t *ds, /* {{{ */
         blen = strlen(buffer);
         break;
     case KAFKA_FORMAT_JSON:
-
         format_json_initialize(buffer, &bfill, &bfree);
         format_json_value_list(buffer, &bfill, &bfree, ds, vl,
                                ctx->store_rates);
@@ -212,15 +211,15 @@ static int kafka_write(const data_set_t *ds, /* {{{ */
                      RD_KAFKA_MSG_F_COPY, buffer, blen,
                      &key, sizeof(key), NULL);
 
-       return status;
+    return status;
 } /* }}} int kafka_write */
 
 static void kafka_topic_context_free(void *p) /* {{{ */
 {
-       struct kafka_topic_context *ctx = p;
+    struct kafka_topic_context *ctx = p;
 
-       if (ctx == NULL)
-               return;
+    if (ctx == NULL)
+        return;
 
     if (ctx->topic_name != NULL)
         sfree(ctx->topic_name);
@@ -246,13 +245,13 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     char                         callback_name[DATA_MAX_NAME_LEN];
     char                         errbuf[1024];
     user_data_t                  ud;
-       oconfig_item_t              *child;
+    oconfig_item_t              *child;
     rd_kafka_conf_res_t          ret;
 
-       if ((tctx = calloc(1, sizeof (*tctx))) == NULL) {
-               ERROR ("write_kafka plugin: calloc failed.");
+    if ((tctx = calloc(1, sizeof (*tctx))) == NULL) {
+        ERROR ("write_kafka plugin: calloc failed.");
         return;
-       }
+    }
 
     tctx->escape_char = '.';
     tctx->store_rates = 1;
@@ -290,33 +289,33 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
         goto errout;
     }
 
-       for (i = 0; i < ci->children_num; i++) {
-               /*
-                * The code here could be simplified but makes room
-                * for easy adding of new options later on.
-                */
-               child = &ci->children[i];
-               status = 0;
-
-               if (strcasecmp ("Property", child->key) == 0) {
-                       if (child->values_num != 2) {
-                               WARNING("kafka properties need both a key and a value.");
+    for (i = 0; i < ci->children_num; i++) {
+        /*
+         * The code here could be simplified but makes room
+         * for easy adding of new options later on.
+         */
+        child = &ci->children[i];
+        status = 0;
+
+        if (strcasecmp ("Property", child->key) == 0) {
+            if (child->values_num != 2) {
+                WARNING("kafka properties need both a key and a value.");
                 goto errout;
-                       }
-                       if (child->values[0].type != OCONFIG_TYPE_STRING ||
-                           child->values[1].type != OCONFIG_TYPE_STRING) {
-                               WARNING("kafka properties needs string arguments.");
+            }
+            if (child->values[0].type != OCONFIG_TYPE_STRING ||
+                child->values[1].type != OCONFIG_TYPE_STRING) {
+                WARNING("kafka properties needs string arguments.");
                 goto errout;
-                       }
+            }
             key = child->values[0].value.string;
             val = child->values[1].value.string;
             ret = rd_kafka_topic_conf_set(tctx->conf,key, val,
                                           errbuf, sizeof(errbuf));
             if (ret != RD_KAFKA_CONF_OK) {
-                               WARNING("cannot set kafka topic property %s to %s: %s.",
+                WARNING("cannot set kafka topic property %s to %s: %s.",
                         key, val, errbuf);
                 goto errout;
-                       }
+            }
 
         } else if (strcasecmp ("Key", child->key) == 0)  {
             char *tmp_buf = NULL;
@@ -397,11 +396,11 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     ud.data = tctx;
     ud.free_func = kafka_topic_context_free;
 
-       status = plugin_register_write (callback_name, kafka_write, &ud);
-       if (status != 0) {
-               WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
-                               "failed with status %i.",
-                               callback_name, status);
+    status = plugin_register_write (callback_name, kafka_write, &ud);
+    if (status != 0) {
+        WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
+                "failed with status %i.",
+                callback_name, status);
         goto errout;
     }
 
@@ -414,14 +413,14 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     if (tctx->conf != NULL)
         rd_kafka_topic_conf_destroy(tctx->conf);
     if (tctx->kafka_conf != NULL)
-               rd_kafka_conf_destroy(tctx->kafka_conf);
+        rd_kafka_conf_destroy(tctx->kafka_conf);
     sfree(tctx);
 } /* }}} int kafka_config_topic */
 
 static int kafka_config(oconfig_item_t *ci) /* {{{ */
 {
-       int                          i;
-       oconfig_item_t              *child;
+    int                          i;
+    oconfig_item_t              *child;
     rd_kafka_conf_t             *conf;
     rd_kafka_conf_res_t          ret;
     char                         errbuf[1024];
@@ -430,49 +429,49 @@ static int kafka_config(oconfig_item_t *ci) /* {{{ */
         WARNING("cannot allocate kafka configuration.");
         return -1;
     }
-       for (i = 0; i < ci->children_num; i++)  {
-               child = &ci->children[i];
+    for (i = 0; i < ci->children_num; i++)  {
+        child = &ci->children[i];
 
-               if (strcasecmp("Topic", child->key) == 0) {
-                       kafka_config_topic (conf, child);
-               } else if (strcasecmp(child->key, "Property") == 0) {
-                       char *key = NULL;
-                       char *val = NULL;
+        if (strcasecmp("Topic", child->key) == 0) {
+            kafka_config_topic (conf, child);
+        } else if (strcasecmp(child->key, "Property") == 0) {
+            char *key = NULL;
+            char *val = NULL;
 
-                       if (child->values_num != 2) {
-                               WARNING("kafka properties need both a key and a value.");
+            if (child->values_num != 2) {
+                WARNING("kafka properties need both a key and a value.");
                 goto errout;
-                       }
-                       if (child->values[0].type != OCONFIG_TYPE_STRING ||
-                           child->values[1].type != OCONFIG_TYPE_STRING) {
-                               WARNING("kafka properties needs string arguments.");
+            }
+            if (child->values[0].type != OCONFIG_TYPE_STRING ||
+                child->values[1].type != OCONFIG_TYPE_STRING) {
+                WARNING("kafka properties needs string arguments.");
                 goto errout;
-                       }
-                       if ((key = strdup(child->values[0].value.string)) == NULL) {
-                               WARNING("cannot allocate memory for attribute key.");
+            }
+            if ((key = strdup(child->values[0].value.string)) == NULL) {
+                WARNING("cannot allocate memory for attribute key.");
                 goto errout;
-                       }
-                       if ((val = strdup(child->values[1].value.string)) == NULL) {
-                               WARNING("cannot allocate memory for attribute value.");
+            }
+            if ((val = strdup(child->values[1].value.string)) == NULL) {
+                WARNING("cannot allocate memory for attribute value.");
                 goto errout;
-                       }
+            }
             ret = rd_kafka_conf_set(conf, key, val, errbuf, sizeof(errbuf));
             if (ret != RD_KAFKA_CONF_OK) {
                 WARNING("cannot set kafka property %s to %s: %s",
                         key, val, errbuf);
                 goto errout;
             }
-                       sfree(key);
-                       sfree(val);
-               } else {
-                       WARNING ("write_kafka plugin: Ignoring unknown "
-                                "configuration option \"%s\" at top level.",
-                                child->key);
-               }
-       }
+            sfree(key);
+            sfree(val);
+        } else {
+            WARNING ("write_kafka plugin: Ignoring unknown "
+                 "configuration option \"%s\" at top level.",
+                 child->key);
+        }
+    }
     if (conf != NULL)
         rd_kafka_conf_destroy(conf);
-       return (0);
+    return (0);
  errout:
     if (conf != NULL)
         rd_kafka_conf_destroy(conf);
@@ -481,7 +480,6 @@ static int kafka_config(oconfig_item_t *ci) /* {{{ */
 
 void module_register(void)
 {
-       plugin_register_complex_config ("write_kafka", kafka_config);
+    plugin_register_complex_config ("write_kafka", kafka_config);
 }
 
-/* vim: set sw=8 sts=8 ts=8 noet : */
index 1eb082f..4bfcc73 100644 (file)
@@ -83,10 +83,11 @@ static int wr_write (const data_set_t *ds, /* {{{ */
   value_size = sizeof (value);
   value_ptr = &value[0];
   status = format_values (value_ptr, value_size, ds, vl, node->store_rates);
-  pthread_mutex_lock (&node->lock);
   if (status != 0)
     return (status);
 
+  pthread_mutex_lock (&node->lock);
+
   if (node->conn == NULL)
   {
     node->conn = redisConnectWithTimeout ((char *)node->host, node->port, node->timeout);
index b09be8e..493a6eb 100755 (executable)
@@ -2,12 +2,12 @@
 
 DEFAULT_VERSION="5.5.0.git"
 
-VERSION="`git describe 2> /dev/null | grep collectd | sed -e 's/^collectd-//'`"
+if [ -d .git ]; then
+       VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"
+fi
 
 if test -z "$VERSION"; then
        VERSION="$DEFAULT_VERSION"
 fi
 
-VERSION="`echo \"$VERSION\" | sed -e 's/-/./g'`"
-
 printf "%s" "$VERSION"