Merge branch 'ef/mic'
authorFlorian Forster <octo@collectd.org>
Tue, 21 May 2013 12:51:22 +0000 (14:51 +0200)
committerFlorian Forster <octo@collectd.org>
Tue, 21 May 2013 12:51:22 +0000 (14:51 +0200)
15 files changed:
AUTHORS
README
configure.in
src/Makefile.am
src/amqp.c
src/cgroups.c [new file with mode: 0644]
src/collectd.conf.in
src/collectd.conf.pod
src/common.c
src/common.h
src/curl_xml.c
src/lvm.c [new file with mode: 0644]
src/plugin.c
src/thermal.c
src/types.db

diff --git a/AUTHORS b/AUTHORS
index 3e990c1..9df0f7a 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,6 +47,9 @@ Bruno Prémont <bonbons at linux-vserver.org>
    especially a nasty bug in the network plugin.
  - Wireshark dissector.
 
+Chad Malfait <malfaitc at yahoo.com>
+ - LVM plugin.
+
 Chris Lundquist <clundquist at bluebox.net>
  - Improvements to the write_mongodb plugin.
 
@@ -129,6 +132,7 @@ Michael Hanselmann <public at hansmi.ch>
 
 Michael Stapelberg <michael+git at stapelberg.de>
  - OpenBSD port of the tcpconns plugin.
+ - cgroups plugin.
 
 Michał Mirosław <mirq-linux at rere.qmqm.pl>
  - thermal plugin.
