Code

Merge branch 'collectd-5.0'
authorFlorian Forster <octo@collectd.org>
Sun, 1 Apr 2012 10:07:20 +0000 (12:07 +0200)
committerFlorian Forster <octo@collectd.org>
Sun, 1 Apr 2012 10:07:20 +0000 (12:07 +0200)
16 files changed:
ChangeLog
configure.in
src/Makefile.am
src/amqp.c
src/collectd.conf.pod
src/common.c
src/common.h
src/conntrack.c
src/libcollectdclient/client.c
src/memcached.c
src/network.c
src/perl.c
src/processes.c
src/snmp.c
src/tcpconns.c
version-gen.sh

index 777a9c71ab7b390ebad9b17b6cea78bc5b375211..4ddcdd9f8e862e1d1b2e1814c5d0b5a6f67b6554 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2012-04-01, Version 5.0.4
+       * Build system: Fix the use of a libltdl macro. Thanks to Clemens Lang
+         for fixing this. Adresses some issues with building the iptables
+         plugin under Gentoo.
+       * libcollectdclient: A memory leak in the lcc_getval() function has
+         been fixed. Thanks to Jason Schmidlapp for finding and fixing this
+         issue.
+       * bind plugin: The use of 'QType" types has been fixed.
+       * df plugin: Fixed compiler issue under Mac OS X 10.7.
+       * conntrack plugin: Support zero as legitimate value. Thanks to Louis
+         Opter for his patch.
+       * memcached plugin: Increased the size of a static buffer, which was
+         truncating status messages form memcached. Thanks to Timon for the
+         patch.
+       * network plugin: Forwarding of notifications has been disabled. This
+         was a contition not checked for before, which may retult in an
+         endless loop.
+       * processes plugin: Support for process names with spaces has been
+         added to the Linux implementation. Thanks to Darrell Bishop for his
+         patch.
+       * perl plugin: A race condition in several callbacks, including log and
+         write callbacks, has been fixed. Thanks to "Rrpv" for reporting this
+         bug.
+       * snmp plugin: A bug when casting unsigned integers to gauge values has
+         been fixed: Unsigned integers would be cast to a signed integer and
+         then to a gauge, possibly resulting in a negative value.
+       * tcpconns plugin: Compilation with newer versions of the FreeBSD
+         runtime has been fixed.
+
 2012-02-19, Version 5.0.3
        * Build system: Fix problems when building the ipvs and iptables
          plugins. Thanks to Sebastian Harl for his patch. A bashism in the
        * v5upgrade target: Target for converting v4 data sets to the v5
          schema.
 
+2012-04-01, Version 4.10.7
+       * Build system: Fix the use of a libltdl macro. Thanks to Clemens Lang
+         for fixing this. Adresses some issues with building the iptables
+         plugin under Gentoo.
+       * libcollectdclient: A memory leak in the lcc_getval() function has
+         been fixed. Thanks to Jason Schmidlapp for finding and fixing this
+         issue.
+       * bind plugin: The use of 'QType" types has been fixed.
+       * df plugin: Fixed compiler issue under Mac OS X 10.7.
+       * conntrack plugin: Support zero as legitimate value. Thanks to Louis
+         Opter for his patch.
+       * memcached plugin: Increased the size of a static buffer, which was
+         truncating status messages form memcached. Thanks to Timon for the
+         patch.
+       * network plugin: Forwarding of notifications has been disabled. This
+         was a contition not checked for before, which may retult in an
+         endless loop.
+       * processes plugin: Support for process names with spaces has been
+         added to the Linux implementation. Thanks to Darrell Bishop for his
+         patch.
+       * perl plugin: A race condition in several callbacks, including log and
+         write callbacks, has been fixed. Thanks to "Rrpv" for reporting this
+         bug.
+       * snmp plugin: A bug when casting unsigned integers to gauge values has
+         been fixed: Unsigned integers would be cast to a signed integer and
+         then to a gauge, possibly resulting in a negative value.
+       * tcpconns plugin: Compilation with newer versions of the FreeBSD
+         runtime has been fixed.
+
 2012-02-19, Version 4.10.6
        * Build system: Fix problems when building the ipvs and iptables
          plugins. Thanks to Sebastian Harl for his patch. A bashism in the
index 7ba22608f5debd7a5e21fc6204c406b34911c3b3..1cfc2fcae20b4f2be5a2064c0c1174ab096a5bb2 100644 (file)
@@ -1423,6 +1423,7 @@ AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETSWAPINFO, test "x$with_kvm_getswapinfo" = "x
 AC_CHECK_LIB(kvm, kvm_nlist, [with_kvm_nlist="yes"], [with_kvm_nlist="no"])
 if test "x$with_kvm_nlist" = "xyes"
 then
+       AC_CHECK_HEADERS(bsd/nlist.h nlist.h)
        AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
                  [Define to 1 if you have the 'kvm' library with the 'kvm_nlist' symbol (-lkvm)])
        with_libkvm="yes"
@@ -1896,9 +1897,10 @@ then
        AC_CHECK_TYPES([iptc_handle_t, ip6tc_handle_t], [], [])
 fi
 # Check for the iptc_init symbol in the library.
+# This could be in iptc or ip4tc
 if test "x$with_libiptc" = "xpkgconfig"
 then
-       AC_CHECK_LIB(iptc, iptc_init,
+       AC_SEARCH_LIBS(iptc_init, [iptc ip4tc],
                        [with_libiptc="pkgconfig"],
                        [with_libiptc="no"],
                        [$with_libiptc_libs])
@@ -3350,26 +3352,39 @@ AC_ARG_WITH(librabbitmq, [AS_HELP_STRING([--with-librabbitmq@<:@=PREFIX@:>@], [P
 [
        with_librabbitmq="yes"
 ])
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
 if test "x$with_librabbitmq" = "xyes"
 then
-       SAVE_CPPFLAGS="$CPPFLAGS"
-       CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
-
        AC_CHECK_HEADERS(amqp.h, [with_librabbitmq="yes"], [with_librabbitmq="no (amqp.h not found)"])
-
-       CPPFLAGS="$SAVE_CPPFLAGS"
 fi
 if test "x$with_librabbitmq" = "xyes"
 then
-       SAVE_CPPFLAGS="$CPPFLAGS"
-       SAVE_LDFLAGS="$LDFLAGS"
-       CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
-       LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
-
+       # librabbitmq up to version 0.9.1 provides "library_errno", later
+       # versions use "library_error". The library does not provide a version
+       # macro :( Use "AC_CHECK_MEMBERS" (plural) for automatic defines.
+       AC_CHECK_MEMBERS([amqp_rpc_reply_t.library_errno],,,
+                        [
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_STDIO_H
+# include <stdio.h>
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#include <amqp.h>
+                         ])
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
        AC_CHECK_LIB(rabbitmq, amqp_basic_publish, [with_librabbitmq="yes"], [with_librabbitmq="no (Symbol 'amqp_basic_publish' not found)"])
-
-       CPPFLAGS="$SAVE_CPPFLAGS"
-       LDFLAGS="$SAVE_LDFLAGS"
 fi
 if test "x$with_librabbitmq" = "xyes"
 then
@@ -3381,6 +3396,8 @@ then
        AC_SUBST(BUILD_WITH_LIBRABBITMQ_LIBS)
        AC_DEFINE(HAVE_LIBRABBITMQ, 1, [Define if librabbitmq is present and usable.])
 fi
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
 AM_CONDITIONAL(BUILD_WITH_LIBRABBITMQ, test "x$with_librabbitmq" = "xyes")
 # }}}
 
index 5c2eb35d89540e0472332839915ce5e101c19c95..f106fa1a85641c7a02e95b1d3f34eb7a2947a789 100644 (file)
@@ -82,7 +82,7 @@ endif
 
 if BUILD_WITH_OWN_LIBOCONFIG
 collectd_LDADD += $(LIBLTDL) liboconfig/liboconfig.la
-collectd_DEPENDENCIES += $(LIBLTDL) liboconfig/liboconfig.la
+collectd_DEPENDENCIES += liboconfig/liboconfig.la
 else
 collectd_LDADD += -loconfig
 endif
index be1f709e120181efdf7ce8181c4f9032f02047ed..55d2a2ceff04f3772e43c21c4288ec6d97c1ddb2 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/amqp.c
- * Copyright (C) 2009  Sebastien Pahl
- * Copyright (C) 2010  Florian Forster
+ * Copyright (C) 2009       Sebastien Pahl
+ * Copyright (C) 2010-2012  Florian Forster
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -178,8 +178,13 @@ static char *camqp_strerror (camqp_config_t *conf, /* {{{ */
             break;
 
         case AMQP_RESPONSE_LIBRARY_EXCEPTION:
+#if HAVE_AMQP_RPC_REPLY_T_LIBRARY_ERRNO
             if (r.library_errno)
                 return (sstrerror (r.library_errno, buffer, buffer_size));
+#else
+            if (r.library_error)
+                return (sstrerror (r.library_error, buffer, buffer_size));
+#endif
             else
                 sstrncpy (buffer, "End of stream", sizeof (buffer));
             break;
@@ -216,6 +221,7 @@ static char *camqp_strerror (camqp_config_t *conf, /* {{{ */
     return (buffer);
 } /* }}} char *camqp_strerror */
 
+#if HAVE_AMQP_RPC_REPLY_T_LIBRARY_ERRNO
 static int camqp_create_exchange (camqp_config_t *conf) /* {{{ */
 {
     amqp_exchange_declare_ok_t *ed_ret;
@@ -246,6 +252,46 @@ static int camqp_create_exchange (camqp_config_t *conf) /* {{{ */
 
     return (0);
 } /* }}} int camqp_create_exchange */
+#else
+static int camqp_create_exchange (camqp_config_t *conf) /* {{{ */
+{
+    amqp_exchange_declare_ok_t *ed_ret;
+    amqp_table_t argument_table;
+    struct amqp_table_entry_t_ argument_table_entries[1];
+
+    if (conf->exchange_type == NULL)
+        return (0);
+
+    /* Valid arguments: "auto_delete", "internal" */
+    argument_table.num_entries = STATIC_ARRAY_SIZE (argument_table_entries);
+    argument_table.entries = argument_table_entries;
+    argument_table_entries[0].key = amqp_cstring_bytes ("auto_delete");
+    argument_table_entries[0].value.kind = AMQP_FIELD_KIND_BOOLEAN;
+    argument_table_entries[0].value.value.boolean = 1;
+
+    ed_ret = amqp_exchange_declare (conf->connection,
+            /* channel     = */ CAMQP_CHANNEL,
+            /* exchange    = */ amqp_cstring_bytes (conf->exchange),
+            /* type        = */ amqp_cstring_bytes (conf->exchange_type),
+            /* passive     = */ 0,
+            /* durable     = */ 0,
+            /* arguments   = */ argument_table);
+    if ((ed_ret == NULL) && camqp_is_error (conf))
+    {
+        char errbuf[1024];
+        ERROR ("amqp plugin: amqp_exchange_declare failed: %s",
+                camqp_strerror (conf, errbuf, sizeof (errbuf)));
+        camqp_close_connection (conf);
+        return (-1);
+    }
+
+    INFO ("amqp plugin: Successfully created exchange \"%s\" "
+            "with type \"%s\".",
+            conf->exchange, conf->exchange_type);
+
+    return (0);
+} /* }}} int camqp_create_exchange */
+#endif
 
 static int camqp_setup_queue (camqp_config_t *conf) /* {{{ */
 {
@@ -316,7 +362,9 @@ static int camqp_setup_queue (camqp_config_t *conf) /* {{{ */
             /* consumer_tag = */ AMQP_EMPTY_BYTES,
             /* no_local     = */ 0,
             /* no_ack       = */ 1,
-            /* exclusive    = */ 0);
+            /* exclusive    = */ 0,
+            /* arguments    = */ AMQP_EMPTY_TABLE
+        );
     if ((cm_ret == NULL) && camqp_is_error (conf))
     {
         char errbuf[1024];
index f89af084062a533a4dab052627bd3123c84a20bd..5fee0d00e7b292498aa8f3b47bfa0fd273052f2c 100644 (file)
@@ -2724,10 +2724,18 @@ The default IPv6 multicast group is C<ff18::efc0:4a42>. The default IPv4
 multicast group is C<239.192.74.66>. The default I<UDP> port is B<25826>.
 
 Both, B<Server> and B<Listen> can be used as single option or as block. When
-used as block, given options are valid for this socket only. For example:
+used as block, given options are valid for this socket only. The following
+example will export the metrics twice: Once to an "internal" server (without
+encryption and signing) and one to an external server (with cryptographic
+signature):
 
  <Plugin "network">
+   # Export to an internal server
+   # (demonstrates usage without additional options)
    Server "collectd.internal.tld"
+   
+   # Export to an external server
+   # (demonstrates usage with signature options)
    <Server "collectd.external.tld">
      SecurityLevel "sign"
      Username "myhostname"
@@ -5024,6 +5032,170 @@ number.
 
 =back
 
+=head1 THRESHOLD CONFIGURATION
+
+Starting with version C<4.3.0> collectd has support for B<monitoring>. By that
+we mean that the values are not only stored or sent somewhere, but that they
+are judged and, if a problem is recognized, acted upon. The only action
+collectd takes itself is to generate and dispatch a "notification". Plugins can
+register to receive notifications and perform appropriate further actions.
+
+Since systems and what you expect them to do differ a lot, you can configure
+B<thresholds> for your values freely. This gives you a lot of flexibility but
+also a lot of responsibility.
+
+Every time a value is out of range a notification is dispatched. This means
+that the idle percentage of your CPU needs to be less then the configured
+threshold only once for a notification to be generated. There's no such thing
+as a moving average or similar - at least not now.
+
+Also, all values that match a threshold are considered to be relevant or
+"interesting". As a consequence collectd will issue a notification if they are
+not received for B<Timeout> iterations. The B<Timeout> configuration option is
+explained in section L<"GLOBAL OPTIONS">. If, for example, B<Timeout> is set to
+"2" (the default) and some hosts sends it's CPU statistics to the server every
+60 seconds, a notification will be dispatched after about 120 seconds. It may
+take a little longer because the timeout is checked only once each B<Interval>
+on the server.
+
+When a value comes within range again or is received after it was missing, an
+"OKAY-notification" is dispatched.
+
+Here is a configuration example to get you started. Read below for more
+information.
+
+ <Threshold>
+   <Type "foo">
+     WarningMin    0.00
+     WarningMax 1000.00
+     FailureMin    0.00
+     FailureMax 1200.00
+     Invert false
+     Instance "bar"
+   </Type>
+
+   <Plugin "interface">
+     Instance "eth0"
+     <Type "if_octets">
+       FailureMax 10000000
+       DataSource "rx"
+     </Type>
+   </Plugin>
+
+   <Host "hostname">
+     <Type "cpu">
+       Instance "idle"
+       FailureMin 10
+     </Type>
+
+     <Plugin "memory">
+       <Type "memory">
+         Instance "cached"
+         WarningMin 100000000
+       </Type>
+     </Plugin>
+   </Host>
+ </Threshold>
+
+There are basically two types of configuration statements: The C<Host>,
+C<Plugin>, and C<Type> blocks select the value for which a threshold should be
+configured. The C<Plugin> and C<Type> blocks may be specified further using the
+C<Instance> option. You can combine the block by nesting the blocks, though
+they must be nested in the above order, i.E<nbsp>e. C<Host> may contain either
+C<Plugin> and C<Type> blocks, C<Plugin> may only contain C<Type> blocks and
+C<Type> may not contain other blocks. If multiple blocks apply to the same
+value the most specific block is used.
+
+The other statements specify the threshold to configure. They B<must> be
+included in a C<Type> block. Currently the following statements are recognized:
+
+=over 4
+
+=item B<FailureMax> I<Value>
+
+=item B<WarningMax> I<Value>
+
+Sets the upper bound of acceptable values. If unset defaults to positive
+infinity. If a value is greater than B<FailureMax> a B<FAILURE> notification
+will be created. If the value is greater than B<WarningMax> but less than (or
+equal to) B<FailureMax> a B<WARNING> notification will be created.
+
+=item B<FailureMin> I<Value>
+
+=item B<WarningMin> I<Value>
+
+Sets the lower bound of acceptable values. If unset defaults to negative
+infinity. If a value is less than B<FailureMin> a B<FAILURE> notification will
+be created. If the value is less than B<WarningMin> but greater than (or equal
+to) B<FailureMin> a B<WARNING> notification will be created.
+
+=item B<DataSource> I<DSName>
+
+Some data sets have more than one "data source". Interesting examples are the
+C<if_octets> data set, which has received (C<rx>) and sent (C<tx>) bytes and
+the C<disk_ops> data set, which holds C<read> and C<write> operations. The
+system load data set, C<load>, even has three data sources: C<shortterm>,
+C<midterm>, and C<longterm>.
+
+Normally, all data sources are checked against a configured threshold. If this
+is undesirable, or if you want to specify different limits for each data
+source, you can use the B<DataSource> option to have a threshold apply only to
+one data source.
+
+=item B<Invert> B<true>|B<false>
+
+If set to B<true> the range of acceptable values is inverted, i.E<nbsp>e.
+values between B<FailureMin> and B<FailureMax> (B<WarningMin> and
+B<WarningMax>) are not okay. Defaults to B<false>.
+
+=item B<Persist> B<true>|B<false>
+
+Sets how often notifications are generated. If set to B<true> one notification
+will be generated for each value that is out of the acceptable range. If set to
+B<false> (the default) then a notification is only generated if a value is out
+of range but the previous value was okay.
+
+This applies to missing values, too: If set to B<true> a notification about a
+missing value is generated once every B<Interval> seconds. If set to B<false>
+only one such notification is generated until the value appears again.
+
+=item B<Percentage> B<true>|B<false>
+
+If set to B<true>, the minimum and maximum values given are interpreted as
+percentage value, relative to the other data sources. This is helpful for
+example for the "df" type, where you may want to issue a warning when less than
+5E<nbsp>% of the total space is available. Defaults to B<false>.
+
+=item B<Hits> I<Number>
+
+Delay creating the notification until the threshold has been passed I<Number>
+times. When a notification has been generated, or when a subsequent value is
+inside the threshold, the counter is reset. If, for example, a value is
+collected once every 10E<nbsp>seconds and B<Hits> is set to 3, a notification
+will be dispatched at most once every 30E<nbsp>seconds.
+
+This is useful when short bursts are not a problem. If, for example, 100% CPU
+usage for up to a minute is normal (and data is collected every
+10E<nbsp>seconds), you could set B<Hits> to B<6> to account for this.
+
+=item B<Hysteresis> I<Number>
+
+When set to non-zero, a hysteresis value is applied when checking minimum and
+maximum bounds. This is useful for values that increase slowly and fluctuate a
+bit while doing so. When these values come close to the threshold, they may
+"flap", i.e. switch between failure / warning case and okay case repeatedly.
+
+If, for example, the threshold is configures as
+
+  WarningMax 100.0
+  Hysteresis 1.0
+
+then a I<Warning> notification is created when the value exceeds I<101> and the
+corresponding I<Okay> notification is only created once the value falls below
+I<99>, thus avoiding the "flapping".
+
+=back
+
 =head1 FILTER CONFIGURATION
 
 Starting with collectd 4.6 there is a powerful filtering infrastructure
index 0069a8b6508691b4fd2270642d10452428606fc4..459c7024bb2bcb9824c0c131d5ea10a9e50845d4 100644 (file)
@@ -953,9 +953,25 @@ int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
        return (0);
 } /* }}} int parse_identifier_vl */
 
-int parse_value (const char *value, value_t *ret_value, int ds_type)
+int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
 {
+  char *value;
   char *endptr = NULL;
+  size_t value_len;
+
+  if (value_orig == NULL)
+    return (EINVAL);
+
+  value = strdup (value_orig);
+  if (value == NULL)
+    return (ENOMEM);
+  value_len = strlen (value);
+
+  while ((value_len > 0) && isspace ((int) value[value_len - 1]))
+  {
+    value[value_len - 1] = 0;
+    value_len--;
+  }
 
   switch (ds_type)
   {
@@ -976,11 +992,13 @@ int parse_value (const char *value, value_t *ret_value, int ds_type)
       break;
 
     default:
+      sfree (value);
       ERROR ("parse_value: Invalid data source type: %i.", ds_type);
       return -1;
   }
 
   if (value == endptr) {
+    sfree (value);
     ERROR ("parse_value: Failed to parse string as %s: %s.",
         DS_TYPE_TO_STRING (ds_type), value);
     return -1;
@@ -988,8 +1006,9 @@ int parse_value (const char *value, value_t *ret_value, int ds_type)
   else if ((NULL != endptr) && ('\0' != *endptr))
     INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
         "Input string was \"%s\".",
-        endptr, DS_TYPE_TO_STRING (ds_type), value);
+        endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
 
+  sfree (value);
   return 0;
 } /* int parse_value */
 
index e6b899de5c8114b26c0413f980056dbbd9b91c0d..6b11b538db8a69ef001e7e7b28843d519d9ebe6b 100644 (file)
@@ -287,6 +287,7 @@ typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
                void *user_data);
 int walk_directory (const char *dir, dirwalk_callback_f callback,
                void *user_data, int hidden);
+/* Returns the number of bytes read or negative on error. */
 int read_file_contents (const char *filename, char *buf, int bufsize);
 
 counter_t counter_diff (counter_t old_value, counter_t new_value);
index e70ff5f1834b5deecc53bfe7f0419176ce564eeb..33236c45975c4d9c5c519e4defbfcd029c0b0821 100644 (file)
 
 #define CONNTRACK_FILE "/proc/sys/net/netfilter/nf_conntrack_count"
 
-static void conntrack_submit (double conntrack)
+static void conntrack_submit (value_t conntrack)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = conntrack;
-
-       vl.values = values;
+       vl.values = &conntrack;
        vl.values_len = 1;
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "conntrack", sizeof (vl.plugin));
@@ -49,14 +46,16 @@ static void conntrack_submit (double conntrack)
 
 static int conntrack_read (void)
 {
-       double conntrack;
+       value_t conntrack;
        FILE *fh;
        char buffer[64];
+       size_t buffer_len;
 
        fh = fopen (CONNTRACK_FILE, "r");
        if (fh == NULL)
                return (-1);
 
+       memset (buffer, 0, sizeof (buffer));
        if (fgets (buffer, sizeof (buffer), fh) == NULL)
        {
                fclose (fh);
@@ -64,10 +63,18 @@ static int conntrack_read (void)
        }
        fclose (fh);
 
-       conntrack = atof (buffer);
+       /* strip trailing newline. */
+       buffer_len = strlen (buffer);
+       while ((buffer_len > 0) && isspace ((int) buffer[buffer_len - 1]))
+       {
+               buffer[buffer_len - 1] = 0;
+               buffer_len--;
+       }
+
+       if (parse_value (buffer, &conntrack, DS_TYPE_GAUGE) != 0)
+               return (-1);
 
-       if (conntrack > 0.0)
-               conntrack_submit (conntrack);
+       conntrack_submit (conntrack);
 
        return (0);
 } /* static int conntrack_read */
index d13decdbade29a13a25af36c79148187990fcef6..2adf6d48821d49590bde1186dd8c047c78eaa17a 100644 (file)
@@ -780,6 +780,8 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
   if (ret_values_names != NULL)
     *ret_values_names = values_names;
 
+  lcc_response_free (&res);
+
   return (0);
 } /* }}} int lcc_getval */
 
index ee3dbe12d67c4998b3ac65ede2f808016370023f..48fa713b8dbbe3aebf83f7130cf3988d18717dd3 100644 (file)
@@ -357,7 +357,7 @@ static void submit_gauge2 (const char *type, const char *type_inst,
 
 static int memcached_read (void) /* {{{ */
 {
-       char buf[1024];
+       char buf[4096];
        char *fields[3];
        char *ptr;
        char *line;
index e0c329c6f0abae9f10231a08f14fb08d72cfab90..5fed1b196933a5bb00d39d8e9f3c9d828930bd84 100644 (file)
@@ -352,6 +352,43 @@ static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
   return (!received);
 } /* }}} _Bool check_send_okay */
 
+static _Bool check_notify_received (const notification_t *n) /* {{{ */
+{
+  notification_meta_t *ptr;
+
+  for (ptr = n->meta; ptr != NULL; ptr = ptr->next)
+    if ((strcmp ("network:received", ptr->name) == 0)
+        && (ptr->type == NM_TYPE_BOOLEAN))
+      return ((_Bool) ptr->nm_value.nm_boolean);
+
+  return (0);
+} /* }}} _Bool check_notify_received */
+
+static _Bool check_send_notify_okay (const notification_t *n) /* {{{ */
+{
+  static c_complain_t complain_forwarding = C_COMPLAIN_INIT_STATIC;
+  _Bool received = 0;
+
+  if (n->meta == NULL)
+    return (1);
+
+  received = check_notify_received (n);
+
+  if (network_config_forward && received)
+  {
+    c_complain_once (LOG_ERR, &complain_forwarding,
+        "network plugin: A notification has been received via the network "
+        "forwarding if enabled. Forwarding of notifications is currently "
+        "not supported, because there is not loop-deteciton available. "
+        "Please contact the collectd mailing list if you need this "
+        "feature.");
+  }
+
+  /* By default, only *send* value lists that were not *received* by the
+   * network plugin. */
+  return (!received);
+} /* }}} _Bool check_send_notify_okay */
+
 static int network_dispatch_values (value_list_t *vl, /* {{{ */
     const char *username)
 {
@@ -415,6 +452,29 @@ static int network_dispatch_values (value_list_t *vl, /* {{{ */
   return (0);
 } /* }}} int network_dispatch_values */
 
+static int network_dispatch_notification (notification_t *n) /* {{{ */
+{
+  int status;
+
+  assert (n->meta == NULL);
+
+  status = plugin_notification_meta_add_boolean (n, "network:received", 1);
+  if (status != 0)
+  {
+    ERROR ("network plugin: plugin_notification_meta_add_boolean failed.");
+    plugin_notification_meta_free (n->meta);
+    n->meta = NULL;
+    return (status);
+  }
+
+  status = plugin_dispatch_notification (n);
+
+  plugin_notification_meta_free (n->meta);
+  n->meta = NULL;
+
+  return (status);
+} /* }}} int network_dispatch_notification */
+
 #if HAVE_LIBGCRYPT
 static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */
     const void *iv, size_t iv_size, const char *username)
@@ -705,7 +765,7 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
 
        exp_size = 3 * sizeof (uint16_t)
                + pkg_numval * (sizeof (uint8_t) + sizeof (value_t));
-       if ((buffer_len < 0) || (buffer_len < exp_size))
+       if (buffer_len < exp_size)
        {
                WARNING ("network plugin: parse_part_values: "
                                "Packet too short: "
@@ -790,7 +850,7 @@ static int parse_part_number (void **ret_buffer, size_t *ret_buffer_len,
 
        uint16_t pkg_length;
 
-       if ((buffer_len < 0) || ((size_t) buffer_len < exp_size))
+       if (buffer_len < exp_size)
        {
                WARNING ("network plugin: parse_part_number: "
                                "Packet too short: "
@@ -829,7 +889,7 @@ static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
 
        uint16_t pkg_length;
 
-       if ((buffer_len < 0) || (buffer_len < header_size))
+       if (buffer_len < header_size)
        {
                WARNING ("network plugin: parse_part_string: "
                                "Packet too short: "
@@ -1484,7 +1544,7 @@ static int parse_packet (sockent_t *se, /* {{{ */
                        }
                        else
                        {
-                               plugin_dispatch_notification (&n);
+                               network_dispatch_notification (&n);
                        }
                }
                else if (pkg_type == TYPE_SEVERITY)
@@ -3087,14 +3147,17 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
 } /* }}} int network_config */
 
 static int network_notification (const notification_t *n,
-               user_data_t __attribute__((unused)) *user_data)
+    user_data_t __attribute__((unused)) *user_data)
 {
   char  buffer[network_config_packet_size];
   char *buffer_ptr = buffer;
   int   buffer_free = sizeof (buffer);
   int   status;
 
-  memset (buffer, '\0', sizeof (buffer));
+  if (!check_send_notify_okay (n))
+    return (0);
+
+  memset (buffer, 0, sizeof (buffer));
 
   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME_HR,
       (uint64_t) n->time);
@@ -3109,7 +3172,7 @@ static int network_notification (const notification_t *n,
   if (strlen (n->host) > 0)
   {
     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
-       n->host, strlen (n->host));
+        n->host, strlen (n->host));
     if (status != 0)
       return (-1);
   }
@@ -3117,7 +3180,7 @@ static int network_notification (const notification_t *n,
   if (strlen (n->plugin) > 0)
   {
     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
-       n->plugin, strlen (n->plugin));
+        n->plugin, strlen (n->plugin));
     if (status != 0)
       return (-1);
   }
@@ -3125,8 +3188,8 @@ static int network_notification (const notification_t *n,
   if (strlen (n->plugin_instance) > 0)
   {
     status = write_part_string (&buffer_ptr, &buffer_free,
-       TYPE_PLUGIN_INSTANCE,
-       n->plugin_instance, strlen (n->plugin_instance));
+        TYPE_PLUGIN_INSTANCE,
+        n->plugin_instance, strlen (n->plugin_instance));
     if (status != 0)
       return (-1);
   }
@@ -3134,7 +3197,7 @@ static int network_notification (const notification_t *n,
   if (strlen (n->type) > 0)
   {
     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
-       n->type, strlen (n->type));
+        n->type, strlen (n->type));
     if (status != 0)
       return (-1);
   }
@@ -3142,7 +3205,7 @@ static int network_notification (const notification_t *n,
   if (strlen (n->type_instance) > 0)
   {
     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
-       n->type_instance, strlen (n->type_instance));
+        n->type_instance, strlen (n->type_instance));
     if (status != 0)
       return (-1);
   }
index f8a482275d89bde294344222b060294cdaa8b3e6..a2568da2621fb8f7ea79445f199f7171822f6abb 100644 (file)
@@ -1929,6 +1929,11 @@ static int perl_read (void)
                aTHX = t->interp;
        }
 
+       /* Assert that we're not running as the base thread. Otherwise, we might
+        * run into concurrency issues with c_ithread_create(). See
+        * https://github.com/collectd/collectd/issues/9 for details. */
+       assert (aTHX != perl_threads->head->interp);
+
        log_debug ("perl_read: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
        return pplugin_call_all (aTHX_ PLUGIN_READ);
@@ -1937,6 +1942,7 @@ static int perl_read (void)
 static int perl_write (const data_set_t *ds, const value_list_t *vl,
                user_data_t __attribute__((unused)) *user_data)
 {
+       int status;
        dTHX;
 
        if (NULL == perl_threads)
@@ -1952,9 +1958,20 @@ static int perl_write (const data_set_t *ds, const value_list_t *vl,
                aTHX = t->interp;
        }
 
+       /* Lock the base thread if this is not called from one of the read threads
+        * to avoid race conditions with c_ithread_create(). See
+        * https://github.com/collectd/collectd/issues/9 for details. */
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_lock (&perl_threads->mutex);
+
        log_debug ("perl_write: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
-       return pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl);
+       status = pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl);
+
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_unlock (&perl_threads->mutex);
+
+       return status;
 } /* static int perl_write (const data_set_t *, const value_list_t *) */
 
 static void perl_log (int level, const char *msg,
@@ -1975,7 +1992,17 @@ static void perl_log (int level, const char *msg,
                aTHX = t->interp;
        }
 
+       /* Lock the base thread if this is not called from one of the read threads
+        * to avoid race conditions with c_ithread_create(). See
+        * https://github.com/collectd/collectd/issues/9 for details. */
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_lock (&perl_threads->mutex);
+
        pplugin_call_all (aTHX_ PLUGIN_LOG, level, msg);
+
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_unlock (&perl_threads->mutex);
+
        return;
 } /* static void perl_log (int, const char *) */
 
index 518419f4c79d1955d05ed5c906c18c86604f593a..66237dc376be56414b29d62000d8a39c6fd70e1b 100644 (file)
@@ -881,9 +881,12 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        char *fields[64];
        char  fields_len;
 
-       int   i;
+       int   buffer_len;
 
-       int   name_len;
+       char *buffer_ptr;
+       size_t name_start_pos;
+       size_t name_end_pos;
+       size_t name_len;
 
        derive_t cpu_user_counter;
        derive_t cpu_system_counter;
@@ -895,33 +898,56 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
 
        ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
 
-       i = read_file_contents (filename, buffer, sizeof(buffer) - 1);
-       if (i <= 0)
+       buffer_len = read_file_contents (filename,
+                       buffer, sizeof(buffer) - 1);
+       if (buffer_len <= 0)
                return (-1);
-       buffer[i] = 0;
-
-       fields_len = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
-       if (fields_len < 24)
+       buffer[buffer_len] = 0;
+
+       /* The name of the process is enclosed in parens. Since the name can
+        * contain parens itself, spaces, numbers and pretty much everything
+        * else, use these to determine the process name. We don't use
+        * strchr(3) and strrchr(3) to avoid pointer arithmetic which would
+        * otherwise be required to determine name_len. */
+       name_start_pos = 0;
+       while ((buffer[name_start_pos] != '(')
+                       && (name_start_pos < buffer_len))
+               name_start_pos++;
+
+       name_end_pos = buffer_len;
+       while ((buffer[name_end_pos] != ')')
+                       && (name_end_pos > 0))
+               name_end_pos--;
+
+       /* Either '(' or ')' is not found or they are in the wrong order.
+        * Anyway, something weird that shouldn't happen ever. */
+       if (name_start_pos >= name_end_pos)
        {
-               DEBUG ("processes plugin: ps_read_process (pid = %i):"
-                               " `%s' has only %i fields..",
-                               (int) pid, filename, fields_len);
+               ERROR ("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
+                               name_start_pos, name_end_pos);
                return (-1);
        }
 
-       /* copy the name, strip brackets in the process */
-       name_len = strlen (fields[1]) - 2;
-       if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')'))
+       name_len = (name_end_pos - name_start_pos) - 1;
+       if (name_len >= sizeof (ps->name))
+               name_len = sizeof (ps->name) - 1;
+
+       sstrncpy (ps->name, &buffer[name_start_pos + 1], name_len + 1);
+
+       if ((buffer_len - name_end_pos) < 2)
+               return (-1);
+       buffer_ptr = &buffer[name_end_pos + 2];
+
+       fields_len = strsplit (buffer_ptr, fields, STATIC_ARRAY_SIZE (fields));
+       if (fields_len < 22)
        {
-               DEBUG ("No brackets found in process name: `%s'", fields[1]);
+               DEBUG ("processes plugin: ps_read_process (pid = %i):"
+                               " `%s' has only %i fields..",
+                               (int) pid, filename, fields_len);
                return (-1);
        }
