Merge remote-tracking branch 'github/pr/2472'
authorFlorian Forster <octo@collectd.org>
Thu, 18 Oct 2018 08:49:37 +0000 (10:49 +0200)
committerFlorian Forster <octo@collectd.org>
Thu, 18 Oct 2018 08:49:37 +0000 (10:49 +0200)
.travis.yml
Makefile.am
src/collectd.conf.pod
src/daemon/common.h
src/daemon/plugin.h
src/disk.c
src/exec.c
src/gps.c
src/libcollectdclient/server.c
src/utils_format_json.c
src/wireless.c

index 1bd6142..97115d1 100644 (file)
@@ -75,7 +75,7 @@ before_script: autoreconf -fi
 script:
   - if [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]; then exit 0; fi
   - ./configure
-  - make -j 4
+  - make -j $(nproc)
   - make check
 
 addons:
@@ -85,5 +85,5 @@ addons:
       description: "Build submitted via Travis CI"
     notification_email: collectd-changes@verplant.org
     build_command_prepend: "./configure; make clean"
-    build_command: "make -j 4"
+    build_command: "make -j $(nproc)"
     branch_pattern: coverity_scan
index 12d6fa4..6a0f78e 100644 (file)
@@ -127,7 +127,7 @@ bin_PROGRAMS = \
 endif # BUILD_WIN32
 
 
-EXTRA_LTLIBRARIES = \
+noinst_LTLIBRARIES = \
        libavltree.la \
        libcmds.la \
        libcommon.la \
@@ -1579,7 +1579,7 @@ python_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBPYTHON_LDFLAGS)
 endif
 
 if HAVE_LIBMNL
-EXTRA_LTLIBRARIES += libtaskstats.la
+noinst_LTLIBRARIES += libtaskstats.la
 libtaskstats_la_SOURCES = \
        src/utils_taskstats.c \
        src/utils_taskstats.h
index da8e873..e11e514 100644 (file)
@@ -9106,6 +9106,40 @@ only on the host system.
 
 Only I<Connection> is required.
 
+Consider the following example config:
+
+ <Plugin "virt">
+   Connection "qemu:///system"
+   HostnameFormat "hostname"
+   InterfaceFormat "address"
+   PluginInstanceFormat "name"
+ </Plugin>
+
+It will generate the following values:
+
+  node42.example.com/virt-instance-0006f26c/disk_octets-vda
+  node42.example.com/virt-instance-0006f26c/disk_ops-vda
+  node42.example.com/virt-instance-0006f26c/if_dropped-ca:fe:ca:fe:ca:fe
+  node42.example.com/virt-instance-0006f26c/if_errors-ca:fe:ca:fe:ca:fe
+  node42.example.com/virt-instance-0006f26c/if_octets-ca:fe:ca:fe:ca:fe
+  node42.example.com/virt-instance-0006f26c/if_packets-ca:fe:ca:fe:ca:fe
+  node42.example.com/virt-instance-0006f26c/memory-actual_balloon
+  node42.example.com/virt-instance-0006f26c/memory-available
+  node42.example.com/virt-instance-0006f26c/memory-last_update
+  node42.example.com/virt-instance-0006f26c/memory-major_fault
+  node42.example.com/virt-instance-0006f26c/memory-minor_fault
+  node42.example.com/virt-instance-0006f26c/memory-rss
+  node42.example.com/virt-instance-0006f26c/memory-swap_in
+  node42.example.com/virt-instance-0006f26c/memory-swap_out
+  node42.example.com/virt-instance-0006f26c/memory-total
+  node42.example.com/virt-instance-0006f26c/memory-unused
+  node42.example.com/virt-instance-0006f26c/memory-usable
+  node42.example.com/virt-instance-0006f26c/virt_cpu_total
+  node42.example.com/virt-instance-0006f26c/virt_vcpu-0
+
+You can get information on the metric's units from the online libvirt documentation.
+For instance, I<virt_cpu_total> is in nanoseconds.
+
 =over 4
 
 =item B<Connection> I<uri>
@@ -9208,7 +9242,8 @@ B<uuid> means use the guest's UUID. This is useful if you want to track the
 same guest across migrations.
 
 B<hostname> means to use the global B<Hostname> setting, which is probably not
