Merge branch 'collectd-5.4'
authorMarc Fournier <marc.fournier@camptocamp.com>
Mon, 24 Nov 2014 08:44:45 +0000 (09:44 +0100)
committerMarc Fournier <marc.fournier@camptocamp.com>
Mon, 24 Nov 2014 08:44:45 +0000 (09:44 +0100)
Conflicts:
src/Makefile.am
src/cpu.c
src/swap.c
src/write_redis.c

NB: dropped change to src/swap.c made in 1a146775d4, as suggested in the
commit message.

contrib/exec-nagios.px
contrib/redhat/init.d-collectd
src/collectd.conf.in
src/collectd.conf.pod
src/cpu.c
src/curl_json.c
src/daemon/common.c
src/daemon/filter_chain.c
src/daemon/plugin.c
src/write_graphite.c

index c7f18c5..ec13b0a 100755 (executable)
@@ -442,7 +442,7 @@ sub execute_script
 
   close ($fh);
   # Save the exit status of the check in $state
-  $state = $?;
+  $state = $? >> 8;
 
   if ($state == 0)
   {
index abdb168..4c69f3c 100644 (file)
@@ -21,6 +21,8 @@ COLLECTD=/usr/sbin/collectd
 COLLECTDMONPIDDIR="/var/run"
 COLLECTDMONPID="$COLLECTDMONPIDDIR/collectdmon.pid"
 
+MAXWAIT=30
+
 if [ -r /etc/sysconfig/$service ]; then
        . /etc/sysconfig/$service
 fi
@@ -58,7 +60,7 @@ start () {
 }
 stop () {
        echo -n $"Stopping collectd: "
-       killproc -p $COLLECTDMONPID $prog
+       killproc -p $COLLECTDMONPID -d $MAXWAIT $prog
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$service
index 5196979..a25cce5 100644 (file)
 #</Plugin>
 
 #<Plugin curl_json>
+#  <URL "http://localhost:80/test.json">
+#    Instance "test_http_json"
+#    <Key "testArray/0">
+#      Type "gauge"
+#      # Expect: 1
+#    </Key>
+#    <Key "testArray/1">
+#      Type "gauge"
+#      # Expect: 2
+#    </Key>
+#    <Key "testArrayInbetween/0/blarg">
+#      Type "gauge"
+#      # Expect: 3
+#    </Key>
+#    <Key "testArrayInbetween/1/blub">
+#      Type "gauge"
+#      # Expect: 4
+#    </Key>
+#    <Key "testDirectHit">
+#      Type "gauge"
+#      # Expect: 5
+#    </Key>
+#    <Key "testSubLevelHit/oneMoreLevel">
+#      Type "gauge"
+#      # Expect: 6
+#    </Key>
+#  </URL>
+# put this as test.json on your webserver, the above config demonstraces
+# how to match them.
+# {
+#  "testArray":[1,2],
+#  "testArrayInbetween":[{"blarg":3},{"blub":4}],
+#  "testDirectHit":5,
+#  "testSubLevelHit":{"oneMoreLevel":6}
+# }
 ## See: http://wiki.apache.org/couchdb/Runtime_Statistics
 #  <URL "http://localhost:5984/_stats">
 #    Instance "httpd"
 #  DeleteGauges   false
 #  DeleteSets     false
 #  TimerPercentile 90.0
+#  TimerPercentile 95.0
+#  TimerPercentile 99.0
+#  TimerLower     false
+#  TimerUpper     false
+#  TimerSum       false
+#  TimerCount     false
 #</Plugin>
 
 #<Plugin swap>
index 20c6126..a65d432 100644 (file)
@@ -5812,7 +5812,20 @@ that I<Percent> of all reported timers are smaller than or equal to the
 computed latency. This is useful for cutting off the long tail latency, as it's
 often done in I<Service Level Agreements> (SLAs).
 
-If not specified, no percentile is calculated / dispatched.
+Different percentiles can be calculated by setting this option several times.
+If none are specified, no percentiles are calculated / dispatched.
+
+=item B<TimerLower> B<false>|B<true>
+
+=item B<TimerUpper> B<false>|B<true>
+
+=item B<TimerSum> B<false>|B<true>
+
+=item B<TimerCount> B<false>|B<true>
+
+Calculate and dispatch various values out of I<Timer> metrics received during
+an interval. If set to B<False>, the default, these values aren't calculated /
+dispatched.
 
 =back
 
@@ -7105,6 +7118,61 @@ want to set B<metadata.broker.list> to your Kafka broker list.
 
 =back
 
+=head2 Plugin C<write_redis>
+
+The I<write_redis plugin> submits values to I<Redis>, a data structure server.
+
+Synopsis:
+
+  <Plugin "write_redis">
+    <Node "example">
+        Host "localhost"
+        Port "6379"
+        Timeout 1000
+    </Node>
+  </Plugin>
+
+Values are submitted to I<Sorted Sets>, using the metric name as the key, and
+the timestamp as the score. Retrieving a date range can then be done using the
+C<ZRANGEBYSCORE> I<Redis> command. Additionnally, all the identifiers of these
+I<Sorted Sets> are kept in a I<Set> called C<collectd/values> and can be
+retrieved using the C<SMEMBERS> I<Redis> command. See
+L<http://redis.io/commands#sorted_set> and L<http://redis.io/commands#set> for
+details.
+
+The information shown in the synopsis above is the I<default configuration>
+which is used by the plugin if no configuration is present.
+
+The plugin can send values to multiple instances of I<Redis> by specifying
+one B<Node> block for each instance. Within the B<Node> blocks, the following
+options are available:
+
+=over 4
+
+=item B<Node> I<Nodename>
+
+The B<Node> block identifies a new I<Redis> node, that is a new I<Redis>
+instance running in an specified host and port. The name for node is a
+canonical identifier which is used as I<plugin instance>. It is limited to
+64E<nbsp>characters in length.
+
+=item B<Host> I<Hostname>
+
+The B<Host> option is the hostname or IP-address where the I<Redis> instance is
+running on.
+
+=item B<Port> I<Port>
+
+The B<Port> option is the TCP port on which the Redis instance accepts
+connections. Either a service name of a port number may be given. Please note
+that numerical port numbers must be given as a string, too.
+
+=item B<Timeout> I<Timeout in miliseconds>
+
+The B<Timeout> option sets the socket connection timeout, in milliseconds.
+
+=back
+
 =head2 Plugin C<write_riemann>
 
 The I<write_riemann plugin> will send values to I<Riemann>, a powerful stream
index d1978f9..2fb4918 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -131,12 +131,6 @@ static const char *cpu_state_names[] = {
 static mach_port_t port_host;
 static processor_port_array_t cpu_list;
 static mach_msg_type_number_t cpu_list_len;
-
-#if PROCESSOR_TEMPERATURE
-static int cpu_temp_retry_counter = 0;
-static int cpu_temp_retry_step    = 1;
-static int cpu_temp_retry_max     = 1;
-#endif /* PROCESSOR_TEMPERATURE */
 /* #endif PROCESSOR_CPU_LOAD_INFO */
 
 #elif defined(KERNEL_LINUX)
@@ -222,7 +216,7 @@ static int cpu_config (char const *key, char const *value) /* {{{ */
 
 static int init (void)
 {
-#if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
+#if PROCESSOR_CPU_LOAD_INFO
        kern_return_t status;
 
        port_host = mach_host_self ();
@@ -577,33 +571,27 @@ static int cpu_read (void)
 {
        cdtime_t now = cdtime ();
 
-#if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE /* {{{ */
+#if PROCESSOR_CPU_LOAD_INFO /* {{{ */
        int cpu;
 
        kern_return_t status;
 
-#if PROCESSOR_CPU_LOAD_INFO
        processor_cpu_load_info_data_t cpu_info;
        mach_msg_type_number_t         cpu_info_len;
-#endif
-#if PROCESSOR_TEMPERATURE
-       processor_info_data_t          cpu_temp;
-       mach_msg_type_number_t         cpu_temp_len;
-#endif
 
        host_t cpu_host;
 
        for (cpu = 0; cpu < cpu_list_len; cpu++)
        {
-#if PROCESSOR_CPU_LOAD_INFO
                cpu_host = 0;
                cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
 
-               if ((status = processor_info (cpu_list[cpu],
-                                               PROCESSOR_CPU_LOAD_INFO, &cpu_host,
-                                               (processor_info_t) &cpu_info, &cpu_info_len)) != KERN_SUCCESS)
+               status = processor_info (cpu_list[cpu], PROCESSOR_CPU_LOAD_INFO, &cpu_host,
+                               (processor_info_t) &cpu_info, &cpu_info_len);
+               if (status != KERN_SUCCESS)
                {
-                       ERROR ("cpu plugin: processor_info failed with status %i", (int) status);
+                       ERROR ("cpu plugin: processor_info (PROCESSOR_CPU_LOAD_INFO) failed: %s",
+                                       mach_error_string (status));
                        continue;
                }
 
@@ -617,50 +605,6 @@ static int cpu_read (void)
                cpu_stage (cpu, CPU_STATE_NICE,   (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE],   now);
                cpu_stage (cpu, CPU_STATE_SYSTEM, (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM], now);
                cpu_stage (cpu, CPU_STATE_IDLE,   (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE],   now);
-#endif /* PROCESSOR_CPU_LOAD_INFO */
-
-#if PROCESSOR_TEMPERATURE
-               /*
-                * Not all Apple computers do have this ability. To minimize
-                * the messages sent to the syslog we do an exponential
-                * stepback if `processor_info' fails. We still try ~once a day
-                * though..
-                */
-               if (cpu_temp_retry_counter > 0)
-               {
-                       cpu_temp_retry_counter--;
-                       continue;
-               }
-
-               cpu_temp_len = PROCESSOR_INFO_MAX;
-
-               status = processor_info (cpu_list[cpu],
-                               PROCESSOR_TEMPERATURE,
-                               &cpu_host,
-                               cpu_temp, &cpu_temp_len);
-               if (status != KERN_SUCCESS)
-               {
-                       ERROR ("cpu plugin: processor_info failed: %s",
-                                       mach_error_string (status));
-
-                       cpu_temp_retry_counter = cpu_temp_retry_step;
-                       cpu_temp_retry_step *= 2;
-                       if (cpu_temp_retry_step > cpu_temp_retry_max)
-                               cpu_temp_retry_step = cpu_temp_retry_max;
-
-                       continue;
-               }
-
-               if (cpu_temp_len != 1)
-               {
-                       DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
-                                       (int) cpu_temp_len);
-                       continue;
-               }
-
-               cpu_temp_retry_counter = 0;
-               cpu_temp_retry_step    = 1;
-#endif /* PROCESSOR_TEMPERATURE */
        }
 /* }}} #endif PROCESSOR_CPU_LOAD_INFO */
 
index 8a084fe..e99500a 100644 (file)
@@ -234,9 +234,14 @@ static int cj_cb_number (void *ctx,
     if (key != NULL)
       NOTICE ("curl_json plugin: Found \"%s\", but the configuration expects"
               " a map.", buffer);
-    cj_cb_inc_array_index (ctx, /* update_key = */ 0);
-    return (CJ_CB_CONTINUE);
-  } else {
+    cj_cb_inc_array_index (ctx, /* update_key = */ 1);
+    key = db->state[db->depth].key;
+    if (key == NULL) {
+      return (CJ_CB_CONTINUE);
+    }
+  }
+  else
+  {
     cj_cb_inc_array_index (ctx, /* update_key = */ 1);
   }
 
@@ -276,10 +281,21 @@ static int cj_cb_map_key (void *ctx,
     memcpy (name, in_name, name_len);
     name[name_len] = 0;
 
-    if (c_avl_get (tree, name, (void *) &value) == 0)
-      db->state[db->depth].key = value;
+    if (c_avl_get (tree, name, (void *) &value) == 0) {
+      if (CJ_IS_KEY((cj_key_t*)value)) {
+        db->state[db->depth].key = value;
+      }
+      else {
+        db->state[db->depth].tree = (c_avl_tree_t*) value;
+      }
+    }
     else if (c_avl_get (tree, CJ_ANY, (void *) &value) == 0)
-      db->state[db->depth].key = value;
+      if (CJ_IS_KEY((cj_key_t*)value)) {
+        db->state[db->depth].key = value;
+      }
+      else {
+        db->state[db->depth].tree = (c_avl_tree_t*) value;
+      }
     else
       db->state[db->depth].key = NULL;
   }
index 535dfad..e2b618f 100644 (file)
@@ -475,8 +475,8 @@ size_t strstripnewline (char *buffer)
                if ((buffer[buffer_len - 1] != '\n')
                                && (buffer[buffer_len - 1] != '\r'))
                        break;
-               buffer[buffer_len] = 0;
                buffer_len--;
+               buffer[buffer_len] = 0;
        }
 
        return (buffer_len);
index c87b877..b93435f 100644 (file)
@@ -78,6 +78,15 @@ struct fc_chain_s /* {{{ */
   fc_chain_t  *next;
 }; /* }}} */
 
+/* Writer configuration. */
+struct fc_writer_s;
+typedef struct fc_writer_s fc_writer_t; /* {{{ */
+struct fc_writer_s
+{
+  char *plugin;
+  c_complain_t complaint;
+}; /* }}} */
+
 /*
  * Global variables
  */
@@ -627,16 +636,13 @@ static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
 {
   int i;
 
-  char **plugin_list;
-  size_t plugin_list_len;
-
-  plugin_list = NULL;
-  plugin_list_len = 0;
+  fc_writer_t *plugin_list = NULL;
+  size_t plugin_list_len = 0;
 
   for (i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *child = ci->children + i;
-    char **temp;
+    fc_writer_t *temp;
     int j;
 
     if (strcasecmp ("Plugin", child->key) != 0)
@@ -649,14 +655,17 @@ static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
 
     for (j = 0; j < child->values_num; j++)
     {
+      char *plugin;
+
       if (child->values[j].type != OCONFIG_TYPE_STRING)
       {
         ERROR ("Filter subsystem: Built-in target `write': "
             "The `Plugin' option accepts only string arguments.");
         continue;
       }
+      plugin = child->values[j].value.string;
 
-      temp = (char **) realloc (plugin_list, (plugin_list_len + 2)
+      temp = (fc_writer_t *) realloc (plugin_list, (plugin_list_len + 2)
           * (sizeof (*plugin_list)));
       if (temp == NULL)
       {
@@ -665,14 +674,15 @@ static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
       }
       plugin_list = temp;
 
-      plugin_list[plugin_list_len] = fc_strdup (child->values[j].value.string);
-      if (plugin_list[plugin_list_len] == NULL)
+      plugin_list[plugin_list_len].plugin = fc_strdup (plugin);
+      if (plugin_list[plugin_list_len].plugin == NULL)
       {
         ERROR ("fc_bit_write_create: fc_strdup failed.");
         continue;
       }
+      C_COMPLAIN_INIT (&plugin_list[plugin_list_len].complaint);
       plugin_list_len++;
-      plugin_list[plugin_list_len] = NULL;
+      plugin_list[plugin_list_len].plugin = NULL;
     } /* for (j = 0; j < child->values_num; j++) */
   } /* for (i = 0; i < ci->children_num; i++) */
 
@@ -683,7 +693,7 @@ static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
 
 static int fc_bit_write_destroy (void **user_data) /* {{{ */
 {
-  char **plugin_list;
+  fc_writer_t *plugin_list;
   size_t i;
 
   if ((user_data == NULL) || (*user_data == NULL))
@@ -691,8 +701,8 @@ static int fc_bit_write_destroy (void **user_data) /* {{{ */
 
   plugin_list = *user_data;
 
-  for (i = 0; plugin_list[i] != NULL; i++)
-    free (plugin_list[i]);
+  for (i = 0; plugin_list[i].plugin != NULL; i++)
+    free (plugin_list[i].plugin);
   free (plugin_list);
 
   return (0);
@@ -702,23 +712,23 @@ static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
     value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
     void **user_data)
 {
-  char **plugin_list;
+  fc_writer_t *plugin_list;
   int status;
 
   plugin_list = NULL;
   if (user_data != NULL)
     plugin_list = *user_data;
 
-  if ((plugin_list == NULL) || (plugin_list[0] == NULL))
+  if ((plugin_list == NULL) || (plugin_list[0].plugin == NULL))
   {
-    static c_complain_t enoent_complaint = C_COMPLAIN_INIT_STATIC;
+    static c_complain_t write_complaint = C_COMPLAIN_INIT_STATIC;
 
     status = plugin_write (/* plugin = */ NULL, ds, vl);
     if (status == ENOENT)
     {
       /* in most cases this is a permanent error, so use the complain
        * mechanism rather than spamming the logs */
-      c_complain (LOG_INFO, &enoent_complaint,
+      c_complain (LOG_INFO, &write_complaint,
           "Filter subsystem: Built-in target `write': Dispatching value to "
           "all write plugins failed with status %i (ENOENT). "
           "Most likely this means you didn't load any write plugins.",
@@ -726,13 +736,16 @@ static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
     }
     else if (status != 0)
     {
-      INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
+      /* often, this is a permanent error (e.g. target system unavailable),
+       * so use the complain mechanism rather than spamming the logs */
+      c_complain (LOG_INFO, &write_complaint,
+          "Filter subsystem: Built-in target `write': Dispatching value to "
           "all write plugins failed with status %i.", status);
     }
     else
     {
       assert (status == 0);
-      c_release (LOG_INFO, &enoent_complaint, "Filter subsystem: "
+      c_release (LOG_INFO, &write_complaint, "Filter subsystem: "
           "Built-in target `write': Some write plugin is back to normal "
           "operation. `write' succeeded.");
     }
@@ -741,13 +754,21 @@ static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
   {
     size_t i;
 
-    for (i = 0; plugin_list[i] != NULL; i++)
+    for (i = 0; plugin_list[i].plugin != NULL; i++)
     {
-      status = plugin_write (plugin_list[i], ds, vl);
+      status = plugin_write (plugin_list[i].plugin, ds, vl);
       if (status != 0)
       {
-        INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
-            "the `%s' plugin failed with status %i.", plugin_list[i], status);
+        c_complain (LOG_INFO, &plugin_list[i].complaint,
+            "Filter subsystem: Built-in target `write': Dispatching value to "
+            "the `%s' plugin failed with status %i.",
+            plugin_list[i].plugin, status);
+      }
+      else
+      {
+        c_release (LOG_INFO, &plugin_list[i].complaint,
+            "Filter subsystem: Built-in target `write': Plugin `%s' is back "
+            "to normal operation. `write' succeeded.", plugin_list[i].plugin);
       }
     } /* for (i = 0; plugin_list[i] != NULL; i++) */
   }
index 97b794f..6c6ab63 100644 (file)
@@ -393,7 +393,7 @@ static int plugin_load_file (char *file, uint32_t flags)
 
                ssnprintf (errbuf, sizeof (errbuf),
                                "lt_dlopen (\"%s\") failed: %s. "
-                               "The most common cause for this problem are "
+                               "The most common cause for this problem is "
                                "missing dependencies. Use ldd(1) to check "
                                "the dependencies of the plugin "
                                "/ shared object.",
index d3d5202..41451a8 100644 (file)
@@ -197,6 +197,8 @@ static int wg_callback_init (struct wg_callback *cb)
     const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE;
     const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
 
+    char connerr[1024] = "";
+
     if (cb->sock_fd > 0)
         return (0);
 
@@ -233,12 +235,19 @@ static int wg_callback_init (struct wg_callback *cb)
     {
         cb->sock_fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
                 ai_ptr->ai_protocol);
-        if (cb->sock_fd < 0)
+        if (cb->sock_fd < 0) {
+            char errbuf[1024];
+            snprintf (connerr, sizeof (connerr), "failed to open socket: %s",
+                    sstrerror (errno, errbuf, sizeof (errbuf)));
             continue;
+        }
 
         status = connect (cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
         if (status != 0)
         {
+            char errbuf[1024];
+            snprintf (connerr, sizeof (connerr), "failed to connect to remote "
+                    "host: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
             close (cb->sock_fd);
             cb->sock_fd = -1;
             continue;
@@ -251,11 +260,12 @@ static int wg_callback_init (struct wg_callback *cb)
 
     if (cb->sock_fd < 0)
     {
-        char errbuf[1024];
+        if (connerr[0] == '\0')
+            /* this should not happen but try to get a message anyway */
+            sstrerror (errno, connerr, sizeof (connerr));
         c_complain (LOG_ERR, &cb->init_complaint,
-                "write_graphite plugin: Connecting to %s:%s via %s failed. "
-                "The last error was: %s", node, service, protocol,
-                sstrerror (errno, errbuf, sizeof (errbuf)));
+                  "write_graphite plugin: Connecting to %s:%s via %s failed. "
+                  "The last error was: %s", node, service, protocol, connerr);
         return (-1);
     }
     else