From: Florian Forster Date: Tue, 10 Aug 2010 11:26:45 +0000 (+0200) Subject: write_redis plugin: Add a new plugin writing collectd data to an instance of Redis. X-Git-Tag: collectd-5.0.0-beta0~50^2^2~3 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=f3706b0b8792e7340225d7667f69ffb7b178c08e;hp=fe3dc1b1d500cf1593009ef70487c3eb29cec57f;p=collectd.git write_redis plugin: Add a new plugin writing collectd data to an instance of Redis. --- diff --git a/configure.in b/configure.in index 962d1716..8ebf1244 100644 --- a/configure.in +++ b/configure.in @@ -4561,6 +4561,7 @@ AC_PLUGIN([vmem], [$plugin_vmem], [Virtual memory statistics]) AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer statistics]) AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics]) AC_PLUGIN([write_http], [$with_libcurl], [HTTP output plugin]) +AC_PLUGIN([write_redis], [$with_libcredis], [Redis output plugin]) AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics]) AC_PLUGIN([zfs_arc], [$plugin_zfs_arc], [ZFS ARC statistics]) @@ -4882,6 +4883,7 @@ Configuration: vserver . . . . . . . $enable_vserver wireless . . . . . . $enable_wireless write_http . . . . . $enable_write_http + write_redis . . . . . $enable_write_redis xmms . . . . . . . . $enable_xmms zfs_arc . . . . . . . $enable_zfs_arc diff --git a/src/Makefile.am b/src/Makefile.am index f44ad5f5..3bfebb62 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1210,6 +1210,16 @@ endif collectd_DEPENDENCIES += write_http.la endif +if BUILD_PLUGIN_WRITE_REDIS +pkglib_LTLIBRARIES += write_redis.la +write_redis_la_SOURCES = write_redis.c +write_redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS) +write_redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS) +write_redis_la_LIBADD = -lcredis +collectd_LDADD += "-dlopen" write_redis.la +collectd_DEPENDENCIES += write_redis.la +endif + if BUILD_PLUGIN_XMMS pkglib_LTLIBRARIES += xmms.la xmms_la_SOURCES = xmms.c diff --git a/src/collectd.conf.in b/src/collectd.conf.in index c96edad2..cc125ddf 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -139,6 +139,7 @@ #@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver #@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless #@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http +#@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc @@ -938,6 +939,14 @@ # # +# +# +# Host "localhost" +# Port "6379" +# Timeout 1000 +# +# + ############################################################################## # Filter configuration # #----------------------------------------------------------------------------# diff --git a/src/write_redis.c b/src/write_redis.c new file mode 100644 index 00000000..404391a6 --- /dev/null +++ b/src/write_redis.c @@ -0,0 +1,220 @@ +/** + * collectd - src/target_set.c + * Copyright (C) 2008-2010 Florian Forster + * + * 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: + * Florian Forster + **/ + +#include "collectd.h" +#include "plugin.h" +#include "common.h" +#include "configfile.h" + +#include +#include + +struct wr_node_s +{ + char name[DATA_MAX_NAME_LEN]; + + char *host; + int port; + int timeout; + + REDIS conn; + pthread_mutex_t lock; +}; +typedef struct wr_node_s wr_node_t; + +/* + * Functions + */ +static int wr_write (const data_set_t *ds, /* {{{ */ + const value_list_t *vl, + user_data_t *ud) +{ + wr_node_t *node = ud->data; + char key[512]; + char value[512]; + char tmp[512]; + int status; + int i; + + status = FORMAT_VL (tmp, sizeof (tmp), vl); + if (status != 0) + return (status); + ssnprintf (key, sizeof (key), "collectd/%s", tmp); + + ssnprintf (value, sizeof (value), "%lu", (unsigned long) vl->time); + for (i = 0; i < ds->ds_num; i++) + { + if (ds->ds[i].type == DS_TYPE_COUNTER) + ssnprintf (tmp, sizeof (tmp), "%s:%llu", + value, vl->values[i].counter); + else if (ds->ds[i].type == DS_TYPE_GAUGE) + ssnprintf (tmp, sizeof (tmp), "%s:%g", + value, vl->values[i].gauge); + else if (ds->ds[i].type == DS_TYPE_DERIVE) + ssnprintf (tmp, sizeof (tmp), "%s:%"PRIi64, + value, vl->values[i].derive); + else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) + ssnprintf (tmp, sizeof (tmp), "%s:%"PRIu64, + value, vl->values[i].absolute); + else + assert (23 == 42); + + memcpy (value, tmp, sizeof (value)); + } + + pthread_mutex_lock (&node->lock); + + if (node->conn == NULL) + { + node->conn = credis_connect (node->host, node->port, node->timeout); + if (node->conn == NULL) + { + ERROR ("write_redis plugin: Connecting to host \"%s\" (port %i) failed.", + (node->host != NULL) ? node->host : "localhost", + (node->port != 0) ? node->port : 6379); + pthread_mutex_unlock (&node->lock); + return (-1); + } + } + + /* "credis_zadd" doesn't handle a NULL pointer gracefully, so I'd rather + * have a meaningful assertion message than a normal segmentation fault. */ + assert (node->conn != NULL); + status = credis_zadd (node->conn, key, (double) vl->time, value); + + pthread_mutex_unlock (&node->lock); + + return (0); +} /* }}} int wr_write */ + +static void wr_config_free (void *ptr) /* {{{ */ +{ + wr_node_t *node = ptr; + + if (node == NULL) + return; + + if (node->conn != NULL) + { + credis_close (node->conn); + node->conn = NULL; + } + + sfree (node->host); + sfree (node); +} /* }}} void wr_config_free */ + +static int wr_config_node (oconfig_item_t *ci) /* {{{ */ +{ + wr_node_t *node; + int status; + int i; + + node = malloc (sizeof (*node)); + if (node == NULL) + return (ENOMEM); + memset (node, 0, sizeof (*node)); + node->host = NULL; + node->port = 0; + node->timeout = 1000; + node->conn = NULL; + pthread_mutex_init (&node->lock, /* attr = */ NULL); + + status = cf_util_get_string_buffer (ci, node->name, sizeof (node->name)); + if (status != 0) + { + sfree (node); + return (status); + } + + for (i = 0; i < ci->children_num; i++) + { + oconfig_item_t *child = ci->children + i; + + if (strcasecmp ("Host", child->key) == 0) + status = cf_util_get_string (child, &node->host); + else if (strcasecmp ("Port", child->key) == 0) + { + status = cf_util_get_port_number (child); + if (status > 0) + { + node->port = status; + status = 0; + } + } + else if (strcasecmp ("Timeout", child->key) == 0) + status = cf_util_get_int (child, &node->timeout); + else + WARNING ("write_redis plugin: Ignoring unknown config option \"%s\".", + child->key); + + if (status != 0) + break; + } /* for (i = 0; i < ci->children_num; i++) */ + + if (status == 0) + { + char cb_name[DATA_MAX_NAME_LEN]; + user_data_t ud; + + ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name); + + ud.data = node; + ud.free_func = wr_config_free; + + status = plugin_register_write (cb_name, wr_write, &ud); + } + + if (status != 0) + wr_config_free (node); + + return (status); +} /* }}} int wr_config_node */ + +static int wr_config (oconfig_item_t *ci) /* {{{ */ +{ + int i; + + for (i = 0; i < ci->children_num; i++) + { + oconfig_item_t *child = ci->children + i; + + if (strcasecmp ("Node", child->key) == 0) + wr_config_node (child); + else + WARNING ("write_redis plugin: Ignoring unknown " + "configuration option \"%s\" at top level.", child->key); + } + + return (0); +} /* }}} int wr_config */ + +void module_register (void) +{ + plugin_register_complex_config ("write_redis", wr_config); +} + +/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */