X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fwrite_graphite.c;h=9feb6b338458f828d0deb4bbacf81a6feb3750d3;hb=0a8741b9061f8df4a78a448c021612db06e17425;hp=a7eef3fb435616ca6093207c385eb8ba90a104a2;hpb=65c20e41cfad6e7ab024983f561835fd347124ce;p=collectd.git diff --git a/src/write_graphite.c b/src/write_graphite.c index a7eef3fb..9feb6b33 100644 --- a/src/write_graphite.c +++ b/src/write_graphite.c @@ -43,18 +43,13 @@ */ #include "collectd.h" + #include "common.h" #include "plugin.h" -#include "configfile.h" -#include "utils_cache.h" #include "utils_complain.h" #include "utils_format_graphite.h" -/* Folks without pthread will need to disable this plugin. */ -#include - -#include #include #ifndef WG_DEFAULT_NODE @@ -113,8 +108,36 @@ struct wg_callback pthread_mutex_t send_lock; c_complain_t init_complaint; cdtime_t last_connect_time; + + /* Force reconnect useful for load balanced environments */ + cdtime_t last_reconnect_time; + cdtime_t reconnect_interval; + _Bool reconnect_interval_reached; }; +/* wg_force_reconnect_check closes cb->sock_fd when it was open for longer + * than cb->reconnect_interval. Must hold cb->send_lock when calling. */ +static void wg_force_reconnect_check (struct wg_callback *cb) +{ + cdtime_t now; + + if (cb->reconnect_interval == 0) + return; + + /* check if address changes if addr_timeout */ + now = cdtime (); + if ((now - cb->last_reconnect_time) < cb->reconnect_interval) + return; + + /* here we should close connection on next */ + close (cb->sock_fd); + cb->sock_fd = -1; + cb->last_reconnect_time = now; + cb->reconnect_interval_reached = 1; + + INFO ("write_graphite plugin: Connection closed after %.3f seconds.", + CDTIME_T_TO_DOUBLE (now - cb->last_reconnect_time)); +} /* * Functions @@ -129,18 +152,19 @@ static void wg_reset_buffer (struct wg_callback *cb) static int wg_send_buffer (struct wg_callback *cb) { - ssize_t status = 0; + ssize_t status; + + if (cb->sock_fd < 0) + return (-1); status = swrite (cb->sock_fd, cb->send_buf, strlen (cb->send_buf)); if (status != 0) { - const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL; - if (cb->log_send_errors) { char errbuf[1024]; ERROR ("write_graphite plugin: send to %s:%s (%s) failed with status %zi (%s)", - cb->node, cb->service, protocol, + cb->node, cb->service, cb->protocol, status, sstrerror (errno, errbuf, sizeof (errbuf))); } @@ -173,7 +197,7 @@ static int wg_flush_nolock (cdtime_t timeout, struct wg_callback *cb) return (0); } - if (cb->send_buf_fill <= 0) + if (cb->send_buf_fill == 0) { cb->send_buf_init_time = cdtime (); return (0); @@ -187,16 +211,10 @@ static int wg_flush_nolock (cdtime_t timeout, struct wg_callback *cb) static int wg_callback_init (struct wg_callback *cb) { - struct addrinfo ai_hints; struct addrinfo *ai_list; - struct addrinfo *ai_ptr; cdtime_t now; int status; - const char *node = cb->node ? cb->node : WG_DEFAULT_NODE; - const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE; - const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL; - char connerr[1024] = ""; if (cb->sock_fd > 0) @@ -209,29 +227,26 @@ static int wg_callback_init (struct wg_callback *cb) return (EAGAIN); cb->last_connect_time = now; - memset (&ai_hints, 0, sizeof (ai_hints)); -#ifdef AI_ADDRCONFIG - ai_hints.ai_flags |= AI_ADDRCONFIG; -#endif - ai_hints.ai_family = AF_UNSPEC; + struct addrinfo ai_hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_ADDRCONFIG + }; - if (0 == strcasecmp ("tcp", protocol)) + if (0 == strcasecmp ("tcp", cb->protocol)) ai_hints.ai_socktype = SOCK_STREAM; else ai_hints.ai_socktype = SOCK_DGRAM; - ai_list = NULL; - - status = getaddrinfo (node, service, &ai_hints, &ai_list); + status = getaddrinfo (cb->node, cb->service, &ai_hints, &ai_list); if (status != 0) { ERROR ("write_graphite plugin: getaddrinfo (%s, %s, %s) failed: %s", - node, service, protocol, gai_strerror (status)); + cb->node, cb->service, cb->protocol, gai_strerror (status)); return (-1); } assert (ai_list != NULL); - for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) + for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) { cb->sock_fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); @@ -242,6 +257,8 @@ static int wg_callback_init (struct wg_callback *cb) continue; } + set_sock_opts (cb->sock_fd); + status = connect (cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if (status != 0) { @@ -265,17 +282,23 @@ static int wg_callback_init (struct wg_callback *cb) sstrerror (errno, connerr, sizeof (connerr)); c_complain (LOG_ERR, &cb->init_complaint, "write_graphite plugin: Connecting to %s:%s via %s failed. " - "The last error was: %s", node, service, protocol, connerr); + "The last error was: %s", cb->node, cb->service, cb->protocol, connerr); return (-1); } else { c_release (LOG_INFO, &cb->init_complaint, "write_graphite plugin: Successfully connected to %s:%s via %s.", - node, service, protocol); + cb->node, cb->service, cb->protocol); } - wg_reset_buffer (cb); + /* wg_force_reconnect_check does not flush the buffer before closing a + * sending socket, so only call wg_reset_buffer() if the socket was closed + * for a different reason (tracked in cb->reconnect_interval_reached). */ + if (!cb->reconnect_interval_reached || (cb->send_buf_free == 0)) + wg_reset_buffer (cb); + else + cb->reconnect_interval_reached = 0; return (0); } @@ -351,6 +374,8 @@ static int wg_send_message (char const *message, struct wg_callback *cb) pthread_mutex_lock (&cb->send_lock); + wg_force_reconnect_check (cb); + if (cb->sock_fd < 0) { status = wg_callback_init (cb); @@ -383,9 +408,7 @@ static int wg_send_message (char const *message, struct wg_callback *cb) cb->send_buf_free -= message_len; DEBUG ("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"", - cb->node, - cb->service, - cb->protocol, + cb->node, cb->service, cb->protocol, cb->send_buf_fill, sizeof (cb->send_buf), 100.0 * ((double) cb->send_buf_fill) / ((double) sizeof (cb->send_buf)), message); @@ -398,7 +421,7 @@ static int wg_send_message (char const *message, struct wg_callback *cb) static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, struct wg_callback *cb) { - char buffer[WG_SEND_BUF_SIZE]; + char buffer[WG_SEND_BUF_SIZE] = { 0 }; int status; if (0 != strcmp (ds->type, vl->type)) @@ -408,7 +431,6 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, return -1; } - memset (buffer, 0, sizeof (buffer)); status = format_graphite (buffer, sizeof (buffer), ds, vl, cb->prefix, cb->postfix, cb->escape_char, cb->format_flags); if (status != 0) /* error message has been printed already. */ @@ -441,11 +463,9 @@ static int wg_write (const data_set_t *ds, const value_list_t *vl, static int config_set_char (char *dest, oconfig_item_t *ci) { - char buffer[4]; + char buffer[4] = { 0 }; int status; - memset (buffer, 0, sizeof (buffer)); - status = cf_util_get_string_buffer (ci, buffer, sizeof (buffer)); if (status != 0) return (status); @@ -472,23 +492,23 @@ static int config_set_char (char *dest, static int wg_config_node (oconfig_item_t *ci) { struct wg_callback *cb; - user_data_t user_data; char callback_name[DATA_MAX_NAME_LEN]; - int i; int status = 0; - cb = malloc (sizeof (*cb)); + cb = calloc (1, sizeof (*cb)); if (cb == NULL) { - ERROR ("write_graphite plugin: malloc failed."); + ERROR ("write_graphite plugin: calloc failed."); return (-1); } - memset (cb, 0, sizeof (*cb)); cb->sock_fd = -1; cb->name = NULL; - cb->node = NULL; - cb->service = NULL; - cb->protocol = NULL; + cb->node = strdup (WG_DEFAULT_NODE); + cb->service = strdup (WG_DEFAULT_SERVICE); + cb->protocol = strdup (WG_DEFAULT_PROTOCOL); + cb->last_reconnect_time = cdtime(); + cb->reconnect_interval = 0; + cb->reconnect_interval_reached = 0; cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS; cb->prefix = NULL; cb->postfix = NULL; @@ -509,7 +529,7 @@ static int wg_config_node (oconfig_item_t *ci) pthread_mutex_init (&cb->send_lock, /* attr = */ NULL); C_COMPLAIN_INIT (&cb->init_complaint); - for (i = 0; i < ci->children_num; i++) + for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; @@ -529,6 +549,8 @@ static int wg_config_node (oconfig_item_t *ci) status = -1; } } + else if (strcasecmp ("ReconnectInterval", child->key) == 0) + cf_util_get_cdtime (child, &cb->reconnect_interval); else if (strcasecmp ("LogSendErrors", child->key) == 0) cf_util_get_boolean (child, &cb->log_send_errors); else if (strcasecmp ("Prefix", child->key) == 0) @@ -544,6 +566,12 @@ static int wg_config_node (oconfig_item_t *ci) else if (strcasecmp ("AlwaysAppendDS", child->key) == 0) cf_util_get_flag (child, &cb->format_flags, GRAPHITE_ALWAYS_APPEND_DS); + else if (strcasecmp ("PreserveSeparator", child->key) == 0) + cf_util_get_flag (child, &cb->format_flags, + GRAPHITE_PRESERVE_SEPARATOR); + else if (strcasecmp ("DropDuplicateFields", child->key) == 0) + cf_util_get_flag (child, &cb->format_flags, + GRAPHITE_DROP_DUPE_FIELDS); else if (strcasecmp ("EscapeCharacter", child->key) == 0) config_set_char (&cb->escape_char, child); else @@ -566,29 +594,25 @@ static int wg_config_node (oconfig_item_t *ci) /* FIXME: Legacy configuration syntax. */ if (cb->name == NULL) ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s/%s", - cb->node != NULL ? cb->node : WG_DEFAULT_NODE, - cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE, - cb->protocol != NULL ? cb->protocol : WG_DEFAULT_PROTOCOL); + cb->node, cb->service, cb->protocol); else ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s", cb->name); - memset (&user_data, 0, sizeof (user_data)); - user_data.data = cb; - user_data.free_func = wg_callback_free; - plugin_register_write (callback_name, wg_write, &user_data); + plugin_register_write (callback_name, wg_write, + &(user_data_t) { + .data = cb, + .free_func = wg_callback_free, + }); - user_data.free_func = NULL; - plugin_register_flush (callback_name, wg_flush, &user_data); + plugin_register_flush (callback_name, wg_flush, &(user_data_t) { .data = cb }); return (0); } static int wg_config (oconfig_item_t *ci) { - int i; - - for (i = 0; i < ci->children_num; i++) + for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i;