-useful on its own because all guests will appear to have the same name.
+useful on its own because all guests will appear to have the same name. This is
+useful in conjunction with B<PluginInstanceFormat> though.
 
 You can also specify combinations of these fields. For example B<name uuid>
 means to concatenate the guest name and UUID (with a literal colon character
index 8cd4e22..addf06d 100644 (file)
@@ -358,7 +358,7 @@ ssize_t read_file_contents(char const *filename, char *buf, size_t bufsize);
 counter_t counter_diff(counter_t old_value, counter_t new_value);
 
 /* Convert a rate back to a value_t. When converting to a derive_t, counter_t
- * or absoltue_t, take fractional residuals into account. This is important
+ * or absolute_t, take fractional residuals into account. This is important
  * when scaling counters, for example.
  * Returns zero on success. Returns EAGAIN when called for the first time; in
  * this case the value_t is invalid and the next call should succeed. Other
index 2d903cb..616889a 100644 (file)
@@ -245,7 +245,7 @@ int plugin_shutdown_all(void);
  *
  * DESCRIPTION
  *  Calls the write function of the given plugin with the provided data set and
- *  value list. It differs from `plugin_dispatch_value' in that it does not
+ *  value list. It differs from `plugin_dispatch_values' in that it does not
  *  update the cache, does not do threshold checking, call the chain subsystem
  *  and so on. It looks up the requested plugin and invokes the function, end
  *  of story.
index 23354a6..c0408ce 100644 (file)
@@ -663,7 +663,6 @@ static int disk_read(void) {
 
   char *fields[32];
   int numfields;
-  int fieldshift = 0;
 
   int minor = 0;
 
@@ -684,14 +683,8 @@ static int disk_read(void) {
   diskstats_t *ds, *pre_ds;
 
   if ((fh = fopen("/proc/diskstats", "r")) == NULL) {
-    fh = fopen("/proc/partitions", "r");
-    if (fh == NULL) {
-      ERROR("disk plugin: fopen (/proc/{diskstats,partitions}) failed.");
-      return -1;
-    }
-
-    /* Kernel is 2.4.* */
-    fieldshift = 1;
+    ERROR("disk plugin: fopen(\"/proc/diskstats\"): %s", STRERRNO);
+    return -1;
   }
 
   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