-       fields[1] = fields[1] + 1;
-       fields[1][name_len] = '\0';
-       strncpy (ps->name, fields[1], PROCSTAT_NAME_LEN);
-
 
-       *state = fields[2][0];
+       *state = fields[0][0];
 
        if (*state == 'Z')
        {
@@ -946,16 +972,16 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
                return (0);
        }
 
-       cpu_user_counter   = atoll (fields[13]);
-       cpu_system_counter = atoll (fields[14]);
-       vmem_size          = atoll (fields[22]);
-       vmem_rss           = atoll (fields[23]);
-       ps->vmem_minflt_counter = atoll (fields[9]);
-       ps->vmem_majflt_counter = atoll (fields[11]);
+       cpu_user_counter   = atoll (fields[11]);
+       cpu_system_counter = atoll (fields[12]);
+       vmem_size          = atoll (fields[20]);
+       vmem_rss           = atoll (fields[21]);
+       ps->vmem_minflt_counter = atol (fields[7]);
+       ps->vmem_majflt_counter = atol (fields[9]);
 
        {
-               unsigned long long stack_start = atoll (fields[27]);
-               unsigned long long stack_ptr   = atoll (fields[28]);
+               unsigned long long stack_start = atoll (fields[25]);
+               unsigned long long stack_ptr   = atoll (fields[26]);
 
                stack_size = (stack_start > stack_ptr)
                        ? stack_start - stack_ptr
index 7a8485113289f16923a14f491537c16b2aa5ac79..160687f0ab56aad17116f5a198155f3f03e3652b 100644 (file)
@@ -709,7 +709,9 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
   value_t ret;
   uint64_t tmp_unsigned = 0;
   int64_t tmp_signed = 0;
-  int defined = 1;
+  _Bool defined = 1;
+  /* Set to true when the original SNMP type appears to have been signed. */
+  _Bool prefer_signed = 0;
 
   if ((vl->type == ASN_INTEGER)
       || (vl->type == ASN_UINTEGER)
@@ -721,7 +723,12 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
   {
     tmp_unsigned = (uint32_t) *vl->val.integer;
     tmp_signed = (int32_t) *vl->val.integer;
-    DEBUG ("snmp plugin: Parsed int32 value is %"PRIi64".", tmp_signed);
+
+    if ((vl->type == ASN_INTEGER)
+        || (vl->type == ASN_GAUGE))
+      prefer_signed = 1;
+
+    DEBUG ("snmp plugin: Parsed int32 value is %"PRIu64".", tmp_unsigned);
   }
   else if (vl->type == ASN_COUNTER64)
   {
@@ -813,14 +820,24 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
   }
   else if (type == DS_TYPE_GAUGE)
   {
-    ret.gauge = NAN;
-    if (defined != 0)
+    if (!defined)
+      ret.gauge = NAN;
+    else if (prefer_signed)
       ret.gauge = (scale * tmp_signed) + shift;
+    else
+      ret.gauge = (scale * tmp_unsigned) + shift;
   }
   else if (type == DS_TYPE_DERIVE)
-    ret.derive = (derive_t) tmp_signed;
+  {
+    if (prefer_signed)
+      ret.derive = (derive_t) tmp_signed;
+    else
+      ret.derive = (derive_t) tmp_unsigned;
+  }
   else if (type == DS_TYPE_ABSOLUTE)
+  {
     ret.absolute = (absolute_t) tmp_unsigned;
+  }
   else
   {
     ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source "
index 6a7e32d72007e216ff739bd491e6e34a6abefe11..3c8fc7285e2621c57fa5f3779d08df70e8ed7179 100644 (file)
 # include <netinet/tcp_var.h>
 # include <netdb.h>
 # include <arpa/inet.h>
-# include <nlist.h>
+# if !defined(HAVE_BSD_NLIST_H) || !HAVE_BSD_NLIST_H
+#  include <nlist.h>
+# else /* HAVE_BSD_NLIST_H */
+#  include <bsd/nlist.h>
+# endif
 # include <kvm.h>
 /* #endif HAVE_LIBKVM_NLIST */
 
index 23c471d4ad5bdd5d9cf68a3ea0fdd918ea24b7e3..9d4aaac61330c687b44f7e9e07a5812ae9036ffa 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-DEFAULT_VERSION="5.0.3.git"
+DEFAULT_VERSION="5.0.4.git"
 
 VERSION="`git describe 2> /dev/null | sed -e 's/^collectd-//'`"