[collectd] [PATCH] cgroup plugin: add new plugin for monitoring cgroup stats
Bruno Prémont
bonbons at linux-vserver.org
Wed Mar 21 21:44:13 CET 2012
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 <bonbons at linux-vserver.org>
---
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 <bonbons at linux-vserver.org>
+ **/
+
+#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 at LoadPlugin ascent
#@BUILD_PLUGIN_BATTERY_TRUE at LoadPlugin battery
#@BUILD_PLUGIN_BIND_TRUE at LoadPlugin bind
+#@BUILD_PLUGIN_CGROUP_TRUE at LoadPlugin cgroup
#@BUILD_PLUGIN_CONNTRACK_TRUE at LoadPlugin conntrack
#@BUILD_PLUGIN_CONTEXTSWITCH_TRUE at LoadPlugin contextswitch
@BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE at 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
More information about the collectd
mailing list