write_prometheus: add support for libmicrohttpd 0.9.45+
[collectd.git] / src / virt.c
index c1c77bc..62b53dc 100644 (file)
@@ -31,6 +31,7 @@
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/xpath.h>
+#include <libgen.h> /* for basename(3) */
 
 /* Plugin name */
 #define PLUGIN_NAME "virt"
@@ -42,6 +43,8 @@ static const char *config_keys[] = {
 
     "Domain",
     "BlockDevice",
+    "BlockDeviceFormat",
+    "BlockDeviceFormatBasename",
     "InterfaceDevice",
     "IgnoreSelected",
 
@@ -130,6 +133,12 @@ enum plginst_field {
 static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] =
     { plginst_none };
 
+/* BlockDeviceFormat */
+enum bd_field {
+       target,
+       source
+};
+
 /* InterfaceFormat. */
 enum if_field {
     if_address,
@@ -137,6 +146,9 @@ enum if_field {
     if_number
 };
 
+/* BlockDeviceFormatBasename */
+_Bool blockdevice_format_basename = 0;
+static enum bd_field blockdevice_format = target;
 static enum if_field interface_format = if_name;
 
 /* Time that we last refreshed. */
@@ -223,103 +235,71 @@ init_value_list (value_list_t *vl, virDomainPtr dom)
 
 } /* void init_value_list */
 
-static void
-memory_submit (gauge_t memory, virDomainPtr dom)
+static void submit (virDomainPtr dom,
+                    char const *type, char const *type_instance,
+                    value_t *values, size_t values_len)
 {
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
-
     init_value_list (&vl, dom);
 
-    values[0].gauge = memory;
-
     vl.values = values;
-    vl.values_len = 1;
+    vl.values_len = values_len;
 
-    sstrncpy (vl.type, "memory", sizeof (vl.type));
-    sstrncpy (vl.type_instance, "total", sizeof (vl.type_instance));
+    sstrncpy (vl.type, type, sizeof (vl.type));
+    if (type_instance != NULL)
+        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
     plugin_dispatch_values (&vl);
 }
 
 static void
-memory_stats_submit (gauge_t memory, virDomainPtr dom, int tag_index)
+memory_submit (gauge_t value, virDomainPtr dom)
+{
+    submit (dom, "memory", "total", &(value_t) { .gauge = value }, 1);
+}
+
+static void
+memory_stats_submit (gauge_t value, virDomainPtr dom, int tag_index)
 {
     static const char *tags[] = { "swap_in", "swap_out", "major_fault", "minor_fault",
                                     "unused", "available", "actual_balloon", "rss"};
 
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, dom);
-
-    values[0].gauge = memory;
-
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, "memory", sizeof (vl.type));
-    sstrncpy (vl.type_instance, tags[tag_index], sizeof (vl.type_instance));
+    if ((tag_index < 0) || (tag_index >= STATIC_ARRAY_SIZE (tags))) {
+        ERROR ("virt plugin: Array index out of bounds: tag_index = %d", tag_index);
+        return;
+    }
 
-    plugin_dispatch_values (&vl);
+    submit (dom, "memory", tags[tag_index], &(value_t) { .gauge = value }, 1);
 }
 
 static void
-cpu_submit (unsigned long long cpu_time,
+cpu_submit (unsigned long long value,
             virDomainPtr dom, const char *type)
 {
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, dom);
-
-    values[0].derive = cpu_time;
-
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-
-    plugin_dispatch_values (&vl);
+    submit (dom, type, NULL, &(value_t) { .derive = (derive_t) value }, 1);
 }
 
 static void
-vcpu_submit (derive_t cpu_time,
+vcpu_submit (derive_t value,
              virDomainPtr dom, int vcpu_nr, const char *type)
 {
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
+    char type_instance[DATA_MAX_NAME_LEN];
 
-    init_value_list (&vl, dom);
-
-    values[0].derive = cpu_time;
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
+    ssnprintf (type_instance, sizeof (type_instance), "%d", vcpu_nr);
 
-    plugin_dispatch_values (&vl);
+    submit (dom, type, type_instance, &(value_t) { .derive = value }, 1);
 }
 
 static void
 submit_derive2 (const char *type, derive_t v0, derive_t v1,
              virDomainPtr dom, const char *devname)
 {
-    value_t values[2];
-    value_list_t vl = VALUE_LIST_INIT;
+    value_t values[] = {
+        { .derive = v0 },
+        { .derive = v1 },
+    };
 
-    init_value_list (&vl, dom);
-
-    values[0].derive = v0;
-    values[1].derive = v1;
-    vl.values = values;
-    vl.values_len = 2;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
-
-    plugin_dispatch_values (&vl);
+    submit (dom, type, devname, values, STATIC_ARRAY_SIZE (values));
 } /* void submit_derive2 */
 
 static int
@@ -370,6 +350,22 @@ lv_config (const char *key, const char *value)
         if (ignorelist_add (il_block_devices, value)) return 1;
         return 0;
     }
+
+    if (strcasecmp (key, "BlockDeviceFormat") == 0) {
+        if (strcasecmp (value, "target") == 0)
+            blockdevice_format = target;
+        else if (strcasecmp (value, "source") == 0)
+            blockdevice_format = source;
+        else {
+            ERROR (PLUGIN_NAME " plugin: unknown BlockDeviceFormat: %s", value);
+            return -1;
+        }
+        return 0;
+    }
+    if (strcasecmp (key, "BlockDeviceFormatBasename") == 0) {
+        blockdevice_format_basename = IS_TRUE (value);
+        return 0;
+    }
     if (strcasecmp (key, "InterfaceDevice") == 0) {
         if (ignorelist_add (il_interface_devices, value)) return 1;
         return 0;
@@ -610,15 +606,23 @@ lv_read (void)
                     &stats, sizeof stats) != 0)
             continue;
 
+        char *type_instance = NULL;
+        if (blockdevice_format_basename && blockdevice_format == source)
+            type_instance = strdup(basename(block_devices[i].path));
+        else
+            type_instance = strdup(block_devices[i].path);
+
         if ((stats.rd_req != -1) && (stats.wr_req != -1))
             submit_derive2 ("disk_ops",
                     (derive_t) stats.rd_req, (derive_t) stats.wr_req,
-                    block_devices[i].dom, block_devices[i].path);
+                    block_devices[i].dom, type_instance);
 
         if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
             submit_derive2 ("disk_octets",
                     (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
-                    block_devices[i].dom, block_devices[i].path);
+                    block_devices[i].dom, type_instance);
+
+        sfree (type_instance);
     } /* for (nr_block_devices) */
 
     /* Get interface stats for each domain. */
@@ -626,7 +630,6 @@ lv_read (void)
         struct _virDomainInterfaceStats stats;
         char *display_name = NULL;
 
-
         switch (interface_format) {
             case if_address:
                 display_name = interface_devices[i].address;
@@ -747,9 +750,11 @@ refresh_lists (void)
             xpath_ctx = xmlXPathNewContext (xml_doc);
 
             /* Block devices. */
-            xpath_obj = xmlXPathEval
-                ((xmlChar *) "/domain/devices/disk/target[@dev]",
-                 xpath_ctx);
+            char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
+            if (blockdevice_format == source)
+                bd_xmlpath = "/domain/devices/disk/source[@dev]";
+            xpath_obj = xmlXPathEval ((xmlChar *) bd_xmlpath, xpath_ctx);
+
             if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
                 xpath_obj->nodesetval == NULL)
                 goto cont;