From d289c0a9d042a06acc60d4d8d915787268f25bb2 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Wed, 20 Aug 2014 20:19:47 -0700 Subject: [PATCH] timeseries::rrdtool: Added a plugin to fetch time-series from RRD files. Obviously, the plugin requires librrd. The configure script checks for librrd using pkg-config. --- configure.ac | 22 ++++++ src/Makefile.am | 11 +++ src/plugins/timeseries/rrdtool.c | 123 +++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 src/plugins/timeseries/rrdtool.c diff --git a/configure.ac b/configure.ac index b94b2a0..ef6868e 100644 --- a/configure.ac +++ b/configure.ac @@ -409,6 +409,19 @@ AC_SUBST([READLINE_LIBS]) AC_SUBST([READLINE_CFLAGS]) AM_CONDITIONAL([BUILD_CLIENT], test "x$readline_support" != "no") +AC_ARG_WITH([librrd], + [AS_HELP_STRING([--with-librrd], [librrd support (default: auto)])], + [with_librrd="$withval"], + [with_librrd="yes"]) +if test "x$with_librrd" = "xyes" || test "x$with_librrd" = "xauto"; then + PKG_CHECK_MODULES([RRD], [librrd], + [have_librrd="yes"], [have_librrd="no"]) +else if test "x$with_librrd" = "xno"; then + have_librrd="$with_librrd (disabled on command-line)" +else + AC_MSG_ERROR([Invalid value for option --with-librrd=$with_librrd (expected "yes", "no", or "auto")]) +fi; fi + dnl Feature checks. build_documentation="yes" @@ -454,6 +467,11 @@ AC_SDB_PLUGIN([mk-livestatus], [yes], AC_SDB_PLUGIN([puppet-storeconfigs], [$puppet_storeconfigs_default], [backend accessing the Puppet stored configuration database]) +m4_divert_once([HELP_ENABLE], [ +Time-series fetchers:]) +AC_SDB_PLUGIN([rrdtool], [$have_librrd], + [fetch time-series data from RRD files]) + m4_divert_once([HELP_ENABLE], [ Plugins:]) @@ -498,12 +516,16 @@ AC_MSG_RESULT([ Libraries:]) AC_MSG_RESULT([ libdbi: . . . . . . . . . . $with_libdbi]) AC_MSG_RESULT([ libedit: . . . . . . . . . $have_libedit]) AC_MSG_RESULT([ libreadline: . . . . . . . $have_libreadline]) +AC_MSG_RESULT([ librrd: . . . . . . . . . . $have_librrd]) AC_MSG_RESULT() AC_MSG_RESULT([ Backends:]) AC_MSG_RESULT([ collectd: . . . . . . . . . $enable_collectd]) AC_MSG_RESULT([ mk-livestatus: . . . . . . $enable_mk_livestatus]) AC_MSG_RESULT([ puppet-storeconfigs: . . . $enable_puppet_storeconfigs]) AC_MSG_RESULT() +AC_MSG_RESULT([ Time-series fetchers:]) +AC_MSG_RESULT([ rrdtool: . . . . . . . . . $enable_rrdtool]) +AC_MSG_RESULT() AC_MSG_RESULT([ Plugins:]) AC_MSG_RESULT([ cname::dns: . . . . . . . . $enable_cname_dns]) AC_MSG_RESULT([ syslog: . . . . . . . . . . $enable_syslog]) diff --git a/src/Makefile.am b/src/Makefile.am index 97c3188..ef6367e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -143,12 +143,14 @@ pkgbackendlibdir = $(pkglibdir)/backend pkgbackendcollectdlibdir = $(pkgbackendlibdir)/collectd pkgbackendpuppetlibdir = $(pkgbackendlibdir)/puppet pkgcnamelibdir = $(pkglibdir)/cname +pkgtimeserieslibdir = $(pkglibdir)/timeseries pkglib_LTLIBRARIES = pkgbackendlib_LTLIBRARIES = pkgbackendcollectdlib_LTLIBRARIES = pkgbackendpuppetlib_LTLIBRARIES = pkgcnamelib_LTLIBRARIES = +pkgtimeserieslib_LTLIBRARIES = if BUILD_PLUGIN_CNAMEDNS pkgcnamelib_LTLIBRARIES += plugins/cname/dns.la @@ -182,6 +184,15 @@ sysdbd_LDADD += -dlopen plugins/backend/puppet/store-configs.la sysdbd_DEPENDENCIES += plugins/backend/puppet/store-configs.la endif +if BUILD_PLUGIN_RRDTOOL +pkgtimeserieslib_LTLIBRARIES += plugins/timeseries/rrdtool.la +plugins_timeseries_rrdtool_la_SOURCES = plugins/timeseries/rrdtool.c +plugins_timeseries_rrdtool_la_CFLAGS = $(AM_CFLAGS) @RRD_CFLAGS@ +plugins_timeseries_rrdtool_la_LDFLAGS = $(AM_LDFLAGS) @RRD_LIBS@ -module -avoid-version +sysdbd_LDADD += -dlopen plugins/timeseries/rrdtool.la +sysdbd_DEPENDENCIES += plugins/timeseries/rrdtool.la +endif + if BUILD_PLUGIN_SYSLOG pkglib_LTLIBRARIES += plugins/syslog.la plugins_syslog_la_SOURCE = plugins/syslog.c diff --git a/src/plugins/timeseries/rrdtool.c b/src/plugins/timeseries/rrdtool.c new file mode 100644 index 0000000..572c033 --- /dev/null +++ b/src/plugins/timeseries/rrdtool.c @@ -0,0 +1,123 @@ +/* + * SysDB - src/plugins/timeseries/rrdtool.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sysdb.h" +#include "core/plugin.h" +#include "utils/error.h" + +#include +#include + +SDB_PLUGIN_MAGIC; + +/* + * plugin API + */ + +static sdb_timeseries_t * +sdb_rrd_fetch(const char *id, sdb_timeseries_opts_t *opts, + sdb_object_t __attribute__((unused)) *user_data) +{ + sdb_timeseries_t *ts; + + time_t start = (time_t)SDB_TIME_TO_SECS(opts->start); + time_t end = (time_t)SDB_TIME_TO_SECS(opts->end); + time_t t; + + unsigned long step = 0; + unsigned long ds_cnt = 0; + unsigned long val_cnt = 0; + char **ds_namv = NULL; + rrd_value_t *data = NULL, *data_ptr; + +#define FREE_RRD_DATA() \ + do { \ + size_t i; \ + for (i = 0; i < ds_cnt; ++i) \ + rrd_freemem(ds_namv[i]); \ + rrd_freemem(ds_namv); \ + rrd_freemem(data); \ + } while (0) + + if (rrd_fetch_r(id, "AVERAGE", &start, &end, &step, + &ds_cnt, &ds_namv, &data)) { + char errbuf[1024]; + sdb_strerror(errno, errbuf, sizeof(errbuf)); + sdb_log(SDB_LOG_ERR, "rrdtool plugin: Failed to fetch data " + "from %s: %s", id, errbuf); + return NULL; + } + + val_cnt = (unsigned long)(end - start) / step; + + ts = sdb_timeseries_create(ds_cnt, (const char * const *)ds_namv, val_cnt); + if (! ts) { + char errbuf[1024]; + sdb_strerror(errno, errbuf, sizeof(errbuf)); + sdb_log(SDB_LOG_ERR, "rrdtool plugin: Failed to allocate " + "time-series object: %s", errbuf); + FREE_RRD_DATA(); + return NULL; + } + + ts->start = SECS_TO_SDB_TIME(start + (time_t)step); + ts->end = SECS_TO_SDB_TIME(end); + + data_ptr = data; + for (t = start + (time_t)step; t <= end; t += (time_t)step) { + unsigned long i, j; + + i = (unsigned long)(t - start) / step - 1; + + for (j = 0; j < ds_cnt; ++j) { + ts->data[j][i].timestamp = SECS_TO_SDB_TIME(t); + ts->data[j][i].value = *data_ptr; + ++data_ptr; + } + } + + FREE_RRD_DATA(); + return ts; +} /* sdb_rrd_fetch */ + +int +sdb_module_init(sdb_plugin_info_t *info) +{ + sdb_plugin_set_info(info, SDB_PLUGIN_INFO_DESC, + "fetch time-series from RRD files"); + sdb_plugin_set_info(info, SDB_PLUGIN_INFO_COPYRIGHT, + "Copyright (C) 2014 Sebastian 'tokkee' Harl "); + sdb_plugin_set_info(info, SDB_PLUGIN_INFO_LICENSE, "BSD"); + sdb_plugin_set_info(info, SDB_PLUGIN_INFO_VERSION, SDB_VERSION); + sdb_plugin_set_info(info, SDB_PLUGIN_INFO_PLUGIN_VERSION, SDB_VERSION); + + sdb_plugin_register_ts_fetcher("rrdtool", sdb_rrd_fetch, NULL); + return 0; +} /* sdb_module_init */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + -- 2.30.2