diff --git a/README b/README
index 104bc4d..04e87ab 100644 (file)
--- a/README
+++ b/README
@@ -37,6 +37,9 @@ Features
       Name server and resolver statistics from the `statistics-channel'
       interface of BIND 9.5, 9,6 and later.
 
+    - cgroups
+      CPU accounting information for process groups under Linux.
+
     - conntrack
       Number of nf_conntrack entries.
 
@@ -135,6 +138,10 @@ Features
     - libvirt
       CPU, memory, disk and network I/O statistics from virtual machines.
 
+    - lvm
+      Size of “Logical Volumes” (LV) and “Volume Groups” (VG) of Linux'
+      “Logical Volume Manager” (LVM).
+
     - madwifi
       Queries very detailed usage statistics from wireless LAN adapters and
       interfaces that use the Atheros chipset and the MadWifi driver.
index a0c95a6..ba52389 100644 (file)
@@ -2152,6 +2152,58 @@ AC_SUBST(JAVA_LIBS)
 AM_CONDITIONAL(BUILD_WITH_JAVA, test "x$with_java" = "xyes")
 # }}}
 
+# --with-liblvm2app {{{
+with_liblvm2app_cppflags=""
+with_liblvm2app_ldflags=""
+AC_ARG_WITH(liblvm2app, [AS_HELP_STRING([--with-liblvm2app@<:@=PREFIX@:>@], [Path to liblvm2app.])],
+[
+        if test "x$withval" != "xno" && test "x$withval" != "xyes"
+        then
+                with_liblvm2app_cppflags="-I$withval/include"
+                with_liblvm2app_ldflags="-L$withval/lib"
+                with_liblvm2app="yes"
+        else
+                with_liblvm2app="$withval"
+        fi
+],
+[
+        with_liblvm2app="yes"
+])
+if test "x$with_liblvm2app" = "xyes"
+then
+        SAVE_CPPFLAGS="$CPPFLAGS"
+        CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
+
+        AC_CHECK_HEADERS(lvm2app.h, [with_liblvm2app="yes"], [with_liblvm2app="no (lvm2app.h not found)"])
+
+        CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+
+if test "x$with_liblvm2app" = "xyes"
+then
+        SAVE_CPPFLAGS="$CPPFLAGS"
+        SAVE_LDFLAGS="$LDFLAGS"
+        CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
+        LDFLAGS="$LDFLAGS $with_liblvm2app_ldflags"
+
+        AC_CHECK_LIB(lvm2app, lvm_init, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_init' not found)"])
+
+        CPPFLAGS="$SAVE_CPPFLAGS"
+        LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_liblvm2app" = "xyes"
+then
+        BUILD_WITH_LIBLVM2APP_CPPFLAGS="$with_liblvm2app_cppflags"
+        BUILD_WITH_LIBLVM2APP_LDFLAGS="$with_liblvm2app_ldflags"
+        BUILD_WITH_LIBLVM2APP_LIBS="-llvm2app"
+        AC_SUBST(BUILD_WITH_LIBLVM2APP_CPPFLAGS)
+        AC_SUBST(BUILD_WITH_LIBLVM2APP_LDFLAGS)
+        AC_SUBST(BUILD_WITH_LIBLVM2APP_LIBS)
+        AC_DEFINE(HAVE_LIBLVM2APP, 1, [Define if liblvm2app is present and usable.])
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBLVM2APP, test "x$with_liblvm2app" = "xyes")
+# }}}
+
 # --with-libmemcached {{{
 with_libmemcached_cppflags=""
 with_libmemcached_ldflags=""
@@ -4635,6 +4687,7 @@ dependency_error="no"
 plugin_ascent="no"
 plugin_battery="no"
 plugin_bind="no"
+plugin_cgroups="no"
 plugin_conntrack="no"
 plugin_contextswitch="no"
 plugin_cpu="no"
@@ -4678,6 +4731,7 @@ then
        plugin_battery="yes"
        plugin_conntrack="yes"
        plugin_contextswitch="yes"
+       plugin_cgroups="yes"
        plugin_cpu="yes"
        plugin_cpufreq="yes"
        plugin_disk="yes"
@@ -4686,6 +4740,7 @@ then
        plugin_interface="yes"
        plugin_irq="yes"
        plugin_load="yes"
+       plugin_lvm="yes"
        plugin_memory="yes"
        plugin_nfs="yes"
        plugin_numa="yes"
@@ -4960,6 +5015,7 @@ AC_PLUGIN([csv],         [yes],                [CSV output plugin])
 AC_PLUGIN([curl],        [$with_libcurl],      [CURL generic web statistics])
 AC_PLUGIN([curl_json],   [$plugin_curl_json],    [CouchDB statistics])
 AC_PLUGIN([curl_xml],   [$plugin_curl_xml],    [CURL generic xml statistics])
+AC_PLUGIN([cgroups],     [$plugin_cgroups],    [CGroups CPU usage accounting])
 AC_PLUGIN([dbi],         [$with_libdbi],       [General database statistics])
 AC_PLUGIN([df],          [$plugin_df],         [Filesystem usage statistics])
 AC_PLUGIN([disk],        [$plugin_disk],       [Disk usage statistics])
@@ -4982,6 +5038,7 @@ AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
 AC_PLUGIN([load],        [$plugin_load],       [System load])
 AC_PLUGIN([logfile],     [yes],                [File logging plugin])
 AC_PLUGIN([lpar],        [$with_perfstat],     [AIX logical partitions statistics])
+AC_PLUGIN([lvm],         [$with_liblvm2app],   [LVM statistics])
 AC_PLUGIN([madwifi],     [$have_linux_wireless_h], [Madwifi wireless statistics])
 AC_PLUGIN([match_empty_counter], [yes],        [The empty counter match])
 AC_PLUGIN([match_hashed], [yes],               [The hashed match])
@@ -5291,6 +5348,7 @@ Configuration:
     bind  . . . . . . . . $enable_bind
     conntrack . . . . . . $enable_conntrack
     contextswitch . . . . $enable_contextswitch
+    cgroups . . . . . . . $enable_cgroups
     cpu . . . . . . . . . $enable_cpu
     cpufreq . . . . . . . $enable_cpufreq
     csv . . . . . . . . . $enable_csv
@@ -5319,6 +5377,7 @@ Configuration:
     load  . . . . . . . . $enable_load
     logfile . . . . . . . $enable_logfile
     lpar... . . . . . . . $enable_lpar
+    lvm . . . . . . . . . $enable_lvm
     madwifi . . . . . . . $enable_madwifi
     match_empty_counter . $enable_match_empty_counter
     match_hashed  . . . . $enable_match_hashed
index 5030267..d67deca 100644 (file)
@@ -230,6 +230,14 @@ collectd_LDADD += "-dlopen" bind.la
 collectd_DEPENDENCIES += bind.la
 endif
 
+if BUILD_PLUGIN_CGROUPS
+pkglib_LTLIBRARIES += cgroups.la
+cgroups_la_SOURCES = cgroups.c utils_mount.c utils_mount.h
+cgroups_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" cgroups.la
+collectd_DEPENDENCIES += cgroups.la
+endif
+
 if BUILD_PLUGIN_CONNTRACK
 pkglib_LTLIBRARIES += conntrack.la
 conntrack_la_SOURCES = conntrack.c
@@ -568,6 +576,15 @@ collectd_DEPENDENCIES += lpar.la
 lpar_la_LIBADD = -lperfstat
 endif
 
+if BUILD_PLUGIN_LVM
+pkglib_LTLIBRARIES += lvm.la
+lvm_la_SOURCES = lvm.c
+lvm_la_LDFLAGS = -module -avoid-version
+lvm_la_LIBADD = $(BUILD_WITH_LIBLVM2APP_LIBS)
+collectd_LDADD += "-dlopen" lvm.la
+collectd_DEPENDENCIES += lvm.la
+endif
+
 if BUILD_PLUGIN_MADWIFI
 pkglib_LTLIBRARIES += madwifi.la
 madwifi_la_SOURCES = madwifi.c madwifi.h
index 767a877..edd4f74 100644 (file)
@@ -877,6 +877,7 @@ static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
     /* publish only */
     conf->delivery_mode = CAMQP_DM_VOLATILE;
     conf->store_rates = 0;
+    conf->graphite_flags = 0;
     /* publish & graphite only */
     conf->prefix = NULL;
     conf->postfix = NULL;
@@ -942,6 +943,12 @@ static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
         }
         else if ((strcasecmp ("Format", child->key) == 0) && publish)
             status = camqp_config_set_format (child, conf);
+        else if ((strcasecmp ("GraphiteSeparateInstances", child->key) == 0) && publish)
+            status = cf_util_get_flag (child, &conf->graphite_flags,
+                    GRAPHITE_SEPARATE_INSTANCES);
+        else if ((strcasecmp ("GraphiteAlwaysAppendDS", child->key) == 0) && publish)
+            status = cf_util_get_flag (child, &conf->graphite_flags,
+                    GRAPHITE_ALWAYS_APPEND_DS);
         else if ((strcasecmp ("GraphitePrefix", child->key) == 0) && publish)
             status = cf_util_get_string (child, &conf->prefix);
         else if ((strcasecmp ("GraphitePostfix", child->key) == 0) && publish)
diff --git a/src/cgroups.c b/src/cgroups.c
new file mode 100644 (file)
index 0000000..ffb1740
--- /dev/null
@@ -0,0 +1,251 @@
+/**
+ * collectd - src/cgroups.c
+ * Copyright (C) 2011  Michael Stapelberg
+ * Copyright (C) 2013  Florian Forster
+ *
+ * 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:
+ *   Michael Stapelberg <michael at stapelberg.de>
+ *   Florian Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_mount.h"
+#include "utils_ignorelist.h"
+
+static char const *config_keys[] =
+{
+       "CGroup",
+       "IgnoreSelected"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static ignorelist_t *il_cgroup = NULL;
+
+__attribute__ ((nonnull(1)))
+__attribute__ ((nonnull(2)))
+static void cgroups_submit_one (char const *plugin_instance,
+               char const *type_instance, value_t value)
+{
+       value_list_t vl = VALUE_LIST_INIT;
+
+       vl.values = &value;
+       vl.values_len = 1;
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "cgroups", sizeof (vl.plugin));
+       sstrncpy (vl.plugin_instance, plugin_instance,
+                       sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, "cpu", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance,
+                       sizeof (vl.type_instance));
+
+       plugin_dispatch_values (&vl);
+} /* void cgroups_submit_one */
+
+/*
+ * This callback reads the user/system CPU time for each cgroup.
+ */
+static int read_cpuacct_procs (const char *dirname, char const *cgroup_name,
+    void *user_data)
+{
+       char abs_path[PATH_MAX];
+       struct stat statbuf;
+       char buf[1024];
+       int status;
+
+       FILE *fh;
+
+       if (ignorelist_match (il_cgroup, cgroup_name))
+               return (0);
+
+       ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, cgroup_name);
+
+       status = lstat (abs_path, &statbuf);
+       if (status != 0)
+       {
+               ERROR ("cgroups plugin: stat (\"%s\") failed.",
+                               abs_path);
+               return (-1);
+       }
+
+       /* We are only interested in directories, so skip everything else. */
+       if (!S_ISDIR (statbuf.st_mode))
+               return (0);
+
+       ssnprintf (abs_path, sizeof (abs_path), "%s/%s/cpuacct.stat",
+                       dirname, cgroup_name);
+       fh = fopen (abs_path, "r");
+       if (fh == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("cgroups pluign: fopen (\"%s\") failed: %s",
+                               abs_path,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       while (fgets (buf, sizeof (buf), fh) != NULL)
+       {
+               char *fields[8];
+               int numfields = 0;
+               char *key;
+               size_t key_len;
+               value_t value;
+
+               /* Expected format:
+                *
+                *   user: 12345
+                *   system: 23456
+                */
+               strstripnewline (buf);
+               numfields = strsplit (buf, fields, STATIC_ARRAY_SIZE (fields));
+               if (numfields != 2)
+                       continue;
+
+               key = fields[0];
+               key_len = strlen (key);
+               if (key_len < 2)
+                       continue;
+
+               /* Strip colon off the first column */
+               if (key[key_len - 1] != ':')
+                       continue;
+               key[key_len - 1] = 0;
+
+               status = parse_value (fields[1], &value, DS_TYPE_DERIVE);
+               if (status != 0)
+                       continue;
+
+               cgroups_submit_one (cgroup_name, key, value);
+       }
+
+       fclose (fh);
+       return (0);
+} /* int read_cpuacct_procs */
+
+/*
+ * Gets called for every file/folder in /sys/fs/cgroup/cpu,cpuacct (or
+ * whereever cpuacct is mounted on the system). Calls walk_directory with the
+ * read_cpuacct_procs callback on every folder it finds, such as "system".
+ */
+static int read_cpuacct_root (const char *dirname, const char *filename,
+               void *user_data)
+{
+       char abs_path[PATH_MAX];
+       struct stat statbuf;
+       int status;
+
+       ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename);
+
+       status = lstat (abs_path, &statbuf);
+       if (status != 0)
+       {
+               ERROR ("cgroups plugin: stat (%s) failed.", abs_path);
+               return (-1);
+       }
+
+       if (S_ISDIR (statbuf.st_mode))
+       {
+               status = walk_directory (abs_path, read_cpuacct_procs,
+                               /* user_data = */ NULL,
+                               /* include_hidden = */ 0);
+               return (status);
+       }
+
+       return (0);
+}
+
+static int cgroups_init (void)
+{
+       if (il_cgroup == NULL)
+               il_cgroup = ignorelist_create (1);
+
+       return (0);
+}
+
+static int cgroups_config (const char *key, const char *value)
+{
+       cgroups_init ();
+
+       if (strcasecmp (key, "CGroup") == 0)
+       {
+               if (ignorelist_add (il_cgroup, value))
+                       return (1);
+               return (0);
+       }
+       else if (strcasecmp (key, "IgnoreSelected") == 0)
+       {
+               if (IS_TRUE (value))
+                       ignorelist_set_invert (il_cgroup, 0);
+               else
+                       ignorelist_set_invert (il_cgroup, 1);
+               return (0);
+       }
+
+       return (-1);
+}
+
+static int cgroups_read (void)
+{
+       cu_mount_t *mnt_list;
+       cu_mount_t *mnt_ptr;
+       _Bool cgroup_found = 0;
+
+       mnt_list = NULL;
+       if (cu_mount_getlist (&mnt_list) == NULL)
+       {
+               ERROR ("cgroups plugin: cu_mount_getlist failed.");
+               return (-1);
+       }
+
+       for (mnt_ptr = mnt_list; mnt_ptr != NULL; mnt_ptr = mnt_ptr->next)
+       {
+               /* Find the cgroup mountpoint which contains the cpuacct
+                * controller. */
+               if (strcmp(mnt_ptr->type, "cgroup") != 0 ||
+                       !cu_mount_getoptionvalue(mnt_ptr->options, "cpuacct"))
+                       continue;
+
+               walk_directory (mnt_ptr->dir, read_cpuacct_root,
+                               /* user_data = */ NULL,
+                               /* include_hidden = */ 0);
+               cgroup_found = 1;
+               /* It doesn't make sense to check other cpuacct mount-points
+                * (if any), they contain the same data. */
+               break;
+       }
+
+       cu_mount_freelist (mnt_list);
+
+       if (!cgroup_found)
+       {
+               WARNING ("cgroups plugin: Unable to find cgroup "
+                               "mount-point with the \"cpuacct\" option.");
+               return (-1);
+       }
+
+       return (0);
+} /* int cgroup_read */
+
+void module_register (void)
+{
+       plugin_register_config ("cgroups", cgroups_config,
+                       config_keys, config_keys_num);
+       plugin_register_init ("cgroups", cgroups_init);
+       plugin_register_read ("cgroups", cgroups_read);
+} /* void module_register */
index 2010d33..b817e8c 100644 (file)
@@ -72,6 +72,7 @@
 #@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind
 #@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
 #@BUILD_PLUGIN_CONTEXTSWITCH_TRUE@LoadPlugin contextswitch
+#@BUILD_PLUGIN_CGROUPS_TRUE@LoadPlugin cgroups
 @BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
 #@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
 @LOAD_PLUGIN_CSV@LoadPlugin csv
 #@BUILD_PLUGIN_LIBVIRT_TRUE@LoadPlugin libvirt
 @BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
 #@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
+#@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
 #@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
 #@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
 #@BUILD_PLUGIN_MD_TRUE@LoadPlugin md
index eb27b59..96c60ea 100644 (file)
@@ -852,6 +852,29 @@ By default no detailed zone information is collected.
 
 =back
 
+=head2 Plugin C<cgroups>
+
+This plugin collects the CPU user/system time for each I<cgroup> by reading the
+F<cpuacct.stat> files in the first cpuacct-mountpoint (typically
+F</sys/fs/cgroup/cpu.cpuacct> on machines using systemd).
+
+=over 4
+
+=item B<CGroup> I<Directory>
+
+Select I<cgroup> based on the name. Whether only matching I<cgroups> are
+collected or if they are ignored is controlled by the B<IgnoreSelected> option;
+see below.
+
+=item B<IgnoreSelected> B<true>|B<false>
+
+Invert the selection: If set to true, all cgroups I<except> the ones that
+match any one of the criteria are collected. By default only selected
+cgroups are collected if a selection is made. If no selection is configured
+at all, B<all> cgroups are selected.
+
+=back
+
 =head2 Plugin C<cpufreq>
 
 This plugin doesn't have any options. It reads
index d617832..d963efa 100644 (file)
@@ -86,6 +86,47 @@ int ssnprintf (char *dest, size_t n, const char *format, ...)
        return (ret);
 } /* int ssnprintf */
 
+char *ssnprintf_alloc (char const *format, ...) /* {{{ */
+{
+       char static_buffer[1024] = "";
+       char *alloc_buffer;
+       size_t alloc_buffer_size;
+       int status;
+       va_list ap;
+
+       /* Try printing into the static buffer. In many cases it will be
+        * sufficiently large and we can simply return a strdup() of this
+        * buffer. */
+       va_start (ap, format);
+       status = vsnprintf (static_buffer, sizeof (static_buffer), format, ap);
+       va_end (ap);
+       if (status < 0)
+               return (NULL);
+
+       /* "status" does not include the null byte. */
+       alloc_buffer_size = (size_t) (status + 1);
+       if (alloc_buffer_size <= sizeof (static_buffer))
+               return (strdup (static_buffer));
+
+       /* Allocate a buffer large enough to hold the string. */
+       alloc_buffer = malloc (alloc_buffer_size);
+       if (alloc_buffer == NULL)
+               return (NULL);
+       memset (alloc_buffer, 0, alloc_buffer_size);
+
+       /* Print again into this new buffer. */
+       va_start (ap, format);
+       status = vsnprintf (alloc_buffer, alloc_buffer_size, format, ap);
+       va_end (ap);
+       if (status < 0)
+       {
+               sfree (alloc_buffer);
+               return (NULL);
+       }
+
+       return (alloc_buffer);
+} /* }}} char *ssnprintf_alloc */
+
 char *sstrdup (const char *s)
 {
        char *r;
@@ -1213,18 +1254,25 @@ int walk_directory (const char *dir, dirwalk_callback_f callback,
        return (0);
 }
 
-int read_file_contents (const char *filename, char *buf, int bufsize)
+ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
 {
        FILE *fh;
-       int n;
+       ssize_t ret;
 
-       if ((fh = fopen (filename, "r")) == NULL)
-               return -1;
+       fh = fopen (filename, "r");
+       if (fh == NULL)
+               return (-1);
 
-       n = fread(buf, 1, bufsize, fh);
-       fclose(fh);
+       ret = (ssize_t) fread (buf, 1, bufsize, fh);
+       if ((ret == 0) && (ferror (fh) != 0))
+       {
+               ERROR ("read_file_contents: Reading file \"%s\" failed.",
+                               filename);
+               ret = -1;
+       }
 
-       return n;
+       fclose(fh);
+       return (ret);
 }
 
 counter_t counter_diff (counter_t old_value, counter_t new_value)
index ae8e311..317be8d 100644 (file)
@@ -56,7 +56,13 @@ struct rate_to_value_state_s
 typedef struct rate_to_value_state_s rate_to_value_state_t;
 
 char *sstrncpy (char *dest, const char *src, size_t n);
+
+__attribute__ ((format(printf,3,4)))
 int ssnprintf (char *dest, size_t n, const char *format, ...);
+
+__attribute__ ((format(printf,1,2)))
+char *ssnprintf_alloc (char const *format, ...);
+
 char *sstrdup(const char *s);
 void *smalloc(size_t size);
 char *sstrerror (int errnum, char *buf, size_t buflen);
@@ -303,7 +309,7 @@ typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
 int walk_directory (const char *dir, dirwalk_callback_f callback,
                void *user_data, int hidden);
 /* Returns the number of bytes read or negative on error. */
-int read_file_contents (const char *filename, char *buf, int bufsize);
+ssize_t read_file_contents (char const *filename, char *buf, size_t bufsize);
 
 counter_t counter_diff (counter_t old_value, counter_t new_value);
 
index 0b41304..5adaf06 100644 (file)
@@ -966,7 +966,7 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
   if (status == 0)
   {
     user_data_t ud;
-    char cb_name[DATA_MAX_NAME_LEN];
+    char *cb_name;
 
     if (db->instance == NULL)
       db->instance = strdup("default");
@@ -978,11 +978,10 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
     ud.data = (void *) db;
     ud.free_func = cx_free;
 
-    ssnprintf (cb_name, sizeof (cb_name), "curl_xml-%s-%s",
-               db->instance, db->url);
-
-    plugin_register_complex_read (/* group = */ NULL, cb_name, cx_read,
+    cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url);
+    plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read,
                                   /* interval = */ NULL, &ud);
+    sfree (cb_name);
   }
   else
   {
diff --git a/src/lvm.c b/src/lvm.c
new file mode 100644 (file)
index 0000000..6ef3a7b
--- /dev/null
+++ b/src/lvm.c
@@ -0,0 +1,103 @@
+/**
+ * collectd - src/lvm.c
+ * Copyright (C) 2013       Chad Malfait
+ *
+ * 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:
+ *   Chad Malfait <malfaitc at yahoo.com>
+ **/
+
+#include <lvm2app.h>
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+static void lvm_submit (char const *plugin_instance, char const *type_instance,
+        uint64_t ivalue)
+{
+    value_t v;
+    value_list_t vl = VALUE_LIST_INIT;
+
+    v.gauge = (gauge_t) ivalue;
+
+    vl.values = &v;
+    vl.values_len = 1;
+
+    sstrncpy(vl.host, hostname_g, sizeof (vl.host));
+    sstrncpy(vl.plugin, "lvm", sizeof (vl.plugin));
+    sstrncpy(vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+    sstrncpy(vl.type, "df_complex", sizeof (vl.type));
+    sstrncpy(vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+    plugin_dispatch_values (&vl);
+}
+
+static int vg_read(vg_t vg, char const *vg_name)
+{
+    struct dm_list *lvs;
+    struct lvm_lv_list *lvl;
+
+    lvm_submit (vg_name, "free", lvm_vg_get_free_size(vg));
+
+    lvs = lvm_vg_list_lvs(vg);
+    dm_list_iterate_items(lvl, lvs) {
+         lvm_submit(vg_name, lvm_lv_get_name(lvl->lv), lvm_lv_get_size(lvl->lv));
+    }
+
+    return (0);
+}
+
+static int lvm_read(void)
+{
+    lvm_t lvm;
+    struct dm_list *vg_names;
+    struct lvm_str_list *name_list;
+
+    lvm = lvm_init(NULL);
+    if (!lvm) {
+        ERROR("lvm plugin: lvm_init failed.");
+        return (-1);
+    }
+
+    vg_names = lvm_list_vg_names(lvm);
+    if (!vg_names) {
+        ERROR("lvm plugin lvm_list_vg_name failed %s", lvm_errmsg(lvm));
+        lvm_quit(lvm);
+        return (-1);
+    }
+
+    dm_list_iterate_items(name_list, vg_names) {
+        vg_t vg;
+
+        vg = lvm_vg_open(lvm, name_list->str, "r", 0);
+        if (!vg) {
+            ERROR ("lvm plugin: lvm_vg_open (%s) failed: %s",
+                    name_list->str, lvm_errmsg(lvm));
+            continue;
+        }
+
+        vg_read(vg, name_list->str);
+        lvm_vg_close(vg);
+    }
+
+    lvm_quit(lvm);
+    return (0);
+} /*lvm_read */
+
+void module_register(void)
+{
+    plugin_register_read("lvm", lvm_read);
+} /* void module_register */
index 4c6a032..b2a8b86 100644 (file)
@@ -61,7 +61,7 @@ struct read_func_s
 #define rf_ctx rf_super.cf_ctx
        callback_func_t rf_super;
        char rf_group[DATA_MAX_NAME_LEN];
-       char rf_name[DATA_MAX_NAME_LEN];
+       char *rf_name;
        int rf_type;
        cdtime_t rf_interval;
        cdtime_t rf_effective_interval;
@@ -437,6 +437,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                {
                        DEBUG ("plugin_read_thread: Destroying the `%s' "
                                        "callback.", rf->rf_name);
