Merge pull request #2923 from qdbp/gpu_nvml_plugin
authorFlorian Forster <ff@octo.it>
Sat, 27 Oct 2018 07:14:25 +0000 (09:14 +0200)
committerGitHub <noreply@github.com>
Sat, 27 Oct 2018 07:14:25 +0000 (09:14 +0200)
New plugin: gpu_nvidia collects NVIDIA GPU stats.

17 files changed:
ChangeLog
configure.ac
docs/review_comments.md [new file with mode: 0644]
docs/review_comments_example.png [new file with mode: 0644]
src/collectd.conf.pod
src/disk.c
src/exec.c
src/ntpd.c
src/ovs_stats.c
src/powerdns.c
src/utils_format_stackdriver_test.c
src/utils_mount.c
src/utils_oauth.c
src/virt.c
src/write_prometheus.c
src/zfs_arc.c
version-gen.sh

index 5c7c42f..e9a8415 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,78 @@
+2018-10-23, Version 5.8.1
+       * collectd: Fix "BaseDir" option. Thanks to Mariusz Białończyk and
+         Pavel Rochnyak. #2857
+       * collectd: improve error handling, check return values. Thanks to
+         Florian Forster.
+       * Build System: use "kstat.h", when available. Thanks to Dagobert
+         Michelsen and Pavel Rochnyak. #2784
+       * Build System: Fix distcheck on MacOS. Thanks to Ruben Kerkhof.
+       * Build System: add missing include of ""collectd.h"" to fix builds on
+         Solaris. Thanks to Pavel Rochnyak.
+       * Build System: add endianess checks for AIX, fix GCC issue on Mac
+         byteorder, fix byteorder on Solaris, add fallback for endianess
+         conversion. Thanks to Dagobert Michelsen (multiple cherry picks from
+         master).
+       * Build System: Out-of-tree builds have been fixed. Thanks to Florian
+         Forster. #2602
+       * Configuration: Error handling in the config parsing code has been
+         improved. Thanks to Florian Forster.
+       * Documentation: Fix typo in collectd.conf(5). Thanks to Pavel Rochnyak.
+         #2760
+       * Documentation: update note on dpdkstat. Thanks to Maryam Tahhan. #2613
+       * Various plugins: Errors found by the static code analysis tool
+         Coverity were fixed. Thanks to Florian Forster. #2559, #2560, #2561,
+         #2562, #2563, #2565, #2568, #2575, #2579, #2580, #2588, #2589
+       * Ceph plugin: A segfault has been fixed. Thanks to Aleksei Zakharov and
+         Matthias Runge. #2572
+       * DF plugin: fix memory leak in error case. Thanks to Takahashi tsc.
+       * Exec plugin: check return value of "plugin_thread_create()". Thanks to
+         Florian Forster.
+       * Exec plugin: Handling of large groups has been fixed. Thanks to
+         Sridhar Mallem. #2696
+       * Exec plugin: Incorrect use of *putenv(3)* has been fixed. Thanks to
+         Daniel Vrátil.
+       * Exec plugin: A deadlock related to setting environment variables after
+         *fork()* has been fixed. Thanks to Daniel Vrátil.
+       * Intel PMU plugin: add core groups feature. Thanks to Kamil Wiatrowski.
+         #2681
+       * Intel PMU plugin: fix compatibility issue with collectd 5.8. Thanks to
+         Kamil Wiatrowski.
+       * Intel PMU plugin: fix possible "NULL" pointer dereference. Thanks to
+         Kamil Wiatrowski. #2676
+       * IPMI plugin: A segfault caused by a wrong data type has been fixed.
+         Thanks to Mariusz Szafrański. #2742
+       * IPMI plugin: The sensor configuration option has been fixed. Thanks to
+         Pavel Rochnyak. #2629
+       * memcached plugin: A deadlock situation has been fixed. Thanks to Pavel
+         Rochnyak. #2612
+       * NFS plugin: Support for NFSv4 has been fixed. Thanks to Jan-Philipp
+         Litza. #2076
+       * NTPd plugin: A memory leak in the error handling path has been fixed.
+         Thanks to Ruben Kerkhof. #2942
+       * OVS Stats plugin: A deadlock situation has been fixed. Thanks to
+         Volodymyr Mytnyk. #2590
+       * OVS Stats plugin: Fix reconnect after thread terminated. Thanks to
+         Volodymyr Mytnyk and Maram Tahhan. #2574
+       * Perl plugin: A compilation failure has been fixed. Thanks to Pavel
+         Rochnyak. #2732
+       * Perl plugin: Fix exporting notification meta data. Thanks to Florian
+         Forster.
+       * RRDtool plugin: Handling of very large "GAUGE" metrics has been fixed.
+         Thanks to Miroslav Lichvar. #2566
+       * Tail plugin: Several regressions have been fixed. Thanks to Pavel
+         Rochnyak. #2535, #2587, #2611
+       * turbostat plugin: A potential segfault due to an incorrect *free()*
+         has been fixed. Thanks to Ruben Kerkhof. #2948
+       * UUID plugin: Fix hostname setting. Thanks to Pavel Rochnyak. #2723
+       * virt plugin: A segfault during error handling has been fixed. Thanks
+         to Ruben Kerkhof. {{Issue|2919]}
+       * Write Kafka plugin: A build failure due to a deprecated API call has
+         been fixed. Thanks to Pavel Rochnyak. #2607, #2628, #2640
+       * Write Prometheus plugin: Fix "MHD_USE_INTERNAL_POLLING_THREAD" flag in
+         newer libmicrohttpd. Thanks to Pavel Rochnyak. #2849
+       * Write Prometheus plugin: set "SO_REUSEADDRESS" on listening socket.
+         Thanks to Pavel Rochnyak. #2570, #2673
+
 2017-11-17, Version 5.8.0
        * collectd: The core daemon is now completely licensed under the MIT
          license.
