$(NULL)
dist_plugins_SCRIPTS = \
+ cgroup-name.sh \
charts.d.dryrun-helper.sh \
charts.d.plugin \
node.d.plugin \
--- /dev/null
+#!/bin/bash
+
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
+
+NETDATA_CONFIG_DIR="${NETDATA_CONFIG_DIR-/etc/netdata}"
+CONFIG="${NETDATA_CONFIG_DIR}/cgroups-names.conf"
+CGROUP="${1}"
+NAME=
+
+if [ -z "${CGROUP}" ]
+ then
+ echo >&2 "${0}: called without a cgroup name. Nothing to do."
+ exit 1
+fi
+
+if [ -f "${CONFIG}" ]
+ then
+ NAME="$(cat "${CONFIG}" | grep "^${CGROUP}" | cut -d ' ' -f 2)"
+ if [ -z "${NAME}" ]
+ then
+ echo >&2 "${0}: cannot find cgroup '${CGROUP}' in '${CONFIG}'."
+ fi
+else
+ echo >&2 "${0}: configuration file '${CONFIG}' is not available."
+fi
+
+if [ -z "${NAME}" ]
+ then
+ if [ ${#CGROUP} -gt 12 ]
+ then
+ NAME="${CGROUP:0:12}"
+ else
+ NAME="${CGROUP}"
+ fi
+fi
+
+echo >&2 "${0}: cgroup '${CGROUP}' is named as '${NAME}'"
+echo "${NAME}"
}
}
-unsigned long long sutime() {
- struct timeval now;
- gettimeofday(&now, NULL);
- return now.tv_sec * 1000000ULL + now.tv_usec;
-}
-
int main(int argc, char **argv)
{
// debug_flags = D_PROCFILE;
for(;1; counter++) {
#ifndef PROFILING_MODE
// delay until it is our time to run
- while((sunow = sutime()) < sunext)
+ while((sunow = timems()) < sunext)
usleep((useconds_t)(sunext - sunow));
// find the next time we need to run
- while(sutime() > sunext)
+ while(timems() > sunext)
sunext += update_every * 1000000ULL;
#endif /* PROFILING_MODE */
char *global_host_prefix = "";
int enable_ksm = 1;
+// time(NULL) in milliseconds
+unsigned long long timems(void) {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return now.tv_sec * 1000000ULL + now.tv_usec;
+}
+
unsigned char netdata_map_chart_names[256] = {
[0] = '\0', //
[1] = '_', //
extern pid_t gettid(void);
+extern unsigned long long timems(void);
+
/* fix for alpine linux */
#ifndef RUSAGE_THREAD
#ifdef RUSAGE_CHILDREN
#include "plugin_nfacct.h"
#include "main.h"
-#include "../config.h"
+
+extern void *cgroups_main(void *ptr);
int netdata_exit = 0;
{"tc", "plugins", "tc", 1, NULL, NULL, tc_main},
{"idlejitter", "plugins", "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
{"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
+ {"cgroups", "plugins", "cgroups", 1, NULL, NULL, cgroups_main},
#ifdef INTERNAL_PLUGIN_NFACCT
// nfacct requires root access
#include "plugin_proc.h"
#include "main.h"
-unsigned long long sutime() {
- struct timeval now;
- gettimeofday(&now, NULL);
- return now.tv_sec * 1000000ULL + now.tv_usec;
-}
-
void *proc_main(void *ptr)
{
if(ptr) { ; }
int vdo_proc_loadavg = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
int vdo_sys_kernel_mm_ksm = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
int vdo_cpu_netdata = !config_get_boolean("plugin:proc", "netdata server resources", 1);
- int vdo_sys_fs_cgroup = !config_get_boolean("plugin:proc", "cgroups", 1);
// keep track of the time each module was called
unsigned long long sutime_proc_net_dev = 0ULL;
unsigned long long sutime_proc_softirqs = 0ULL;
unsigned long long sutime_proc_loadavg = 0ULL;
unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
- unsigned long long sutime_sys_fs_cgroup = 0ULL;
// the next time we will run - aligned properly
unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
if(unlikely(netdata_exit)) break;
// delay until it is our time to run
- while((sunow = sutime()) < sunext)
+ while((sunow = timems()) < sunext)
usleep((useconds_t)(sunext - sunow));
// find the next time we need to run
- while(sutime() > sunext)
+ while(timems() > sunext)
sunext += rrd_update_every * 1000000ULL;
if(unlikely(netdata_exit)) break;
if(!vdo_sys_kernel_mm_ksm) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_kernel_mm_ksm().");
- sunow = sutime();
+ sunow = timems();
vdo_sys_kernel_mm_ksm = do_sys_kernel_mm_ksm(rrd_update_every, (sutime_sys_kernel_mm_ksm > 0)?sunow - sutime_sys_kernel_mm_ksm:0ULL);
sutime_sys_kernel_mm_ksm = sunow;
}
if(!vdo_proc_loadavg) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?sunow - sutime_proc_loadavg:0ULL);
sutime_proc_loadavg = sunow;
}
if(!vdo_proc_interrupts) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_interrupts = do_proc_interrupts(rrd_update_every, (sutime_proc_interrupts > 0)?sunow - sutime_proc_interrupts:0ULL);
sutime_proc_interrupts = sunow;
}
if(!vdo_proc_softirqs) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_softirqs().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_softirqs = do_proc_softirqs(rrd_update_every, (sutime_proc_softirqs > 0)?sunow - sutime_proc_softirqs:0ULL);
sutime_proc_softirqs = sunow;
}
if(!vdo_proc_sys_kernel_random_entropy_avail) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_sys_kernel_random_entropy_avail().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_sys_kernel_random_entropy_avail = do_proc_sys_kernel_random_entropy_avail(rrd_update_every, (sutime_proc_sys_kernel_random_entropy_avail > 0)?sunow - sutime_proc_sys_kernel_random_entropy_avail:0ULL);
sutime_proc_sys_kernel_random_entropy_avail = sunow;
}
if(!vdo_proc_net_dev) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_dev().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_dev = do_proc_net_dev(rrd_update_every, (sutime_proc_net_dev > 0)?sunow - sutime_proc_net_dev:0ULL);
sutime_proc_net_dev = sunow;
}
if(!vdo_proc_diskstats) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_diskstats().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_diskstats = do_proc_diskstats(rrd_update_every, (sutime_proc_diskstats > 0)?sunow - sutime_proc_diskstats:0ULL);
sutime_proc_diskstats = sunow;
}
if(!vdo_proc_net_snmp) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_snmp = do_proc_net_snmp(rrd_update_every, (sutime_proc_net_snmp > 0)?sunow - sutime_proc_net_snmp:0ULL);
sutime_proc_net_snmp = sunow;
}
if(!vdo_proc_net_snmp6) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_snmp6 = do_proc_net_snmp6(rrd_update_every, (sutime_proc_net_snmp6 > 0)?sunow - sutime_proc_net_snmp6:0ULL);
sutime_proc_net_snmp6 = sunow;
}
if(!vdo_proc_net_netstat) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_netstat().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_netstat = do_proc_net_netstat(rrd_update_every, (sutime_proc_net_netstat > 0)?sunow - sutime_proc_net_netstat:0ULL);
sutime_proc_net_netstat = sunow;
}
if(!vdo_proc_net_stat_conntrack) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_stat_conntrack().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(rrd_update_every, (sutime_proc_net_stat_conntrack > 0)?sunow - sutime_proc_net_stat_conntrack:0ULL);
sutime_proc_net_stat_conntrack = sunow;
}
if(!vdo_proc_net_ip_vs_stats) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_ip_vs_stats().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(rrd_update_every, (sutime_proc_net_ip_vs_stats > 0)?sunow - sutime_proc_net_ip_vs_stats:0ULL);
sutime_proc_net_ip_vs_stats = sunow;
}
if(!vdo_proc_net_stat_synproxy) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
sutime_proc_net_stat_synproxy = sunow;
}
if(!vdo_proc_stat) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?sunow - sutime_proc_stat:0ULL);
sutime_proc_stat = sunow;
}
if(!vdo_proc_meminfo) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_meminfo().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_meminfo = do_proc_meminfo(rrd_update_every, (sutime_proc_meminfo > 0)?sunow - sutime_proc_meminfo:0ULL);
sutime_proc_meminfo = sunow;
}
if(!vdo_proc_vmstat) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_vmstat().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_vmstat = do_proc_vmstat(rrd_update_every, (sutime_proc_vmstat > 0)?sunow - sutime_proc_vmstat:0ULL);
sutime_proc_vmstat = sunow;
}
if(!vdo_proc_net_rpc_nfsd) {
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_rpc_nfsd().");
- sunow = sutime();
+ sunow = timems();
vdo_proc_net_rpc_nfsd = do_proc_net_rpc_nfsd(rrd_update_every, (sutime_proc_net_rpc_nfsd > 0)?sunow - sutime_proc_net_rpc_nfsd:0ULL);
sutime_proc_net_rpc_nfsd = sunow;
}
if(unlikely(netdata_exit)) break;
- if(!vdo_sys_fs_cgroup) {
- debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
- sunow = sutime();
- vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
- sutime_sys_fs_cgroup = sunow;
- }
- if(unlikely(netdata_exit)) break;
-
// END -- the job is done
// --------------------------------------------------------------------
extern int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt);
extern int do_proc_loadavg(int update_every, unsigned long long dt);
extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
-extern int do_sys_fs_cgroup(int update_every, unsigned long long dt);
#endif /* NETDATA_PLUGIN_PROC_H */
#include "procfile.h"
#include "log.h"
#include "rrd.h"
+#include "main.h"
+#include "popen.h"
// ----------------------------------------------------------------------------
// cgroup globals
// ----------------------------------------------------------------------------
// add/remove/find cgroup objects
+#define CGROUP_NAME_LINE_MAX 1024
+
+void cgroup_get_name(struct cgroup *cg) {
+ pid_t cgroup_pid;
+ char buffer[CGROUP_NAME_LINE_MAX + 1];
+
+ snprintf(buffer, CGROUP_NAME_LINE_MAX, "exec %s '%s'",
+ config_get("plugin:cgroups", "script to get cgroup names", PLUGINS_DIR "/cgroup-name.sh"), cg->name);
+
+ FILE *fp = mypopen(buffer, &cgroup_pid);
+ if(!fp) {
+ error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
+ return;
+ }
+ char *s = fgets(buffer, CGROUP_NAME_LINE_MAX, fp);
+ mypclose(fp, cgroup_pid);
+
+ if(s && *s && *s != '\n') {
+ trim(s);
+ netdata_fix_chart_name(s);
+ free(cg->name);
+ cg->name = strdup(s);
+ if(!cg->name)
+ fatal("CGROUP: Cannot allocate memory for name cgroup %s name: '%s'", cg->id, s);
+ }
+}
+
struct cgroup *cgroup_add(const char *id) {
if(cgroup_root_count >= cgroup_root_max) {
info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
cgroup_root_count++;
// fprintf(stderr, " > added cgroup No %d, with id '%s' (%u) and name '%s'\n", cgroup_root_count, cg->id, cg->hash, cg->name);
+
+ // fix the name by calling the external script
+ cgroup_get_name(cg);
}
else fatal("Cannot allocate memory for cgroup '%s'", id);
if(cg->id[0] == '\0')
strcpy(type, "cgroup_host");
else if(cg->id[0] == '/')
- snprintf(type, RRD_ID_LENGTH_MAX, "cgroup%s", cg->id);
+ snprintf(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->name);
else
- snprintf(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->id);
+ snprintf(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->name);
netdata_fix_chart_id(type);
return 0;
}
+
+void *cgroups_main(void *ptr)
+{
+ if(ptr) { ; }
+
+ info("CGROUP Plugin thread created with task id %d", gettid());
+
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("Cannot set pthread cancel type to DEFERRED.");
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("Cannot set pthread cancel state to ENABLE.");
+
+ struct rusage thread;
+
+ // when ZERO, attempt to do it
+ int vdo_sys_fs_cgroup = 0;
+ int vdo_cpu_netdata = !config_get_boolean("plugin:cgroups", "netdata server resources", 1);
+
+ // keep track of the time each module was called
+ unsigned long long sutime_sys_fs_cgroup = 0ULL;
+
+ // the next time we will run - aligned properly
+ unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
+ unsigned long long sunow;
+
+ RRDSET *stcpu_thread = NULL;
+
+ for(;1;) {
+ if(unlikely(netdata_exit)) break;
+
+ // delay until it is our time to run
+ while((sunow = timems()) < sunext)
+ usleep((useconds_t)(sunext - sunow));
+
+ // find the next time we need to run
+ while(timems() > sunext)
+ sunext += rrd_update_every * 1000000ULL;
+
+ if(unlikely(netdata_exit)) break;
+
+ // BEGIN -- the job to be done
+
+ if(!vdo_sys_fs_cgroup) {
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
+ sunow = timems();
+ vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
+ sutime_sys_fs_cgroup = sunow;
+ }
+ if(unlikely(netdata_exit)) break;
+
+ // END -- the job is done
+
+ // --------------------------------------------------------------------
+
+ if(!vdo_cpu_netdata) {
+ getrusage(RUSAGE_THREAD, &thread);
+
+ if(!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
+ if(!stcpu_thread) {
+ stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "proc.internal", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 131000, rrd_update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ }
+ else rrdset_next(stcpu_thread);
+
+ rrddim_set(stcpu_thread, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
+ rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
+ rrdset_done(stcpu_thread);
+ }
+ }
+
+ pthread_exit(NULL);
+ return NULL;
+}