This new plugin adds support for monitoring (some) cgroup statistics. It considers: - memory controller - cpuacct controller - count of processes in cgroup
Each cgroup to be monitored has to be explicitly listed in, configuration relatives paths are expected to be absolute, usually in the form /sys/fs/cgroup/<cgroup> Signed-off-by: Bruno Prémont <[email protected]> --- diff -NurpP collectd-5.0.1.orig/configure.in collectd-5.0.1/configure.in --- collectd-5.0.1.orig/configure.in 2011-10-31 19:42:23.597249677 +0100 +++ collectd-5.0.1/configure.in 2011-10-31 19:46:32.125788396 +0100 @@ -4321,6 +4321,7 @@ dependency_error="no" plugin_ascent="no" plugin_battery="no" plugin_bind="no" +plugin_cgroup="no" plugin_conntrack="no" plugin_contextswitch="no" plugin_cpu="no" @@ -4360,6 +4361,7 @@ plugin_zfs_arc="no" if test "x$ac_system" = "xLinux" then plugin_battery="yes" + plugin_cgroup="yes" plugin_conntrack="yes" plugin_contextswitch="yes" plugin_cpu="yes" @@ -4620,6 +4622,7 @@ AC_PLUGIN([apple_sensors], [$with_libiok AC_PLUGIN([ascent], [$plugin_ascent], [AscentEmu player statistics]) AC_PLUGIN([battery], [$plugin_battery], [Battery statistics]) AC_PLUGIN([bind], [$plugin_bind], [ISC Bind nameserver statistics]) +AC_PLUGIN([cgroup], [$plugin_cgroup], [Linux cgroup statistics]) AC_PLUGIN([conntrack], [$plugin_conntrack], [nf_conntrack statistics]) AC_PLUGIN([contextswitch], [$plugin_contextswitch], [context switch statistics]) AC_PLUGIN([cpufreq], [$plugin_cpufreq], [CPU frequency statistics]) diff -NurpP collectd-5.0.1.orig/src/cgroup.c collectd-5.0.1/src/cgroup.c --- collectd-5.0.1.orig/src/cgroup.c 1970-01-01 01:00:00.000000000 +0100 +++ collectd-5.0.1/src/cgroup.c 2011-10-31 23:34:43.216403906 +0100 @@ -0,0 +1,275 @@ +/** + * collectd - src/cgroup.c + * Copyright (C) 2011 Bruno Prémont + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the license is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Bruno Prémont <[email protected]> + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#include <dirent.h> +#include <sys/types.h> +#include <unistd.h> + +#define BUFSIZE 512 + +#if !KERNEL_LINUX +# error "No applicable input method." +#endif + +static const char *config_keys[] = +{ + "CGroup" +}; +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); + +typedef struct { + const char *name; + const char *path; + int fail_cnt; +} cgroup_t; +static cgroup_t **cgroup_list = NULL; +int cgroup_num = 0; + +static int cgroup_config (const char *key, const char *value) +{ + if (strcasecmp (key, "CGroup") == 0) + { + cgroup_t *cg, **list; + char *tmp; + char *fields[2]; + int fields_num, value_len; + + value_len = strlen(value)+1; + cg = malloc(value_len + sizeof(cgroup_t)); + if (cg == NULL) + { + char errbuf[1024]; + ERROR ("malloc failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (1); + } + tmp = (char *)&cg[1]; + memcpy(tmp, value, value_len); + + fields_num = strsplit (tmp, fields, 2); + if (fields_num < 2) + { + free(cg); + return (1); + } + cg->name = fields[0]; + cg->path = fields[1]; + cg->fail_cnt = 0; + + list = (cgroup_t **) realloc (cgroup_list, (cgroup_num + 1) * sizeof (cgroup_t *)); + if (list == NULL) + { + char errbuf[1024]; + ERROR ("realloc failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + free(cg); + return (1); + } + + cgroup_list = list; + cgroup_list[cgroup_num] = cg; + cgroup_num++; + } + + return (-1); +} + +static int cgroup_read_memory (const char *cgroup, const char *file) +{ + FILE *fh; + char buffer[BUFSIZE]; + char *cols[2]; + + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + vl.values = values; + vl.values_len = STATIC_ARRAY_SIZE (values); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "cgroup", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, cgroup, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, "memory", sizeof (vl.type)); + + if (NULL == (fh = fopen (file, "r"))) + { + char errbuf[1024]; + if (errno != ENOENT) + ERROR ("Cannot open '%s': %s", file, + sstrerror (errno, errbuf, sizeof (errbuf))); + return (1); + } + + while (NULL != fgets (buffer, BUFSIZE, fh)) + { + if (strsplit (buffer, cols, 2) < 2) + continue; + + if (0 == strncmp (cols[0], "total_", 6)) + continue; + + values[0].gauge = atof (cols[1]); + + sstrncpy (vl.type_instance, cols[0], sizeof (vl.type_instance)); + plugin_dispatch_values (&vl); + } /* while (fgets) */ + + fclose (fh); + return 0; +} /* int cgroup_read_memory */ + +static int cgroup_read_procs (const char *cgroup, const char *file) +{ + FILE *fh; + char buffer[BUFSIZE]; + + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + vl.values = values; + vl.values_len = STATIC_ARRAY_SIZE (values); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "cgroup", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, cgroup, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, "vs_processes", sizeof (vl.type)); + sstrncpy (vl.type_instance, "", sizeof (vl.type_instance)); + + if (NULL == (fh = fopen (file, "r"))) + { + char errbuf[1024]; + if (errno != ENOENT) + ERROR ("Cannot open '%s': %s", file, + sstrerror (errno, errbuf, sizeof (errbuf))); + return (1); + } + + values[0].gauge = 0; + while (NULL != fgets (buffer, BUFSIZE, fh)) + { + values[0].gauge++; + } /* while (fgets) */ + + plugin_dispatch_values (&vl); + fclose (fh); + return 0; +} /* int cgroup_read_memory */ + +static int cgroup_read_cpuacct (const char *cgroup, const char *file) +{ + FILE *fh; + char buffer[BUFSIZE]; + char *cols[2]; + + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + vl.values = values; + vl.values_len = STATIC_ARRAY_SIZE (values); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "cgroup", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, cgroup, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, "cpu", sizeof (vl.type)); + + if (NULL == (fh = fopen (file, "r"))) + { + char errbuf[1024]; + if (errno != ENOENT) + ERROR ("Cannot open '%s': %s", file, + sstrerror (errno, errbuf, sizeof (errbuf))); + return (1); + } + + while (NULL != fgets (buffer, BUFSIZE, fh)) + { + if (strsplit (buffer, cols, 2) < 2) + continue; + + if (parse_value (cols[1], &values[0], DS_TYPE_DERIVE) != 0) + continue; + + sstrncpy (vl.type_instance, cols[0], sizeof (vl.type_instance)); + plugin_dispatch_values (&vl); + } /* while (fgets) */ + + fclose (fh); + return (0); +} /* int cgroup_read_cpuacct */ + +static int cgroup_read (void) +{ + int i; + + for (i = 0; i < cgroup_num; i++) + { + int len; + char file[BUFSIZE]; + + if (access(cgroup_list[i]->path, R_OK | X_OK) != 0) + { + char errbuf[1024]; + cgroup_list[i]->fail_cnt++; + if (cgroup_list[i]->fail_cnt != 1) + continue; + ERROR ("Cannot access '%s': %s", file, + sstrerror (errno, errbuf, sizeof (errbuf))); + } + + len = ssnprintf (file, sizeof (file), "%s/%s", cgroup_list[i]->path, "memory.stat"); + if ((len >= 0) && (len < BUFSIZE)) + cgroup_read_memory(cgroup_list[i]->name, file); + + len = ssnprintf (file, sizeof (file), "%s/%s", cgroup_list[i]->path, "cpuacct.stat"); + if ((len >= 0) && (len < BUFSIZE)) + cgroup_read_cpuacct(cgroup_list[i]->name, file); + + len = ssnprintf (file, sizeof (file), "%s/%s", cgroup_list[i]->path, "cgroup.procs"); + if ((len >= 0) && (len < BUFSIZE)) + cgroup_read_procs(cgroup_list[i]->name, file); + } + return (0); +} /* int cgroup_read */ + +static int cgroup_shutdown (void) +{ + int i; + + for (i = 0; i < cgroup_num; i++) + { + sfree(cgroup_list[i]); + } + sfree(cgroup_list); + cgroup_num = 0; + + return (0); +} + +void module_register (void) +{ + plugin_register_config ("cgroup", cgroup_config, + config_keys, config_keys_num); + plugin_register_read ("cgroup", cgroup_read); + plugin_register_shutdown ("cgroup", cgroup_shutdown); +} /* void module_register(void) */ + +/* vim: set ts=4 sw=4 noexpandtab : */ diff -NurpP collectd-5.0.1.orig/src/collectd.conf.in collectd-5.0.1/src/collectd.conf.in --- collectd-5.0.1.orig/src/collectd.conf.in 2011-10-31 19:42:23.997215140 +0100 +++ collectd-5.0.1/src/collectd.conf.in 2011-10-31 22:27:23.381885858 +0100 @@ -59,6 +59,7 @@ #@BUILD_PLUGIN_ASCENT_TRUE@LoadPlugin ascent #@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery #@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind +#@BUILD_PLUGIN_CGROUP_TRUE@LoadPlugin cgroup #@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack #@BUILD_PLUGIN_CONTEXTSWITCH_TRUE@LoadPlugin contextswitch @BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu @@ -210,6 +211,11 @@ # </View> #</Plugin> +#<Plugin cgroup> +# CGroup root /sys/fs/cgroup +# CGroup test /sys/fs/cgroup/test +#</Plugin> + #<Plugin csv> # DataDir "/var/lib/@PACKAGE_NAME@/csv" # StoreRates false diff -NurpP collectd-5.0.1.orig/src/collectd.conf.pod collectd-5.0.1/src/collectd.conf.pod --- collectd-5.0.1.orig/src/collectd.conf.pod 2011-10-14 22:49:49.000000000 +0200 +++ collectd-5.0.1/src/collectd.conf.pod 2011-10-31 22:50:40.568106455 +0100 @@ -604,6 +604,25 @@ By default no detailed zone information =back +=head2 Plugin C<cgroup> + +This plugin collects statistics about cgroups. It monitors B<"process count"> +(I<Path>/procs), B<"memory usage"> (I<Path>/memory.stat) and B<"CPU activity"> +(I<Path>/cpuacct.stat). + +Which ones are available depend on kernel support and mount options passed when +mounting the cgroup filesystem to enable given sussystems. + +=over 1 + +=item B<CGroup> I<Name> I<Path> + +Add a cgroup to monitor. I<Name> will get used as plugin-instance and I<Path> +is the directory under which to look for statistics files (usually in the form +F</sys/fs/cgroup/NAME>). + +=back + =head2 Plugin C<cpufreq> This plugin doesn't have any options. It reads diff -NurpP collectd-5.0.1.orig/src/Makefile.am collectd-5.0.1/src/Makefile.am --- collectd-5.0.1.orig/src/Makefile.am 2011-10-31 19:42:23.427264356 +0100 +++ collectd-5.0.1/src/Makefile.am 2011-10-31 19:43:34.661113073 +0100 @@ -1031,6 +1031,14 @@ collectd_LDADD += "-dlopen" table.la collectd_DEPENDENCIES += table.la endif +if BUILD_PLUGIN_CGROUP +pkglib_LTLIBRARIES += cgroup.la +cgroup_la_SOURCES = cgroup.c +cgroup_la_LDFLAGS = -module -avoid-version +collectd_LDADD += "-dlopen" cgroup.la +collectd_DEPENDENCIES += cgroup.la +endif + if BUILD_PLUGIN_TAIL pkglib_LTLIBRARIES += tail.la tail_la_SOURCES = tail.c _______________________________________________ collectd mailing list [email protected] http://mailman.verplant.org/listinfo/collectd