index 2f73cbd..3b6d10e 100644 (file)
@@ -5797,15 +5797,15 @@ if test "x$with_libxmms" = "xyes"; then
 fi
 
 if test "x$with_libxmms" = "xyes"; then
-  SAVE_CFLAGS="$CFLAGS"
-  CFLAGS="$with_xmms_cflags"
+  SAVE_CPPFLAGS="$CFLAGS"
+  CPPFLAGS="$with_xmms_cflags"
 
   AC_CHECK_HEADER([xmmsctrl.h],
     [with_libxmms="yes"],
     [with_libxmms="no"],
   )
 
-  CFLAGS="$SAVE_CFLAGS"
+  CPPFLAGS="$SAVE_CPPFLAGS"
 fi
 
 if test "x$with_libxmms" = "xyes"; then
diff --git a/docs/review_comments.md b/docs/review_comments.md
new file mode 100644 (file)
index 0000000..9bad458
--- /dev/null
@@ -0,0 +1,96 @@
+# Code Review Comments
+
+This is a collection of frequent code review comments, collected here for
+reference and discussed in more depth than a typical code review would allow.
+
+The intended use for this document is to point to it from a code review to make
+a point quickly while still providing the contributor with enough information
+to resolve the issue. For example, a good review comment would be:
+
+![Please initialize variables at declaration. Link to comment.](review_comments_example.png)
+
+A link to each paragraph is provided at the beginning for easy copy'n'pasting.
+
+## Initialize variables
+
+→ [https://collectd.org/review-comments#initialize-variables](https://collectd.org/review-comments#initialize-variables)
+
+Initialize variables when declaring them. By default, C does not initialize
+local variables when they are defined. If a code path ends up reading the
+variable before it is initialized, for example because a loop body is never
+executed, it will read random data, causing undefined behavior. Worst case,
+pointers will point to random memory causing a segmentation fault.
+
+**Examples:**
+
+```c
+/* Initialize scalar with to literal: */
+int status = 0;
+
+/* Initialize pointer with function call: */
+char *buffer = calloc(1, buffer_size);
+
+/* Initialize struct with struct initializer: */
+struct addrinfo ai = {
+  .ai_family = AF_UNSPEC,
+  .ai_flags = AI_ADDRCONFIG,
+  .ai_socktype = SOCK_STREAM,
+};
+
+/* Initialize struct with zero: */
+struct stat statbuf = {0};
+```
+
+In the last example, `{0}` is the universal struct initializer that, in theory,
+should be able to zero-initialize any struct. In practise, however, some
+compilers don't implement this correctly and will get confused when the first
+member is a struct or a union. Our *continuous integration* framework will
+catch these cases.
+
+## Define variables on first use
+
+→ [https://collectd.org/review-comments#define-variables-on-first-use](https://collectd.org/review-comments#define-variables-on-first-use)
+
+Local variables should be defined when they are first used, ideally when they
+can be initialized. For example:
+
+```c
+struct foo *f = calloc(1, sizeof(*f));
+if (f == NULL) {
+  return ENOMEM;
+}
+
+/* GOOD: status defiened and initialized late. */
+int status = function_call(f);
+```
+
+Sometimes variables are initialized by passing a pointer to them to a function.
+In that case define them as close to the function call as you can and
+zero-initialize them. The function may only partially initialize a struct or
+not initialize a struct at all in some circumstances.
+
+**Example:**
+
+```c
+char const *path = determine_path();
+
+struct stat s = {0};
+int status = stat(path, &s);
+```
+
+Old C standards (C89 and ealier) required variables to be defined at the
+beginning of a scope block. The following *bad* style is still frequently
+found:
+
+```c
+/* BAD: local variables defined at beginning of block. */
+struct foo *f;
+int status;
+
+f = calloc(1, sizeof(*f));
+if (f == NULL) {
+  return ENOMEM;
+}
+
+status = function_call(f);
+```
diff --git a/docs/review_comments_example.png b/docs/review_comments_example.png
new file mode 100644 (file)
index 0000000..81eb458
Binary files /dev/null and b/docs/review_comments_example.png differ
index cc288a6..d830573 100644 (file)
@@ -9697,6 +9697,13 @@ B<Options:>
 
 =over 4
 
+=item B<Host> I<Host>
+
+Bind to the hostname / address I<Host>. By default, the plugin will bind to the
+"any" address, i.e. accept packets sent to any of the hosts addresses.
+
+This option is supported only for libmicrohttpd newer than 0.9.0.
+
 =item B<Port> I<Port>
 
 Port the embedded webserver should listen on. Defaults to B<9103>.
index c0408ce..c78df4e 100644 (file)
@@ -692,7 +692,9 @@ static int disk_read(void) {
     char *output_name;
 
     numfields = strsplit(buffer, fields, 32);
-    if ((numfields != 14) && (numfields != 7))
+
+    /* need either 7 fields (partition) or at least 14 fields */
+    if ((numfields != 7) && (numfields < 14))
       continue;
 
     minor = atoll(fields[1]);
@@ -726,7 +728,8 @@ static int disk_read(void) {
       read_sectors = atoll(fields[4]);
       write_ops = atoll(fields[5]);
       write_sectors = atoll(fields[6]);
-    } else if (numfields == 14) {
+    } else {
+      assert(numfields >= 14);
       read_ops = atoll(fields[3]);
       write_ops = atoll(fields[7]);
 
@@ -745,9 +748,6 @@ static int disk_read(void) {
         io_time = atof(fields[12]);
         weighted_time = atof(fields[13]);
       }
-    } else {
-      DEBUG("numfields = %i; => unknown file format.", numfields);
-      continue;
     }
 
     {
index 77b1375..26b8fa7 100644 (file)
@@ -245,11 +245,17 @@ static int exec_config(oconfig_item_t *ci) /* {{{ */
   return 0;
 } /* int exec_config }}} */
 
+#if !defined(HAVE_SETENV)
+static char env_interval[64];
+// max hostname len is 255, so this should be enough
+static char env_hostname[300];
+#endif
+
 static void set_environment(void) /* {{{ */
 {
+#ifdef HAVE_SETENV
   char buffer[1024];
 
-#ifdef HAVE_SETENV
   snprintf(buffer, sizeof(buffer), "%.3f",
            CDTIME_T_TO_DOUBLE(plugin_get_interval()));
   setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
@@ -257,15 +263,29 @@ static void set_environment(void) /* {{{ */
   sstrncpy(buffer, hostname_g, sizeof(buffer));
   setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
 #else
-  snprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f",
+  snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL=%.3f",
            CDTIME_T_TO_DOUBLE(plugin_get_interval()));
-  putenv(buffer);
+  putenv(env_interval);
 
-  snprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
-  putenv(buffer);
+  snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME=%s",
+           hostname_g);
+  putenv(env_hostname);
 #endif
 } /* }}} void set_environment */
 
+static void unset_environment(void) /* {{{ */
+{
+#ifdef HAVE_SETENV
+  unsetenv("COLLECTD_INTERVAL");
+  unsetenv("COLLECTD_HOSTNAME");
+#else
+  snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL");
+  putenv(env_interval);
+  snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME");
+  putenv(env_hostname);
+#endif
+} /* }}} void unset_environment */
+
 __attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid,
                                                  int gid, int egid) /* {{{ */
 {
@@ -466,6 +486,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out,
     goto failed;
   }
 