@@ -699,13 +692,12 @@ static int disk_read(void) {
     char *output_name;
 
     numfields = strsplit(buffer, fields, 32);
-
-    if ((numfields != (14 + fieldshift)) && (numfields != 7))
+    if ((numfields != 14) && (numfields != 7))
       continue;
 
     minor = atoll(fields[1]);
 
-    disk_name = fields[2 + fieldshift];
+    disk_name = fields[2];
 
     for (ds = disklist, pre_ds = disklist; ds != NULL;
          pre_ds = ds, ds = ds->next)
@@ -734,24 +726,24 @@ static int disk_read(void) {
       read_sectors = atoll(fields[4]);
       write_ops = atoll(fields[5]);
       write_sectors = atoll(fields[6]);
-    } else if (numfields == (14 + fieldshift)) {
-      read_ops = atoll(fields[3 + fieldshift]);
-      write_ops = atoll(fields[7 + fieldshift]);
+    } else if (numfields == 14) {
+      read_ops = atoll(fields[3]);
+      write_ops = atoll(fields[7]);
 
-      read_sectors = atoll(fields[5 + fieldshift]);
-      write_sectors = atoll(fields[9 + fieldshift]);
+      read_sectors = atoll(fields[5]);
+      write_sectors = atoll(fields[9]);
 
-      if ((fieldshift == 0) || (minor == 0)) {
+      if (minor == 0) {
         is_disk = 1;
-        read_merged = atoll(fields[4 + fieldshift]);
-        read_time = atoll(fields[6 + fieldshift]);
-        write_merged = atoll(fields[8 + fieldshift]);
-        write_time = atoll(fields[10 + fieldshift]);
+        read_merged = atoll(fields[4]);
+        read_time = atoll(fields[6]);
+        write_merged = atoll(fields[8]);
+        write_time = atoll(fields[10]);
 
-        in_progress = atof(fields[11 + fieldshift]);
+        in_progress = atof(fields[11]);
 
-        io_time = atof(fields[12 + fieldshift]);
-        weighted_time = atof(fields[13 + fieldshift]);
+        io_time = atof(fields[12]);
+        weighted_time = atof(fields[13]);
       }
     } else {
       DEBUG("numfields = %i; => unknown file format.", numfields);
index b145e81..77b1375 100644 (file)
@@ -78,6 +78,11 @@ typedef struct program_list_and_notification_s {
 } program_list_and_notification_t;
 
 /*
+ * constants
+ */
+const long int MAX_GRBUF_SIZE = 65536;
+
+/*
  * Private variables
  */
 static program_list_t *pl_head;
@@ -340,6 +345,65 @@ static void close_pipe(int fd_pipe[2]) /* {{{ */
 } /* }}} void close_pipe */
 
 /*
+ * Get effective group ID from group name.
+ * Input arguments:
+ *       pl  :program list struct with group name
+ *       gid :group id to fallback in case egid cannot be determined.
+ * Returns:
+ *       egid effective group id if successfull,
+ *            -1 if group is not defined/not found.
+ *            -2 for any buffer allocation error.
+ */
+static int getegr_id(program_list_t *pl, int gid) /* {{{ */
+{
+  if (pl->group == NULL) {
+    return -1;
+  }
+  if (strcmp(pl->group, "") == 0) {
+    return gid;
+  }
+  struct group *gr_ptr = NULL;
+  struct group gr;
+
+  long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+  if (grbuf_size <= 0)
+    grbuf_size = sysconf(_SC_PAGESIZE);
+  if (grbuf_size <= 0)
+    grbuf_size = 4096;
+
+  char *temp = NULL;
+  char *grbuf = NULL;
+
+  do {
+    temp = realloc(grbuf, grbuf_size);
+    if (temp == NULL) {
+      ERROR("exec plugin: getegr_id for %s: realloc buffer[%ld] failed ",
+            pl->group, grbuf_size);
+      sfree(grbuf);
+      return -2;
+    }
+    grbuf = temp;
+    if (getgrnam_r(pl->group, &gr, grbuf, grbuf_size, &gr_ptr) == 0) {
+      sfree(grbuf);
+      if (gr_ptr == NULL) {
+        ERROR("exec plugin: No such group: `%s'", pl->group);
+        return -1;
+      }
+      return gr.gr_gid;
+    } else if (errno == ERANGE) {
+      grbuf_size += grbuf_size; // increment buffer size and try again
+    } else {
+      ERROR("exec plugin: getegr_id failed %s", STRERRNO);
+      sfree(grbuf);
+      return -2;
+    }
+  } while (grbuf_size <= MAX_GRBUF_SIZE);
+  ERROR("exec plugin: getegr_id Max grbuf size reached  for %s", pl->group);
+  sfree(grbuf);
+  return -2;
+}
+
+/*
  * Creates three pipes (one for reading, one for writing and one for errors),
  * forks a child, sets up the pipes so that fd_in is connected to STDIN of
  * the child and fd_out is connected to STDOUT and fd_err is connected to STDERR
@@ -397,36 +461,10 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out,
 
   /* The group configured in the configfile is set as effective group, because
    * this way the forked process can (re-)gain the user's primary group. */
-  egid = -1;
-  if (pl->group != NULL) {
-    if (*pl->group != '\0') {
-      struct group *gr_ptr = NULL;
-      struct group gr;
-
-      long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
-      if (grbuf_size <= 0)
-        grbuf_size = sysconf(_SC_PAGESIZE);
-      if (grbuf_size <= 0)
-        grbuf_size = 4096;
-      char grbuf[grbuf_size];
-
-      status = getgrnam_r(pl->group, &gr, grbuf, sizeof(grbuf), &gr_ptr);
-      if (status != 0) {
-        ERROR("exec plugin: Failed to get group information "
-              "for group ``%s'': %s",
-              pl->group, STRERROR(status));
-        goto failed;
-      }
-      if (gr_ptr == NULL) {
-        ERROR("exec plugin: No such group: `%s'", pl->group);
-        goto failed;
-      }
-
-      egid = gr.gr_gid;
-    } else {
-      egid = gid;
-    }
-  } /* if (pl->group == NULL) */
+  egid = getegr_id(pl, gid);
+  if (egid == -2) {
+    goto failed;
+  }
 
   pid = fork();
   if (pid < 0) {
index 1d32d04..b22c3a2 100644 (file)
--- a/src/gps.c
+++ b/src/gps.c
@@ -141,7 +141,12 @@ static void *cgps_thread(void *pData) {
         continue;
       }
 
-      if (gps_read(&gpsd_conn) == -1) {
+#if GPSD_API_MAJOR_VERSION > 6
+      if (gps_read(&gpsd_conn, NULL, 0) == -1)
+#else
+      if (gps_read(&gpsd_conn) == -1)
+#endif
+      {
         WARNING("gps plugin: incorrect data! (err_count: %d)", err_count);
         err_count++;
 
index 2687616..629c367 100644 (file)
@@ -100,7 +100,7 @@ static int server_multicast_join(lcc_listener_t *srv,
     };
 #else
     struct ip_mreq mreq = {
-        .imr_address.s_addr = INADDR_ANY, .imr_multiaddr.s_addr = sa->s_addr,
+        .imr_multiaddr.s_addr = sa->sin_addr.s_addr,
     };
 #endif /* WIN32 */
 #endif /* HAVE_STRUCT_IP_MREQN_IMR_IFINDEX */
index eae0b18..49aa229 100644 (file)
@@ -145,7 +145,6 @@ static int values_to_json(char *buffer, size_t buffer_size, /* {{{ */
 
 #undef BUFFER_ADD
 
-  DEBUG("format_json: values_to_json: buffer = %s;", buffer);
   sfree(rates);
   return 0;
 } /* }}} int values_to_json */
@@ -179,8 +178,6 @@ static int dstypes_to_json(char *buffer, size_t buffer_size, /* {{{ */
 
 #undef BUFFER_ADD
 
-  DEBUG("format_json: dstypes_to_json: buffer = %s;", buffer);
-
   return 0;
 } /* }}} int dstypes_to_json */
 
@@ -213,8 +210,6 @@ static int dsnames_to_json(char *buffer, size_t buffer_size, /* {{{ */
 
 #undef BUFFER_ADD
 
-  DEBUG("format_json: dsnames_to_json: buffer = %s;", buffer);
-
   return 0;
 } /* }}} int dsnames_to_json */
 
@@ -378,8 +373,6 @@ static int value_list_to_json(char *buffer, size_t buffer_size, /* {{{ */
 #undef BUFFER_ADD_KEYVAL
 #undef BUFFER_ADD
 
-  DEBUG("format_json: value_list_to_json: buffer = %s;", buffer);
-
   return 0;
 } /* }}} int value_list_to_json */
 
index 2e597f3..4208d36 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/wireless.c
- * Copyright (C) 2006,2007  Florian octo Forster
+ * Copyright (C) 2006-2018  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"),
 #include "common.h"
 #include "plugin.h"
 
-#if !KERNEL_LINUX
+#if KERNEL_LINUX
+#include <linux/if.h>
+#include <linux/wireless.h>
+#include <sys/ioctl.h>
+#else
 #error "No applicable input method."
 #endif
 
@@ -90,7 +94,14 @@ static int wireless_read(void) {
 
   /* there are a variety of names for the wireless device */
   if ((fh = fopen(WIRELESS_PROC_FILE, "r")) == NULL) {
-    WARNING("wireless: fopen: %s", STRERRNO);
+    ERROR("wireless plugin: fopen: %s", STRERRNO);
+    return -1;
+  }
+
+  int sock = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock == -1) {
+    ERROR("wireless plugin: socket: %s", STRERRNO);
+    fclose(fh);
     return -1;
   }
 
@@ -142,9 +153,20 @@ static int wireless_read(void) {
     wireless_submit(device, "signal_power", power);
     wireless_submit(device, "signal_noise", noise);
 
+    struct iwreq req = {
+        .ifr_ifrn.ifrn_name = {0},
+    };
+    sstrncpy(req.ifr_ifrn.ifrn_name, device, sizeof(req.ifr_ifrn.ifrn_name));
+    if (ioctl(sock, SIOCGIWRATE, &req) == -1) {
+      WARNING("wireless plugin: ioctl(SIOCGIWRATE): %s", STRERRNO);
+    } else {
+      wireless_submit(device, "bitrate", (double)req.u.bitrate.value);
+    }
+
     devices_found++;
   }
 
+  close(sock);
   fclose(fh);
 
   /* If no wireless devices are present return an error, so the plugin