#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
"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 */
#if KERNEL_LINUX || KERNEL_SOLARIS || KERNEL_FREEBSD
if (strlen(c->values[0].value.string) > max_procname_len) {
- WARNING("processes plugin: this platform has a %zu character limit "
+ WARNING("processes plugin: this platform has a %" PRIsz
+ " character limit "
"to process names. The `Process \"%s\"' option will "
"not work as expected.",
max_procname_len, c->values[0].value.string);
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);
}
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));
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) {
/* 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) {
- ERROR("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
+ ERROR("processes plugin: name_start_pos = %" PRIsz
+ " >= name_end_pos = %" PRIsz,
name_start_pos, name_end_pos);
return -1;
}
if ((status < 0) || (((size_t)status) != sizeof(info))) {
ERROR("processes plugin: Unexpected return value "
"while reading \"%s\": "
- "Returned %zd but expected %zu.",
+ "Returned %zd but expected %" PRIsz ".",
path, status, buffer_size);
return NULL;
}
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) {