- redis_handle_info (rn->name, rr->str, "uptime", NULL, "uptime_in_seconds", DS_TYPE_GAUGE);
- redis_handle_info (rn->name, rr->str, "current_connections", "clients", "connected_clients", 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, "memory_lua", NULL, "used_memory_lua", DS_TYPE_GAUGE);
- /* changes_since_last_save: Deprecated in redis version 2.6 and above */
- redis_handle_info (rn->name, rr->str, "volatile_changes", NULL, "changes_since_last_save", DS_TYPE_GAUGE);
- redis_handle_info (rn->name, rr->str, "total_connections", NULL, "total_connections_received", DS_TYPE_DERIVE);
- redis_handle_info (rn->name, rr->str, "total_operations", NULL, "total_commands_processed", DS_TYPE_DERIVE);
- redis_handle_info (rn->name, rr->str, "expired_keys", NULL, "expired_keys", DS_TYPE_DERIVE);
- redis_handle_info (rn->name, rr->str, "pubsub", "channels", "pubsub_channels", DS_TYPE_GAUGE);
- redis_handle_info (rn->name, rr->str, "pubsub", "patterns", "pubsub_patterns", DS_TYPE_GAUGE);
- redis_handle_info (rn->name, rr->str, "current_connections", "slaves", "connected_slaves", DS_TYPE_GAUGE);
-
- for (rq = rn->queries; rq != NULL; rq = rq->next)
- redis_handle_query(rh, rn, rq);
-
-redis_fail:
- if (rr != NULL)
- freeReplyObject (rr);
- redisFree (rh);
+ freeReplyObject(rr);
+ }
+ return;
+} /* void redis_check_connection */
+
+static void redis_read_server_info(redis_node_t *rn) {
+ redisReply *rr;
+
+ if ((rr = c_redisCommand(rn, "INFO")) == NULL) {
+ WARNING("redis plugin: unable to get INFO from node `%s'.", rn->name);
+ return;
+ }
+
+ redis_handle_info(rn->name, rr->str, "uptime", NULL, "uptime_in_seconds",
+ DS_TYPE_GAUGE);
+ redis_handle_info(rn->name, rr->str, "current_connections", "clients",
+ "connected_clients", 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, "memory_lua", NULL, "used_memory_lua",
+ DS_TYPE_GAUGE);
+ /* changes_since_last_save: Deprecated in redis version 2.6 and above */
+ redis_handle_info(rn->name, rr->str, "volatile_changes", NULL,
+ "changes_since_last_save", DS_TYPE_GAUGE);
+ redis_handle_info(rn->name, rr->str, "total_connections", NULL,
+ "total_connections_received", DS_TYPE_DERIVE);
+ redis_handle_info(rn->name, rr->str, "total_operations", NULL,
+ "total_commands_processed", DS_TYPE_DERIVE);
+ redis_handle_info(rn->name, rr->str, "expired_keys", NULL, "expired_keys",
+ DS_TYPE_DERIVE);
+ redis_handle_info(rn->name, rr->str, "evicted_keys", NULL, "evicted_keys",
+ DS_TYPE_DERIVE);
+ redis_handle_info(rn->name, rr->str, "pubsub", "channels", "pubsub_channels",
+ DS_TYPE_GAUGE);
+ redis_handle_info(rn->name, rr->str, "pubsub", "patterns", "pubsub_patterns",
+ DS_TYPE_GAUGE);
+ redis_handle_info(rn->name, rr->str, "current_connections", "slaves",
+ "connected_slaves", DS_TYPE_GAUGE);
+ redis_handle_info(rn->name, rr->str, "total_bytes", "input",
+ "total_net_input_bytes", DS_TYPE_DERIVE);
+ redis_handle_info(rn->name, rr->str, "total_bytes", "output",
+ "total_net_output_bytes", DS_TYPE_DERIVE);
+
+ redis_keyspace_usage(rn, rr->str);
+
+ redis_db_stats(rn->name, rr->str);
+
+ if (rn->report_cpu_usage)
+ redis_cpu_usage(rn->name, rr->str);
+
+ freeReplyObject(rr);
+} /* void redis_read_server_info */
+
+static void redis_read_command_stats(redis_node_t *rn) {
+ redisReply *rr;
+
+ if ((rr = c_redisCommand(rn, "INFO commandstats")) == NULL) {
+ WARNING("redis plugin: node `%s': unable to get `INFO commandstats'.",
+ rn->name);
+ return;
+ }
+
+ if (rr->type != REDIS_REPLY_STRING) {
+ WARNING("redis plugin: node `%s' `INFO commandstats' returned unsupported "
+ "redis type %i.",
+ rn->name, rr->type);
+ freeReplyObject(rr);
+ return;
+ }
+
+ char *command;
+ char *line;
+ char *ptr = rr->str;
+ char *saveptr = NULL;
+ while ((line = strtok_r(ptr, "\n\r", &saveptr)) != NULL) {
+ ptr = NULL;
+
+ if (line[0] == '#')
+ continue;
+
+ /* command name */
+ if (strstr(line, "cmdstat_") != line) {
+ ERROR("redis plugin: not found 'cmdstat_' prefix in line '%s'", line);
+ continue;
+ }
+
+ char *values = strstr(line, ":");
+ if (values == NULL) {
+ ERROR("redis plugin: not found ':' separator in line '%s'", line);
+ continue;
+ }
+
+ /* Null-terminate command token */
+ values[0] = '\0';
+ command = line + strlen("cmdstat_");
+ values++;
+
+ /* parse values */
+ /* cmdstat_publish:calls=20795774,usec=111039258,usec_per_call=5.34 */
+ char *field;
+ char *saveptr_field = NULL;
+ while ((field = strtok_r(values, "=", &saveptr_field)) != NULL) {
+ values = NULL;
+
+ const char *type;
+ /* only these are supported */
+ if (strcmp(field, "calls") == 0)
+ type = "commands";
+ else if (strcmp(field, "usec") == 0)
+ type = "redis_command_cputime";
+ else
+ continue;
+
+ if ((field = strtok_r(NULL, ",", &saveptr_field)) == NULL)
+ continue;
+
+ char *endptr = NULL;
+ errno = 0;
+ derive_t value = strtoll(field, &endptr, 0);
+
+ if ((endptr == field) || (errno != 0))
+ continue;
+
+ redis_submit(rn->name, type, command, (value_t){.derive = value});
+ }
+ }
+ freeReplyObject(rr);
+} /* void redis_read_command_stats */
+
+static int redis_read(user_data_t *user_data) /* {{{ */
+{
+ redis_node_t *rn = user_data->data;
+
+ DEBUG("redis plugin: querying info from node `%s' (%s:%d).", rn->name,
+ rn->host, rn->port);
+
+ redis_check_connection(rn);
+
+ if (!rn->redisContext) /* no connection */
+ return -1;
+
+ redis_read_server_info(rn);
+
+ if (!rn->redisContext) /* connection lost */
+ return -1;
+
+ if (rn->report_command_stats) {
+ redis_read_command_stats(rn);
+
+ if (!rn->redisContext) /* connection lost */
+ return -1;
+ }
+
+ for (redis_query_t *rq = rn->queries; rq != NULL; rq = rq->next) {
+ redis_handle_query(rn, rq);
+ if (!rn->redisContext) /* connection lost */
+ return -1;