+                       sfree (rf->rf_name);
                        destroy_callback ((callback_func_t *) rf);
                        rf = NULL;
                        continue;
@@ -1048,7 +1049,7 @@ int plugin_register_read (const char *name,
        rf->rf_udata.free_func = NULL;
        rf->rf_ctx = plugin_get_ctx ();
        rf->rf_group[0] = '\0';
-       sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
+       rf->rf_name = strdup (name);
        rf->rf_type = RF_SIMPLE;
        rf->rf_interval = plugin_get_interval ();
 
@@ -1080,7 +1081,7 @@ int plugin_register_complex_read (const char *group, const char *name,
                sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
        else
                rf->rf_group[0] = '\0';
-       sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
+       rf->rf_name = strdup (name);
        rf->rf_type = RF_COMPLEX;
        if (interval != NULL)
                rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
index 603f85b..27c92bc 100644 (file)
@@ -80,12 +80,12 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
        if (device_list && ignorelist_match (device_list, name))
                return -1;
 
-       len = snprintf (filename, sizeof (filename),
+       len = ssnprintf (filename, sizeof (filename),
                        "%s/%s/temp", dirname_sysfs, name);
        if ((len < 0) || ((size_t) len >= sizeof (filename)))
                return -1;
 
-       len = read_file_contents (filename, data, sizeof(data));
+       len = (ssize_t) read_file_contents (filename, data, sizeof(data));
        if (len > 1 && data[--len] == '\n') {
                char *endptr = NULL;
                double temp;
@@ -100,12 +100,12 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
                }
        }
 
-       len = snprintf (filename, sizeof (filename),
+       len = ssnprintf (filename, sizeof (filename),
                        "%s/%s/cur_state", dirname_sysfs, name);
        if ((len < 0) || ((size_t) len >= sizeof (filename)))
                return -1;
 
-       len = read_file_contents (filename, data, sizeof(data));
+       len = (ssize_t) read_file_contents (filename, data, sizeof(data));
        if (len > 1 && data[--len] == '\n') {
                char *endptr = NULL;
                double state;
@@ -139,12 +139,12 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
         * temperature:             55 C
         */
        
-       len = snprintf (filename, sizeof (filename),
+       len = ssnprintf (filename, sizeof (filename),
                        "%s/%s/temperature", dirname_procfs, name);
        if ((len < 0) || ((size_t) len >= sizeof (filename)))
                return -1;
 
-       len = read_file_contents (filename, data, sizeof(data));
+       len = (ssize_t) read_file_contents (filename, data, sizeof(data));
        if ((len > 0) && ((size_t) len > sizeof(str_temp))
                        && (data[--len] == '\n')
                        && (! strncmp(data, str_temp, sizeof(str_temp)-1))) {
index 3358f5d..6f1eaf6 100644 (file)
@@ -186,6 +186,7 @@ voltage                     value:GAUGE:U:U
 vs_memory              value:GAUGE:0:9223372036854775807
 vs_processes           value:GAUGE:0:65535
 vs_threads             value:GAUGE:0:65535
+
 #
 # Legacy types
 # (required for the v5 upgrade target)