From 36e8719c3eb45e45cc21dff35d675741ef34802d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9s=20J=2E=20D=C3=ADaz?= Date: Thu, 7 Nov 2013 09:57:53 +0100 Subject: [PATCH] Switch redis.c plugin from credis to hiredis. Change the entire redis.c plugin to use libhiredis (tested with libhiredis0.10) instead on credis. The libhiredis is supported in a number of distributions like Debian or Ubuntu. This patch keeps the same functionality that the old redis.c does. Conflicts: src/redis.c src/types.db --- configure.ac | 62 +++++++++++++++++++++++- src/Makefile.am | 6 +-- src/redis.c | 144 ++++++++++++++++++++++++++------------------------------ src/types.db | 4 ++ 4 files changed, 136 insertions(+), 80 deletions(-) diff --git a/configure.ac b/configure.ac index a00eebb1..15fdd17c 100644 --- a/configure.ac +++ b/configure.ac @@ -1637,6 +1637,65 @@ fi AM_CONDITIONAL(BUILD_WITH_LIBCREDIS, test "x$with_libcredis" = "xyes") # }}} +# --with-libhiredis {{{ +AC_ARG_WITH(libhiredis, [AS_HELP_STRING([--with-libhiredis@<:@=PREFIX@:>@], + [Path to libhiredis.])], +[ + if test "x$withval" = "xyes" + then + with_libhiredis="yes" + else if test "x$withval" = "xno" + then + with_libhiredis="no" + else + with_libhiredis="yes" + LIBHIREDIS_CPPFLAGS="$LIBHIREDIS_CPPFLAGS -I$withval/include" + LIBHIREDIS_LDFLAGS="$LIBHIREDIS_LDFLAGS -L$withval/lib" + fi; fi +], +[with_libhiredis="yes"]) + +SAVE_CPPFLAGS="$CPPFLAGS" +SAVE_LDFLAGS="$LDFLAGS" + +CPPFLAGS="$CPPFLAGS $LIBHIREDIS_CPPFLAGS" +LDFLAGS="$LDFLAGS $LIBHIREDIS_LDFLAGS" + +if test "x$with_libhiredis" = "xyes" +then + if test "x$LIBHIREDIS_CPPFLAGS" != "x" + then + AC_MSG_NOTICE([libhiredis CPPFLAGS: $LIBHIREDIS_CPPFLAGS]) + fi + AC_CHECK_HEADERS(hiredis/hiredis.h, + [with_libhiredis="yes"], + [with_libhiredis="no (hiredis.h not found)"]) +fi +if test "x$with_libhiredis" = "xyes" +then + if test "x$LIBHIREDIS_LDFLAGS" != "x" + then + AC_MSG_NOTICE([libhiredis LDFLAGS: $LIBHIREDIS_LDFLAGS]) + fi + AC_CHECK_LIB(hiredis, redisCommand, + [with_libhiredis="yes"], + [with_libhiredis="no (symbol 'redisCommand' not found)"]) + +fi + +CPPFLAGS="$SAVE_CPPFLAGS" +LDFLAGS="$SAVE_LDFLAGS" + +if test "x$with_libhiredis" = "xyes" +then + BUILD_WITH_LIBHIREDIS_CPPFLAGS="$LIBHIREDIS_CPPFLAGS" + BUILD_WITH_LIBHIREDIS_LDFLAGS="$LIBHIREDIS_LDFLAGS" + AC_SUBST(BUILD_WITH_LIBHIREDIS_CPPFLAGS) + AC_SUBST(BUILD_WITH_LIBHIREDIS_LDFLAGS) +fi +AM_CONDITIONAL(BUILD_WITH_LIBHIREDIS, test "x$with_libhiredis" = "xyes") +# }}} + # --with-libcurl {{{ with_curl_config="curl-config" with_curl_cflags="" @@ -5397,7 +5456,7 @@ AC_PLUGIN([powerdns], [yes], [PowerDNS statistics]) AC_PLUGIN([processes], [$plugin_processes], [Process statistics]) AC_PLUGIN([protocols], [$plugin_protocols], [Protocol (IP, TCP, ...) statistics]) AC_PLUGIN([python], [$with_python], [Embed a Python interpreter]) -AC_PLUGIN([redis], [$with_libcredis], [Redis plugin]) +AC_PLUGIN([redis], [$with_libhiredis], [Redis plugin]) AC_PLUGIN([routeros], [$with_librouteros], [RouterOS plugin]) AC_PLUGIN([rrdcached], [$librrd_rrdc_update], [RRDTool output plugin]) AC_PLUGIN([rrdtool], [$with_librrd], [RRDTool output plugin]) @@ -5627,6 +5686,7 @@ Configuration: libcurl . . . . . . . $with_libcurl libdbi . . . . . . . $with_libdbi libcredis . . . . . . $with_libcredis + libhiredis . . . . . $with_libhiredis libesmtp . . . . . . $with_libesmtp libganglia . . . . . $with_libganglia libgcrypt . . . . . . $with_libgcrypt diff --git a/src/Makefile.am b/src/Makefile.am index 4e62675f..ee7cf6ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -833,9 +833,9 @@ endif if BUILD_PLUGIN_REDIS pkglib_LTLIBRARIES += redis.la redis_la_SOURCES = redis.c -redis_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBCREDIS_LDFLAGS) -redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS) -redis_la_LIBADD = -lcredis +redis_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBHIREDIS_LDFLAGS) +redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBHIREDIS_CPPFLAGS) +redis_la_LIBADD = -lhiredis endif if BUILD_PLUGIN_ROUTEROS diff --git a/src/redis.c b/src/redis.c index 92be18f8..dcede599 100644 --- a/src/redis.c +++ b/src/redis.c @@ -26,7 +26,8 @@ #include "configfile.h" #include -#include +#include +#include #ifndef HOST_NAME_MAX # define HOST_NAME_MAX _POSIX_HOST_NAME_MAX @@ -45,7 +46,8 @@ * * Host "localhost" * Port "6379" - * Timeout 2000 + * Timeout 2 + * Password "foobar" * * */ @@ -107,6 +109,7 @@ static int redis_node_add (const redis_node_t *rn) /* {{{ */ return (0); } /* }}} */ + static int redis_config_node (oconfig_item_t *ci) /* {{{ */ { redis_node_t rn; @@ -180,39 +183,14 @@ static int redis_config (oconfig_item_t *ci) /* {{{ */ } /* }}} */ __attribute__ ((nonnull(2))) -static void redis_submit_g (char *plugin_instance, +static void redis_submit (char *plugin_instance, const char *type, const char *type_instance, - gauge_t value) /* {{{ */ + value_t value) /* {{{ */ { value_t values[1]; value_list_t vl = VALUE_LIST_INIT; - values[0].gauge = value; - - vl.values = values; - vl.values_len = 1; - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, "redis", sizeof (vl.plugin)); - if (plugin_instance != NULL) - sstrncpy (vl.plugin_instance, plugin_instance, - sizeof (vl.plugin_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); -} /* }}} */ - - __attribute__ ((nonnull(2))) -static void redis_submit_d (char *plugin_instance, - const char *type, const char *type_instance, - derive_t value) /* {{{ */ -{ - value_t values[1]; - value_list_t vl = VALUE_LIST_INIT; - - values[0].derive = value; + values[0] = value; vl.values = values; vl.values_len = 1; @@ -231,8 +209,13 @@ static void redis_submit_d (char *plugin_instance, static int redis_init (void) /* {{{ */ { - redis_node_t rn = { "default", REDIS_DEF_HOST, REDIS_DEF_PASSWD, - REDIS_DEF_PORT, REDIS_DEF_TIMEOUT, /* next = */ NULL }; + redis_node_t rn = { + .name = "default", + .host = REDIS_DEF_HOST, + .port = REDIS_DEF_PORT, + .timeout = REDIS_DEF_TIMEOUT, + .next = NULL +}; if (nodes_head == NULL) redis_node_add (&rn); @@ -240,20 +223,50 @@ static int redis_init (void) /* {{{ */ return (0); } /* }}} int redis_init */ +int redis_handle_info (char *node, char const *info_line, char const *type, char const *type_instance, char const *field_name, int ds_type) /* {{{ */ +{ + char *str = strstr (info_line, field_name); + static char buf[MAX_REDIS_VAL_SIZE]; + value_t val; + if (str) + { + int i; + + str += strlen (field_name) + 1; /* also skip the ':' */ + for(i=0;(*str && (isdigit(*str) || *str == '.'));i++,str++) + buf[i] = *str; + buf[i] ='\0'; + + if(parse_value (buf, &val, ds_type) == -1) + { + WARNING ("redis plugin: Unable to parse field `%s'.", field_name); + return (-1); + } + + redis_submit (node, type, type_instance, val); + return (0); + } + return (-1); + +} /* }}} int redis_handle_info */ + static int redis_read (void) /* {{{ */ { redis_node_t *rn; for (rn = nodes_head; rn != NULL; rn = rn->next) { - REDIS rh; - REDIS_INFO info; + redisContext *rh; + redisReply *rr; + + struct timeval tmout; - int status; + tmout.tv_sec = rn->timeout; + tmout.tv_usec = 0; DEBUG ("redis plugin: querying info from node `%s' (%s:%d).", rn->name, rn->host, rn->port); - rh = credis_connect (rn->host, rn->port, rn->timeout); + rh = redisConnectWithTimeout ((char *)rn->host, rn->port, tmout); if (rh == NULL) { ERROR ("redis plugin: unable to connect to node `%s' (%s:%d).", rn->name, rn->host, rn->port); @@ -263,56 +276,35 @@ static int redis_read (void) /* {{{ */ if (strlen (rn->passwd) > 0) { DEBUG ("redis plugin: authenticanting node `%s' passwd(%s).", rn->name, rn->passwd); - status = credis_auth(rh, rn->passwd); - if (status != 0) + rr = redisCommand (rh, "AUTH %s", rn->passwd); + + if (rr == NULL || rr->type != 5) { WARNING ("redis plugin: unable to authenticate on node `%s'.", rn->name); - credis_close (rh); + redisFree (rh); continue; } } - memset (&info, 0, sizeof (info)); - status = credis_info (rh, &info); - if (status != 0) + if ((rr = redisCommand(rh, "INFO")) == NULL) { - WARNING ("redis plugin: unable to get info from node `%s'.", rn->name); - credis_close (rh); + WARNING ("redis plugin: unable to connect to node `%s'.", rn->name); + redisFree (rh); continue; } - /* typedef struct _cr_info { - * char redis_version[CREDIS_VERSION_STRING_SIZE]; - * int bgsave_in_progress; - * int connected_clients; - * int connected_slaves; - * unsigned int used_memory; - * long long changes_since_last_save; - * int last_save_time; - * long long total_connections_received; - * long long total_commands_processed; - * int uptime_in_seconds; - * int uptime_in_days; - * int role; - * } REDIS_INFO; */ - - DEBUG ("redis plugin: received info from node `%s': connected_clients = %d; " - "connected_slaves = %d; used_memory = %lu; changes_since_last_save = %lld; " - "bgsave_in_progress = %d; total_connections_received = %lld; " - "total_commands_processed = %lld; uptime_in_seconds = %ld", rn->name, - info.connected_clients, info.connected_slaves, info.used_memory, - info.changes_since_last_save, info.bgsave_in_progress, - info.total_connections_received, info.total_commands_processed, - info.uptime_in_seconds); - - redis_submit_g (rn->name, "current_connections", "clients", info.connected_clients); - redis_submit_g (rn->name, "current_connections", "slaves", info.connected_slaves); - redis_submit_g (rn->name, "memory", "used", info.used_memory); - redis_submit_g (rn->name, "volatile_changes", NULL, info.changes_since_last_save); - redis_submit_d (rn->name, "total_connections", NULL, info.total_connections_received); - redis_submit_d (rn->name, "total_operations", NULL, info.total_commands_processed); - - credis_close (rh); + redis_handle_info (rn->name, rr->str, "uptime", NULL, "uptime_in_seconds", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "connections", "clients", "connected_clients", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "connections", "slaves", "connected_slaves", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "blocked_clients", NULL, "blocked_clients", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "memory", NULL, "used_memory", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "changes_since_last_save", NULL, "changes_since_last_save", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "operations", NULL, "total_commands_processed", DS_TYPE_DERIVE); + redis_handle_info (rn->name, rr->str, "expired_keys", NULL, "expired_keys", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "pubsub", "patterns", "pubsub_patterns", DS_TYPE_GAUGE); + redis_handle_info (rn->name, rr->str, "pubsub", "channels", "pubsub_channels", DS_TYPE_GAUGE); + + redisFree (rh); } return 0; diff --git a/src/types.db b/src/types.db index 64137b07..4c50b848 100644 --- a/src/types.db +++ b/src/types.db @@ -8,12 +8,14 @@ ath_nodes value:GAUGE:0:65535 ath_stat value:DERIVE:0:U backends value:GAUGE:0:65535 bitrate value:GAUGE:0:4294967295 +blocked_clients value:GAUGE:0:U bytes value:GAUGE:0:U cache_eviction value:DERIVE:0:U cache_operation value:DERIVE:0:U cache_ratio value:GAUGE:0:100 cache_result value:DERIVE:0:U cache_size value:GAUGE:0:U +changes_since_last_save value:GAUGE:0:U charge value:GAUGE:0:U compression_ratio value:GAUGE:0:2 compression uncompressed:DERIVE:0:U, compressed:DERIVE:0:U @@ -59,6 +61,7 @@ email_check value:GAUGE:0:U email_count value:GAUGE:0:U email_size value:GAUGE:0:U entropy value:GAUGE:0:4294967295 +expired_keys value:GAUGE:0:U fanspeed value:GAUGE:0:U file_size value:GAUGE:0:U files value:GAUGE:0:U @@ -156,6 +159,7 @@ ps_rss value:GAUGE:0:9223372036854775807 ps_stacksize value:GAUGE:0:9223372036854775807 ps_state value:GAUGE:0:65535 ps_vm value:GAUGE:0:9223372036854775807 +pubsub value:GAUGE:0:U queue_length value:GAUGE:0:U records value:GAUGE:0:U requests value:GAUGE:0:U -- 2.11.0