processes plugin: Fix compilation when ps_delay() not used.
[collectd.git] / src / processes.c
index 30f4e32..7c7b4b4 100644 (file)
 #include <kstat.h>
 #endif
 
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+
 #ifndef CMDLINE_BUFFER_SIZE
 #if defined(ARG_MAX) && (ARG_MAX < 4096)
 #define CMDLINE_BUFFER_SIZE ARG_MAX
@@ -653,7 +657,7 @@ static void ps_tune_instance(oconfig_item_t *ci, procstat_t *ps) {
               "for the \"CollectDelayAccounting\" option.");
 #endif
     } else {
-      ERROR("processes plugin: Option `%s' not allowed heeere.", c->key);
+      ERROR("processes plugin: Option \"%s\" not allowed here.", c->key);
     }
   } /* for (ci->children) */
 } /* void ps_tune_instance */
@@ -899,38 +903,27 @@ static void ps_submit_proc_list(procstat_t *ps) {
     plugin_dispatch_values(&vl);
   }
 
-  /* The ps->delay_* metrics are in nanoseconds per second. This factor converts
-   * them to a percentage. */
-  gauge_t const delay_factor = 100.0 / 1000000000.0;
-
-  if (!isnan(ps->delay_cpu)) {
-    sstrncpy(vl.type, "percent", sizeof(vl.type));
-    sstrncpy(vl.type_instance, "delay-cpu", sizeof(vl.type_instance));
-    vl.values[0].gauge = ps->delay_cpu * delay_factor;
-    vl.values_len = 1;
-    plugin_dispatch_values(&vl);
-  }
-
-  if (!isnan(ps->delay_blkio)) {
-    sstrncpy(vl.type, "percent", sizeof(vl.type));
-    sstrncpy(vl.type_instance, "delay-blkio", sizeof(vl.type_instance));
-    vl.values[0].gauge = ps->delay_blkio * delay_factor;
-    vl.values_len = 1;
-    plugin_dispatch_values(&vl);
-  }
-
-  if (!isnan(ps->delay_swapin)) {
-    sstrncpy(vl.type, "percent", sizeof(vl.type));
-    sstrncpy(vl.type_instance, "delay-swapin", sizeof(vl.type_instance));
-    vl.values[0].gauge = ps->delay_swapin * delay_factor;
-    vl.values_len = 1;
-    plugin_dispatch_values(&vl);
-  }
-
-  if (!isnan(ps->delay_freepages)) {
-    sstrncpy(vl.type, "percent", sizeof(vl.type));
-    sstrncpy(vl.type_instance, "delay-freepages", sizeof(vl.type_instance));
-    vl.values[0].gauge = ps->delay_freepages * delay_factor;
+  /* The ps->delay_* metrics are in nanoseconds per second. Convert to seconds
+   * per second. */
+  gauge_t const delay_factor = 1000000000.0;
+
+  struct {
+    char *type_instance;
+    gauge_t rate_ns;
+  } delay_metrics[] = {
+      {"delay-cpu", ps->delay_cpu},
+      {"delay-blkio", ps->delay_blkio},
+      {"delay-swapin", ps->delay_swapin},
+      {"delay-freepages", ps->delay_freepages},
+  };
+  for (size_t i = 0; i < STATIC_ARRAY_SIZE(delay_metrics); i++) {
+    if (isnan(delay_metrics[i].rate_ns)) {
+      continue;
+    }
+    sstrncpy(vl.type, "delay_rate", sizeof(vl.type));
+    sstrncpy(vl.type_instance, delay_metrics[i].type_instance,
+             sizeof(vl.type_instance));
+    vl.values[0].gauge = delay_metrics[i].rate_ns * delay_factor;
     vl.values_len = 1;
     plugin_dispatch_values(&vl);
   }
@@ -1215,10 +1208,38 @@ static int ps_delay(process_entry_t *ps) {
   int status = ts_delay_by_tgid(taskstats_handle, (uint32_t)ps->id, &ps->delay);
   if (status == EPERM) {
     static c_complain_t c;
-    c_complain(LOG_ERR, &c, "processes plugin: reading delay information "
-                            "failed: \"%s\". This is probably because the "
-                            "taskstats interface requires root privileges.",
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_ADMIN)
+    if (check_capability(CAP_NET_ADMIN) != 0) {
+      if (getuid() == 0) {
+        c_complain(
+            LOG_ERR, &c,
+            "processes plugin: Reading Delay Accounting metric failed: %s. "
+            "collectd is running as root, but missing the CAP_NET_ADMIN "
+            "capability. The most common cause for this is that the init "
+            "system is dropping capabilities.",
+            STRERROR(status));
+      } else {
+        c_complain(
+            LOG_ERR, &c,
+            "processes plugin: Reading Delay Accounting metric failed: %s. "
+            "collectd is not running as root and missing the CAP_NET_ADMIN "
+            "capability. Either run collectd as root or grant it the "
+            "CAP_NET_ADMIN capability using \"setcap cap_net_admin=ep " PREFIX
+            "/sbin/collectd\".",
+            STRERROR(status));
+      }
+    } else {
+      ERROR("processes plugin: ts_delay_by_tgid failed: %s. The CAP_NET_ADMIN "
+            "capability is available (I checked), so this error is utterly "
+            "unexpected.",
+            STRERROR(status));
+    }
+#else
+    c_complain(LOG_ERR, &c,
+               "processes plugin: Reading Delay Accounting metric failed: %s. "
+               "Reading Delay Accounting metrics requires root privileges.",
                STRERROR(status));
+#endif
     return status;
   } else if (status != 0) {
     ERROR("processes plugin: ts_delay_by_tgid failed: %s", STRERROR(status));
@@ -1227,10 +1248,6 @@ static int ps_delay(process_entry_t *ps) {
 
   return 0;
 }
-#else
-static int ps_delay(__attribute__((unused)) process_entry_t *unused) {
-  return -1;
-}
 #endif
 
 static void ps_fill_details(const procstat_t *ps, process_entry_t *entry) {
@@ -1757,8 +1774,7 @@ static int mach_get_task_name(task_t t, int *pid, char *name,
   return 0;
 }
 #endif /* HAVE_THREAD_INFO */
-/* ------- end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO -------
- */
+/* end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO */
 
 /* do actual readings from kernel */
 static int ps_read(void) {