disk: Add udev-based device renaming on Linux
authorPatrick Mooney <patrick.f.mooney@gmail.com>
Mon, 10 Feb 2014 16:00:15 +0000 (10:00 -0600)
committerPatrick Mooney <patrick.f.mooney@gmail.com>
Mon, 10 Feb 2014 16:00:15 +0000 (10:00 -0600)
On systems with large collections of allocated disk resources, the
kernel provided names can be difficult to use to logically group or
compare collected values.  To grant users the ability to assign custom
instance names for disk devices, collectd can query for a specified udev
attribute.  If the attribute is present, its value is subsituted for the
kernel name when submitting the data points.

configure.ac
src/Makefile.am
src/collectd.conf.pod
src/disk.c

index 3b9b8eb..74dbb22 100644 (file)
@@ -4030,6 +4030,67 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBTOKYOTYRANT, test "x$with_libtokyotyrant" = "xyes")
 # }}}
 
+# --with-libudev {{{
+with_libudev_cflags=""
+with_libudev_ldflags=""
+AC_ARG_WITH(libudev, [AS_HELP_STRING([--with-libudev@<:@=PREFIX@:>@], [Path to libudev.])],
+[
+       if test "x$withval" = "xno"
+       then
+               with_libudev="no"
+       else
+               with_libudev="yes"
+               if test "x$withval" != "xyes"
+               then
+                       with_libudev_cflags="-I$withval/include"
+                       with_libudev_ldflags="-L$withval/lib"
+                       with_libudev="yes"
+               fi
+       fi
+],
+[
+       if test "x$ac_system" = "xLinux"
+       then
+               with_libudev="yes"
+       else
+               with_libudev="no (Linux only library)"
+       fi
+])
+if test "x$with_libudev" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libudev_cflags"
+
+       AC_CHECK_HEADERS(libudev.h, [], [with_libudev="no (libudev.h not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libudev" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       SAVE_LDFLAGS="$LDFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libudev_cflags"
+       LDFLAGS="$LDFLAGS $with_libudev_ldflags"
+
+       AC_CHECK_LIB(udev, udev_new,
+       [
+               AC_DEFINE(HAVE_LIBUDEV, 1, [Define to 1 if you have the udev library (-ludev).])
+       ],
+       [with_libudev="no (libudev not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+       LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libudev" = "xyes"
+then
+       BUILD_WITH_LIBUDEV_CFLAGS="$with_libudev_cflags"
+       BUILD_WITH_LIBUDEV_LDFLAGS="$with_libudev_ldflags"
+       AC_SUBST(BUILD_WITH_LIBUDEV_CFLAGS)
+       AC_SUBST(BUILD_WITH_LIBUDEV_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBUDEV, test "x$with_libudev" = "xyes")
+# }}}
+
 # --with-libupsclient {{{
 with_libupsclient_config=""
 with_libupsclient_cflags=""
@@ -5413,6 +5474,7 @@ Configuration:
     libsigrok   . . . . . $with_libsigrok
     libstatgrab . . . . . $with_libstatgrab
     libtokyotyrant  . . . $with_libtokyotyrant
+    libudev . . . . . . . $with_libudev
     libupsclient  . . . . $with_libupsclient
     libvarnish  . . . . . $with_libvarnish
     libvirt . . . . . . . $with_libvirt
index a9d8582..8720adf 100644 (file)
@@ -385,6 +385,9 @@ if BUILD_WITH_LIBSTATGRAB
 disk_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)  
 disk_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
 endif
+if BUILD_WITH_LIBUDEV
+disk_la_LIBADD += -ludev
+endif
 if BUILD_WITH_PERFSTAT
 disk_la_LIBADD += -lperfstat
 endif
index f597c49..201b5c9 100644 (file)
@@ -1649,6 +1649,12 @@ collected. If at least one B<Disk> option is given and no B<IgnoreSelected> or
 set to B<false>, B<only> matching disks will be collected. If B<IgnoreSelected>
 is set to B<true>, all disks are collected B<except> the ones matched.
 
+=item B<UdevNameAttr> I<Attribute>
+
+Attempt to override disk instance name with the value of a specified udev
+attribute When built with B<libudev>.  If the attribute is not defined for the
+given device, the default name is used.
+
 =back
 
 =head2 Plugin C<dns>
index 36d0a0c..cdf2816 100644 (file)
@@ -128,11 +128,19 @@ static int pnumdisk;
 # error "No applicable input method."
 #endif
 
+#if HAVE_LIBUDEV
+#include <libudev.h>
+
+static char *conf_udev_name_attr = NULL;
+static struct udev *handle_udev;
+#endif
+
 static const char *config_keys[] =
 {
        "Disk",
        "UseBSDName",
-       "IgnoreSelected"
+       "IgnoreSelected",
+       "UdevNameAttr"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
@@ -165,6 +173,21 @@ static int disk_config (const char *key, const char *value)
         "on Mach / Mac OS X and will be ignored.");
 #endif
   }
+  else if (strcasecmp ("UdevNameAttr", key) == 0)
+  {
+#if HAVE_LIBUDEV
+    if (conf_udev_name_attr != NULL)
+    {
+      free (conf_udev_name_attr);
+      conf_udev_name_attr = NULL;
+    }
+    if ((conf_udev_name_attr = strdup (value)) == NULL)
+      return (1);
+#else
+    WARNING ("disk plugin: The \"UdevNameAttr\" option is only supported "
+        "if collectd is built with libudev support");
+#endif
+  }
   else
   {
     return (-1);
@@ -259,6 +282,34 @@ static counter_t disk_calc_time_incr (counter_t delta_time, counter_t delta_ops)
 }
 #endif
 
+#if HAVE_LIBUDEV
+/**
+ * Attempt to provide an rename disk instance from an assigned udev attribute.
+ *
+ * On success, it returns a strduped char* to the desired attribute value.
+ * Otherwise it returns NULL.
+ */
+
+static char *disk_udev_attr_name (struct udev *udev, char *disk_name, const char *attr)
+{
+       struct udev_device *dev;
+       const char *prop;
+       char *output = NULL;
+
+       dev = udev_device_new_from_subsystem_sysname (udev, "block", disk_name);
+       if (dev != NULL)
+       {
+               prop = udev_device_get_property_value (dev, attr);
+               if (prop) {
+                       output = strdup (prop);
+                       DEBUG ("disk plugin: renaming %s => %s", disk_name, output);
+               }
+               udev_device_unref (dev);
+       }
+       return output;
+}
+#endif
+
 #if HAVE_IOKIT_IOKITLIB_H
 static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
 {
@@ -505,9 +556,15 @@ static int disk_read (void)
                fieldshift = 1;
        }
 
+#if HAVE_LIBUDEV
+       handle_udev = udev_new();
+#endif
+
        while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
                char *disk_name;
+               char *output_name;
+               char *alt_name;
 
                numfields = strsplit (buffer, fields, 32);
 
@@ -659,25 +716,43 @@ static int disk_read (void)
                        continue;
                }
 
+               output_name = disk_name;
+
+#if HAVE_LIBUDEV
+               alt_name = disk_udev_attr_name (handle_udev, disk_name,
+                               conf_udev_name_attr);
+#else
+               alt_name = NULL;
+#endif
+               if (alt_name != NULL)
+                       output_name = alt_name;
+
                if ((ds->read_bytes != 0) || (ds->write_bytes != 0))
-                       disk_submit (disk_name, "disk_octets",
+                       disk_submit (output_name, "disk_octets",
                                        ds->read_bytes, ds->write_bytes);
 
                if ((ds->read_ops != 0) || (ds->write_ops != 0))
-                       disk_submit (disk_name, "disk_ops",
+                       disk_submit (output_name, "disk_ops",
                                        read_ops, write_ops);
 
                if ((ds->avg_read_time != 0) || (ds->avg_write_time != 0))
-                       disk_submit (disk_name, "disk_time",
+                       disk_submit (output_name, "disk_time",
                                        ds->avg_read_time, ds->avg_write_time);
 
                if (is_disk)
                {
-                       disk_submit (disk_name, "disk_merged",
+                       disk_submit (output_name, "disk_merged",
                                        read_merged, write_merged);
                } /* if (is_disk) */
+
+               /* release udev-based alternate name, if allocated */
+               free(alt_name);
        } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
 
+#if HAVE_LIBUDEV
+       udev_unref(handle_udev);
+#endif
+
        fclose (fh);
 /* #endif defined(KERNEL_LINUX) */