- LPAR plugin.
- Various fixes for AIX, HP-UX and Solaris.
+Benjamin Gilbert <bgilbert at cs.cmu.edu>
+ - Improvements to the LVM plugin.
+
Bert Vermeulen <bert at biot.com>
- sigrok plugin
- netapp plugin.
- python plugin.
+Tim Laszlo <tim.laszlo at gmail.com>
+ - drbd plugin
+
Thomas Meson <zllak at hycik.org>
- Graphite support for the AMQP plugin.
DNS traffic: Query types, response codes, opcodes and traffic/octets
transfered.
+ - drbd
+ Collect individual drbd resource statistics.
+
- email
Email statistics: Count, traffic, spam scores and checks.
See collectd-email(5).
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)"])
+ AC_CHECK_LIB(lvm2app, lvm_lv_get_property, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_lv_get_property' not found)"])
CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
plugin_curl_xml="no"
plugin_df="no"
plugin_disk="no"
+plugin_drbd="no"
plugin_entropy="no"
plugin_ethstat="no"
plugin_fscache="no"
plugin_cpu="yes"
plugin_cpufreq="yes"
plugin_disk="yes"
+ plugin_drbd="yes"
plugin_entropy="yes"
plugin_fscache="yes"
plugin_interface="yes"
AC_PLUGIN([dbi], [$with_libdbi], [General database statistics])
AC_PLUGIN([df], [$plugin_df], [Filesystem usage statistics])
AC_PLUGIN([disk], [$plugin_disk], [Disk usage statistics])
+AC_PLUGIN([drbd], [$plugin_drbd], [DRBD statistics])
AC_PLUGIN([dns], [$with_libpcap], [DNS traffic analysis])
AC_PLUGIN([email], [yes], [EMail statistics])
AC_PLUGIN([entropy], [$plugin_entropy], [Entropy statistics])
libjvm . . . . . . . $with_java
libkstat . . . . . . $with_kstat
libkvm . . . . . . . $with_libkvm
+ liblvm2app . . . . . $with_liblvm2app
libmemcached . . . . $with_libmemcached
libmnl . . . . . . . $with_libmnl
libmodbus . . . . . . $with_libmodbus
df . . . . . . . . . $enable_df
disk . . . . . . . . $enable_disk
dns . . . . . . . . . $enable_dns
+ drbd . . . . . . . . $enable_drbd
email . . . . . . . . $enable_email
entropy . . . . . . . $enable_entropy
ethstat . . . . . . . $enable_ethstat
collectd_DEPENDENCIES += dns.la
endif
+if BUILD_PLUGIN_DRBD
+pkglib_LTLIBRARIES += drbd.la
+drbd_la_SOURCES = drbd.c
+drbd_la_LDFLAGS = -module -avoid-version
+drbd_la_LIBADD = -lpthread
+collectd_LDADD += "-dlopen" drbd.la
+collectd_DEPENDENCIES += drbd.la
+endif
+
if BUILD_PLUGIN_EMAIL
pkglib_LTLIBRARIES += email.la
email_la_SOURCES = email.c
#@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
#@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
#@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
+#@BUILD_PLUGIN_DRBD_TRUE@LoadPlugin drbd
#@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
#@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
#@BUILD_PLUGIN_ETHSTAT_TRUE@LoadPlugin ethstat
--- /dev/null
+/**
+ * collectd - src/drbd.c
+ * Copyright (C) 2014 Tim Laszlo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Tim Laszlo <tim.laszlo at gmail.com>
+ **/
+
+/*
+ See: http://www.drbd.org/users-guide/ch-admin.html#s-performance-indicators
+
+ version: 8.3.11 (api:88/proto:86-96)
+ srcversion: 71955441799F513ACA6DA60
+ 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate B r-----
+ ns:64363752 nr:0 dw:357799284 dr:846902273 al:34987022 bm:18062 lo:0 \
+ pe:0 ua:0 ap:0 ep:1 wo:f oos:0
+ */
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+static const char *drbd_stats = "/proc/drbd";
+static const char *drbd_names[] =
+{
+ "network_send", /* ns (network send) */
+ "network_recv", /* nr (network receive) */
+ "disk_write", /* dw (disk write) */
+ "disk_read", /* dr (disk read) */
+ "activity_log", /* al (activity log) */
+ "bitmap", /* bm (bit map) */
+ "local_count", /* lo (local count) */
+ "pending", /* pe (pending) */
+ "unacknowledged", /* ua (unacknowledged) */
+ "app pending", /* ap (application pending) */
+ "epochs", /* ep (epochs) */
+ NULL, /* wo (write order) */
+ "oos" /* oos (out of sync) */
+};
+static size_t drbd_names_num = STATIC_ARRAY_SIZE (drbd_names);
+
+static int drbd_init (void)
+{
+ return (0);
+}
+
+
+static int drbd_submit_fields (long int resource,
+ char **fields, size_t fields_num)
+{
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ value_t values[fields_num];
+ value_list_t vl = VALUE_LIST_INIT;
+ size_t i;
+
+ if (resource < 0)
+ {
+ WARNING ("drbd plugin: Unable to parse resource");
+ return (EINVAL);
+ }
+
+ if (fields_num != drbd_names_num)
+ {
+ WARNING ("drbd plugin: Wrong number of fields for "
+ "r%ld statistics. Expected %zu, got %zu.",
+ resource, drbd_names_num, fields_num);
+ return (EINVAL);
+ }
+
+ ssnprintf (plugin_instance, sizeof (plugin_instance), "r%ld",
+ resource);
+
+ for (i = 0; i < drbd_names_num; i++)
+ {
+ char *data;
+ /* skip non numeric wo */
+ if (strncmp(fields[i], "wo", 2) == 0)
+ continue;
+ data = strchr(fields[i], ':');
+ if (data == NULL)
+ return (EINVAL);
+ (void) parse_value (++data, &values[i], DS_TYPE_DERIVE);
+ }
+
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "drbd", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "drbd_resource", sizeof (vl.type));
+
+ for (i = 0; i < fields_num; i++)
+ {
+ if (drbd_names[i] == NULL)
+ continue;
+ vl.values = values + i;
+ sstrncpy (vl.type_instance, drbd_names[i],
+ sizeof (vl.type_instance));
+ plugin_dispatch_values (&vl);
+ }
+
+ return (0);
+} /* drbd_submit_fields */
+
+static int drbd_read (void)
+{
+ FILE *fh;
+ char buffer[256];
+
+ long int resource = -1;
+ char *fields[16];
+ int fields_num = 0;
+
+ fh = fopen (drbd_stats, "r");
+ if (fh == NULL)
+ {
+ WARNING ("Unable to open%s", drbd_stats);
+ return (EINVAL);
+ }
+
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ fields_num = strsplit (buffer,
+ fields, STATIC_ARRAY_SIZE (fields));
+
+ /* ignore headers (first two iterations) */
+ if (fields_num < 4)
+ continue;
+
+ if (isdigit(fields[0][0]))
+ {
+ /* parse the resource line, next loop iteration
+ will submit values for this resource */
+ resource = strtol(fields[0], NULL, 10);
+ }
+ else
+ {
+ /* handle stats data for the resource defined in the
+ previous iteration */
+ drbd_submit_fields(resource, fields, fields_num);
+ }
+ } /* while (fgets) */
+
+ fclose (fh);
+ return (0);
+} /* void drbd_read */
+
+void module_register (void)
+{
+ plugin_register_init ("drbd", drbd_init);
+ plugin_register_read ("drbd", drbd_read);
+} /* void module_register */
/**
* collectd - src/lvm.c
* Copyright (C) 2013 Chad Malfait
+ * Copyright (C) 2014 Carnegie Mellon University
*
* 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
*
* Authors:
* Chad Malfait <malfaitc at yahoo.com>
+ * Benjamin Gilbert <bgilbert at cs.cmu.edu>
**/
#include <lvm2app.h>
#include "common.h"
#include "plugin.h"
+#define NO_VALUE UINT64_MAX
+#define PERCENT_SCALE_FACTOR 1e-8
+
+static uint64_t get_lv_property_int(lv_t lv, char const *property)
+{
+ lvm_property_value_t v;
+
+ v = lvm_lv_get_property(lv, property);
+ if (!v.is_valid || !v.is_integer)
+ return NO_VALUE;
+ /* May be NO_VALUE if @property does not apply to this LV */
+ return v.value.integer;
+}
+
+static char const *get_lv_property_string(lv_t lv, char const *property)
+{
+ lvm_property_value_t v;
+
+ v = lvm_lv_get_property(lv, property);
+ if (!v.is_valid || !v.is_string)
+ return NULL;
+ return v.value.string;
+}
+
static void lvm_submit (char const *plugin_instance, char const *type_instance,
uint64_t ivalue)
{
plugin_dispatch_values (&vl);
}
-static int vg_read(vg_t vg, char const *vg_name)
+static void report_lv_utilization(lv_t lv, char const *vg_name,
+ char const *lv_name, uint64_t lv_size,
+ char const *used_percent_property)
+{
+ uint64_t used_percent_unscaled;
+ uint64_t used_bytes;
+ char plugin_instance[DATA_MAX_NAME_LEN];
+
+ used_percent_unscaled = get_lv_property_int(lv, used_percent_property);
+ if (used_percent_unscaled == NO_VALUE)
+ return;
+ used_bytes = lv_size * (used_percent_unscaled * PERCENT_SCALE_FACTOR);
+
+ ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-%s",
+ vg_name, lv_name);
+ lvm_submit(plugin_instance, "used", used_bytes);
+ lvm_submit(plugin_instance, "free", lv_size - used_bytes);
+}
+
+static void report_thin_pool_utilization(lv_t lv, char const *vg_name,
+ uint64_t lv_size)
+{
+ char const *data_lv;
+ char const *metadata_lv;
+ uint64_t metadata_size;
+
+ data_lv = get_lv_property_string(lv, "data_lv");
+ metadata_lv = get_lv_property_string(lv, "metadata_lv");
+ metadata_size = get_lv_property_int(lv, "lv_metadata_size");
+ if (data_lv == NULL || metadata_lv == NULL || metadata_size == NO_VALUE)
+ return;
+
+ report_lv_utilization(lv, vg_name, data_lv, lv_size, "data_percent");
+ report_lv_utilization(lv, vg_name, metadata_lv, metadata_size,
+ "metadata_percent");
+}
+
+static void vg_read(vg_t vg, char const *vg_name)
{
struct dm_list *lvs;
struct lvm_lv_list *lvl;
+ char const *name;
+ char const *attrs;
+ uint64_t size;
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));
+ if (!lvs) {
+ /* no VGs are defined, which is not an error per se */
+ return;
}
- return (0);
+ dm_list_iterate_items(lvl, lvs) {
+ name = lvm_lv_get_name(lvl->lv);
+ attrs = get_lv_property_string(lvl->lv, "lv_attr");
+ size = lvm_lv_get_size(lvl->lv);
+ if (name == NULL || attrs == NULL || size == NO_VALUE)
+ continue;
+
+ /* Condition on volume type. We want the reported sizes in the
+ volume group to sum to the size of the volume group, so we ignore
+ virtual volumes. */
+ switch (attrs[0]) {
+ case 's':
+ case 'S':
+ /* Snapshot. Also report used/free space. */
+ report_lv_utilization(lvl->lv, vg_name, name, size,
+ "data_percent");
+ break;
+ case 't':
+ /* Thin pool virtual volume. We report the underlying data
+ and metadata volumes, not this one. Report used/free
+ space, then ignore. */
+ report_thin_pool_utilization(lvl->lv, vg_name, size);
+ continue;
+ case 'v':
+ /* Virtual volume. Ignore. */
+ continue;
+ case 'V':
+ /* Thin volume or thin snapshot. Ignore. */
+ continue;
+ }
+ lvm_submit(vg_name, name, size);
+ }
}
static int lvm_read(void)
dns_transfer value:DERIVE:0:U
dns_update value:DERIVE:0:U
dns_zops value:DERIVE:0:U
+drbd_resource value:DERIVE:0:U
duration seconds:GAUGE:0:U
email_check value:GAUGE:0:U
email_count value:GAUGE:0:U