+  set_environment();
+
   pid = fork();
   if (pid < 0) {
     ERROR("exec plugin: fork failed: %s", STRERRNO);
@@ -500,8 +522,6 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out,
       close(fd_pipe_err[1]);
     }
 
-    set_environment();
-
     /* Unblock all signals */
     reset_signal_mask();
 
@@ -509,6 +529,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out,
     /* does not return */
   }
 
+  unset_environment();
+
   close(fd_pipe_in[0]);
   close(fd_pipe_out[1]);
   close(fd_pipe_err[1]);
@@ -531,6 +553,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out,
   return pid;
 
 failed:
+  unset_environment();
+
   close_pipe(fd_pipe_in);
   close_pipe(fd_pipe_out);
   close_pipe(fd_pipe_err);
index ef63498..0b824ba 100644 (file)
@@ -810,11 +810,13 @@ static int ntpd_read(void) {
   if (status != 0) {
     ERROR("ntpd plugin: ntpd_do_query (REQ_GET_KERNEL) failed with status %i",
           status);
+    free(ik);
     return status;
   } else if ((ik == NULL) || (ik_num == 0) || (ik_size == 0)) {
     ERROR("ntpd plugin: ntpd_do_query returned unexpected data. "
           "(ik = %p; ik_num = %i; ik_size = %i)",
           (void *)ik, ik_num, ik_size);
+    free(ik);
     return -1;
   }
 
@@ -849,11 +851,13 @@ static int ntpd_read(void) {
     ERROR(
         "ntpd plugin: ntpd_do_query (REQ_PEER_LIST_SUM) failed with status %i",
         status);
+    free(ps);
     return status;
   } else if ((ps == NULL) || (ps_num == 0) || (ps_size == 0)) {
     ERROR("ntpd plugin: ntpd_do_query returned unexpected data. "
           "(ps = %p; ps_num = %i; ps_size = %i)",
           (void *)ps, ps_num, ps_size);
+    free(ps);
     return -1;
   }
 
index 72c92b2..a629ec6 100644 (file)
@@ -968,7 +968,7 @@ static int ovs_stats_plugin_read(__attribute__((unused)) user_data_t *ud) {
           ovs_stats_submit_two(devname, "if_packets", "512_to_1023_packets",
                                port->stats[rx_512_to_1023_packets],
                                port->stats[tx_512_to_1023_packets], meta);
-          ovs_stats_submit_two(devname, "if_packets", "1024_to_1518_packets",
+          ovs_stats_submit_two(devname, "if_packets", "1024_to_1522_packets",
                                port->stats[rx_1024_to_1522_packets],
                                port->stats[tx_1024_to_1522_packets], meta);
           ovs_stats_submit_two(devname, "if_packets", "1523_to_max_packets",
index 7a2fbfd..644d0ae 100644 (file)
@@ -279,7 +279,7 @@ static statname_lookup_t lookup_table[] = /* {{{ */
         {"ipv6-questions", "dns_question", "incoming-ipv6"},
         {"malloc-bytes", "gauge", "malloc_bytes"},
         {"max-mthread-stack", "gauge", "max_mthread_stack"},
-        {"no-packet-error", "gauge", "no_packet_error"},
+        {"no-packet-error", "errors", "no_packet_error"},
         {"noedns-outqueries", "dns_question", "outgoing-noedns"},
         {"noping-outqueries", "dns_question", "outgoing-noping"},
         {"over-capacity-drops", "dns_question", "incoming-over_capacity"},
index fa43866..1e96b65 100644 (file)
@@ -20,6 +20,8 @@
  *   Florian Forster <octo at collectd.org>
  **/
 
+#include "collectd.h"
+
 #include "testing.h"
 #include "utils_format_stackdriver.h"
 
index e430cc9..279f8e2 100644 (file)
@@ -651,6 +651,8 @@ cu_mount_t *cu_mount_getlist(cu_mount_t **list) {
   new = cu_mount_gen_getmntent();
 #elif HAVE_SEQ_GETMNTENT
 #error "This version of `getmntent' hat not yet been implemented!"
+#elif HAVE_GETMNTENT_R
+  new = cu_mount_getmntent();
 #elif HAVE_ONE_GETMNTENT
   new = cu_mount_getmntent();
 #else
index 35533be..d804b51 100644 (file)
@@ -425,9 +425,10 @@ static int new_token(oauth_t *auth) /* {{{ */
 
 static int renew_token(oauth_t *auth) /* {{{ */
 {
-  /* TODO(octo): Make sure that we get a new token 60 seconds or so before the
-   * old one expires. */
-  if (auth->valid_until > cdtime())
+  /* Renew OAuth token 30 seconds *before* it expires. */
+  cdtime_t const slack = TIME_T_TO_CDTIME_T(30);
+
+  if (auth->valid_until > (cdtime() + slack))
     return 0;
 
   return new_token(auth);
index c52a8a7..a828c45 100644 (file)
@@ -639,12 +639,6 @@ static time_t last_refresh = (time_t)0;
 
 static int refresh_lists(struct lv_read_instance *inst);
 
-struct lv_info {
-  virDomainInfo di;
-  unsigned long long total_user_cpu_time;
-  unsigned long long total_syst_cpu_time;
-};
-
 struct lv_block_info {
   virDomainBlockStatsStruct bi;
 
@@ -708,59 +702,9 @@ static int get_block_info(struct lv_block_info *binfo,
     virErrorPtr err;                                                           \
     err = (conn) ? virConnGetLastError((conn)) : virGetLastError();            \
     if (err)                                                                   \
-      ERROR("%s: %s", (s), err->message);                                      \
+      ERROR(PLUGIN_NAME " plugin: %s failed: %s", (s), err->message);          \
   } while (0)
 
-static void init_lv_info(struct lv_info *info) {
-  if (info != NULL)
-    memset(info, 0, sizeof(*info));
-}
-
-static int lv_domain_info(virDomainPtr dom, struct lv_info *info) {
-#ifdef HAVE_CPU_STATS
-  virTypedParameterPtr param = NULL;
-  int nparams = 0;
-#endif /* HAVE_CPU_STATS */
-  int ret = virDomainGetInfo(dom, &(info->di));
-  if (ret != 0) {
-    return ret;
-  }
-
-#ifdef HAVE_CPU_STATS
-  nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
-  if (nparams < 0) {
-    VIRT_ERROR(conn, "getting the CPU params count");
-    return -1;
-  }
-
-  param = calloc(nparams, sizeof(virTypedParameter));
-  if (param == NULL) {
-    ERROR("virt plugin: alloc(%i) for cpu parameters failed.", nparams);
-    return -1;
-  }
-
-  ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats.
-  if (ret < 0) {
-    virTypedParamsClear(param, nparams);
-    sfree(param);
-    VIRT_ERROR(conn, "getting the disk params values");
-    return -1;
-  }
-
-  for (int i = 0; i < nparams; ++i) {
-    if (!strcmp(param[i].field, "user_time"))
-      info->total_user_cpu_time = param[i].value.ul;
-    else if (!strcmp(param[i].field, "system_time"))
-      info->total_syst_cpu_time = param[i].value.ul;
-  }
-
-  virTypedParamsClear(param, nparams);
-  sfree(param);
-#endif /* HAVE_CPU_STATS */
-
-  return 0;
-}
-
 static void init_value_list(value_list_t *vl, virDomainPtr dom) {
   const char *name;
   char uuid[VIR_UUID_STRING_BUFLEN];
@@ -892,14 +836,6 @@ static void submit_derive2(const char *type, derive_t v0, derive_t v1,
   submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values));
 } /* void submit_derive2 */
 
-static void pcpu_submit(virDomainPtr dom, struct lv_info *info) {
-#ifdef HAVE_CPU_STATS
-  if (extra_stats & ex_stats_pcpu)
-    submit_derive2("ps_cputime", info->total_user_cpu_time,
-                   info->total_syst_cpu_time, dom, NULL);
-#endif /* HAVE_CPU_STATS */
-}
-
 static double cpu_ns_to_percent(unsigned int node_cpus,
                                 unsigned long long cpu_time_old,
                                 unsigned long long cpu_time_new) {
@@ -1411,13 +1347,13 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
 
   virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(vinfo[0]));
   if (vinfo == NULL) {
-    ERROR(PLUGIN_NAME " plugin: malloc failed.");
+    ERROR(PLUGIN_NAME " plugin: calloc failed.");
     return -1;
   }
 
   unsigned char *cpumaps = calloc(nr_virt_cpu, cpu_map_len);
   if (cpumaps == NULL) {
-    ERROR(PLUGIN_NAME " plugin: malloc failed.");
+    ERROR(PLUGIN_NAME " plugin: calloc failed.");
     sfree(vinfo);
     return -1;
   }
@@ -1443,6 +1379,49 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
   return 0;
 }
 
+#ifdef HAVE_CPU_STATS
+static int get_pcpu_stats(virDomainPtr dom) {
+  int nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
+  if (nparams < 0) {
+    VIRT_ERROR(conn, "getting the CPU params count");
+    return -1;
+  }
+
+  virTypedParameterPtr param = calloc(nparams, sizeof(virTypedParameter));
+  if (param == NULL) {
+    ERROR(PLUGIN_NAME " plugin: alloc(%i) for cpu parameters failed.", nparams);
+    return -1;
+  }
+
+  int ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats.
+  if (ret < 0) {
+    virTypedParamsClear(param, nparams);
+    sfree(param);
+    VIRT_ERROR(conn, "getting the CPU params values");
+    return -1;
+  }
+
+  unsigned long long total_user_cpu_time = 0;
+  unsigned long long total_syst_cpu_time = 0;
+
+  for (int i = 0; i < nparams; ++i) {
+    if (!strcmp(param[i].field, "user_time"))
+      total_user_cpu_time = param[i].value.ul;
+    else if (!strcmp(param[i].field, "system_time"))
+      total_syst_cpu_time = param[i].value.ul;
+  }
+
+  if (total_user_cpu_time > 0 || total_syst_cpu_time > 0)
+    submit_derive2("ps_cputime", total_user_cpu_time, total_syst_cpu_time, dom,
+                   NULL);
+
+  virTypedParamsClear(param, nparams);
+  sfree(param);
+
+  return 0;
+}
+#endif /* HAVE_CPU_STATS */
+
 #ifdef HAVE_DOM_REASON
 
 static void domain_state_submit(virDomainPtr dom, int state, int reason) {
@@ -1716,15 +1695,13 @@ static int get_job_stats(virDomainPtr domain) {
 #endif /* HAVE_JOB_STATS */
 
 static int get_domain_metrics(domain_t *domain) {
-  struct lv_info info;
-
   if (!domain || !domain->ptr) {
-    ERROR(PLUGIN_NAME ": get_domain_metrics: NULL pointer");
+    ERROR(PLUGIN_NAME "plugin: get_domain_metrics: NULL pointer");
     return -1;
   }
 
-  init_lv_info(&info);
-  int status = lv_domain_info(domain->ptr, &info);
+  virDomainInfo info;
+  int status = virDomainGetInfo(domain->ptr, &info);
   if (status != 0) {
     ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
           status);
@@ -1742,15 +1719,19 @@ static int get_domain_metrics(domain_t *domain) {
   }
 
   /* Gather remaining stats only for running domains */
-  if (info.di.state != VIR_DOMAIN_RUNNING)
+  if (info.state != VIR_DOMAIN_RUNNING)
     return 0;
 
-  pcpu_submit(domain->ptr, &info);
-  cpu_submit(domain, info.di.cpuTime);
+#ifdef HAVE_CPU_STATS
+  if (extra_stats & ex_stats_pcpu)
+    get_pcpu_stats(domain->ptr);
+#endif
+
+  cpu_submit(domain, info.cpuTime);
 
-  memory_submit(domain->ptr, (gauge_t)info.di.memory * 1024);
+  memory_submit(domain->ptr, (gauge_t)info.memory * 1024);
 
-  GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.di.nrVirtCpu);
+  GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
   GET_STATS(get_memory_stats, "memory stats", domain->ptr);
 
 #ifdef HAVE_PERF_STATS
@@ -1775,7 +1756,7 @@ static int get_domain_metrics(domain_t *domain) {
 #endif
 
   /* Update cached virDomainInfo. It has to be done after cpu_submit */
-  memcpy(&domain->info, &info.di, sizeof(domain->info));
+  memcpy(&domain->info, &info, sizeof(domain->info));
 
   return 0;
 }
index 7137558..53a0709 100644 (file)
@@ -54,6 +54,7 @@
 static c_avl_tree_t *metrics;
 static pthread_mutex_t metrics_lock = PTHREAD_MUTEX_INITIALIZER;
 
+static char *httpd_host = NULL;
 static unsigned short httpd_port = 9103;
 static struct MHD_Daemon *httpd;
 
@@ -746,7 +747,7 @@ static int prom_open_socket(int addrfamily) {
   snprintf(service, sizeof(service), "%hu", httpd_port);
 
   struct addrinfo *res;
-  int status = getaddrinfo(NULL, service,
+  int status = getaddrinfo(httpd_host, service,
                            &(struct addrinfo){
                                .ai_flags = AI_PASSIVE | AI_ADDRCONFIG,
                                .ai_family = addrfamily,
@@ -764,7 +765,7 @@ static int prom_open_socket(int addrfamily) {
       continue;
 
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) != 0) {
-      WARNING("write_prometheus: setsockopt(SO_REUSEADDR) failed: %s",
+      WARNING("write_prometheus plugin: setsockopt(SO_REUSEADDR) failed: %s",
               STRERRNO);
       close(fd);
       fd = -1;
@@ -783,6 +784,15 @@ static int prom_open_socket(int addrfamily) {
       continue;
     }
 
+    char str_node[NI_MAXHOST];
+    char str_service[NI_MAXSERV];
+
+    getnameinfo(ai->ai_addr, ai->ai_addrlen, str_node, sizeof(str_node),
+                str_service, sizeof(str_service),
+                NI_NUMERICHOST | NI_NUMERICSERV);
+
+    INFO("write_prometheus plugin: Listening on [%s]:%s.", str_node,
+         str_service);
     break;
   }
 
@@ -797,7 +807,9 @@ static struct MHD_Daemon *prom_start_daemon() {
   if (fd == -1)
     fd = prom_open_socket(PF_INET);
   if (fd == -1) {
-    ERROR("write_prometheus plugin: Opening a listening socket failed.");
+    ERROR("write_prometheus plugin: Opening a listening socket for [%s]:%hu "
+          "failed.",
+          (httpd_host != NULL) ? httpd_host : "::", httpd_port);
     return NULL;
   }
 
@@ -844,7 +856,15 @@ static int prom_config(oconfig_item_t *ci) {
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
-    if (strcasecmp("Port", child->key) == 0) {
+    if (strcasecmp("Host", child->key) == 0) {
+#if MHD_VERSION >= 0x00090000
+      cf_util_get_string(child, &httpd_host);
+#else
+      ERROR("write_prometheus plugin: Option `Host' not supported. Please "
+            "upgrade libmicrohttpd to at least 0.9.0");
+      return -1;
+#endif
+    } else if (strcasecmp("Port", child->key) == 0) {
       int status = cf_util_get_port_number(child);
       if (status > 0)
         httpd_port = (unsigned short)status;
@@ -872,7 +892,6 @@ static int prom_init() {
   if (httpd == NULL) {
     httpd = prom_start_daemon();
     if (httpd == NULL) {
-      ERROR("write_prometheus plugin: MHD_start_daemon() failed.");
       return -1;
     }
     DEBUG("write_prometheus plugin: Successfully started microhttpd %s",
@@ -965,6 +984,8 @@ static int prom_shutdown() {
   }
   pthread_mutex_unlock(&metrics_lock);
 
+  sfree(httpd_host);
+
   return 0;
 }
 
index c9abdd5..d1ee111 100644 (file)
@@ -231,6 +231,23 @@ static int za_read(void) {
     return -1;
   }
 
+  // Ignore the first two lines because they contain information about
+  // the rest of the file.
+  // See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel
+  // module.
+  if (fgets(buffer, sizeof(buffer), fh) == NULL) {
+    ERROR("zfs_arc plugin: \"%s\" does not contain a single line.",
+          ZOL_ARCSTATS_FILE);
+    fclose(fh);
+    return (-1);
+  }
+  if (fgets(buffer, sizeof(buffer), fh) == NULL) {
+    ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.",
+          ZOL_ARCSTATS_FILE);
+    fclose(fh);
+    return (-1);
+  }
+
   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
     char *fields[3];
     value_t v;
index f16e661..048b5a2 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-DEFAULT_VERSION="5.8.0.git"
+DEFAULT_VERSION="5.8.1.git"
 
 if [ -d .git ]; then
        VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"