X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fwrite_graphite.c;h=546111bb1ba998f2122d424b1d92a42de273609e;hb=fa1a863f0803cc5c6fec5ba3adf31a836121295d;hp=9e96198d6951c4eb64f469b4a28e083fe3950a07;hpb=39dccb06ed38bff82b09085796b58e34ad39d273;p=collectd.git diff --git a/src/write_graphite.c b/src/write_graphite.c index 9e96198d..546111bb 100644 --- a/src/write_graphite.c +++ b/src/write_graphite.c @@ -1,6 +1,10 @@ /** * collectd - src/write_graphite.c - * Copyright (C) 2011 Scott Sanders + * Copyright (C) 2012 Pierre-Yves Ritschard + * Copyright (C) 2011 Scott Sanders + * Copyright (C) 2009 Paul Sadauskas + * Copyright (C) 2009 Doug MacEachern + * Copyright (C) 2007-2013 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -15,10 +19,14 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Author: - * Scott Sanders + * Authors: + * Florian octo Forster + * Doug MacEachern + * Paul Sadauskas + * Scott Sanders + * Pierre-Yves Ritschard * - * based on the excellent write_http plugin + * Based on the write_http plugin. **/ /* write_graphite plugin configuation example @@ -27,6 +35,8 @@ * * Host "localhost" * Port "2003" + * Protocol "udp" + * LogSendErrors true * Prefix "collectd" * * @@ -38,26 +48,16 @@ #include "configfile.h" #include "utils_cache.h" +#include "utils_complain.h" #include "utils_parse_option.h" +#include "utils_format_graphite.h" /* Folks without pthread will need to disable this plugin. */ #include #include -#include -#include - -#include #include -#ifndef WG_FORMAT_NAME -#define WG_FORMAT_NAME(ret, ret_len, vl, cb, name) \ - wg_format_name (ret, ret_len, (vl)->host, (vl)->plugin, \ - (vl)->plugin_instance, (vl)->type, \ - (vl)->type_instance, (cb)->prefix, (cb)->postfix, \ - name, (cb)->dotchar) -#endif - #ifndef WG_DEFAULT_NODE # define WG_DEFAULT_NODE "localhost" #endif @@ -66,8 +66,21 @@ # define WG_DEFAULT_SERVICE "2003" #endif +#ifndef WG_DEFAULT_PROTOCOL +# define WG_DEFAULT_PROTOCOL "udp" +#endif + +#ifndef WG_DEFAULT_LOG_SEND_ERRORS +# define WG_DEFAULT_LOG_SEND_ERRORS 1 +#endif + +#ifndef WG_DEFAULT_ESCAPE +# define WG_DEFAULT_ESCAPE '_' +#endif + +/* Ethernet - (IPv6 + TCP) = 1500 - (40 + 32) = 1428 */ #ifndef WG_SEND_BUF_SIZE -# define WG_SEND_BUF_SIZE 4096 +# define WG_SEND_BUF_SIZE 1428 #endif /* @@ -76,13 +89,18 @@ struct wg_callback { int sock_fd; - struct hostent *server; + + char *name; char *node; char *service; + char *protocol; + _Bool log_send_errors; char *prefix; char *postfix; - char dotchar; + char escape_char; + + unsigned int format_flags; char send_buf[WG_SEND_BUF_SIZE]; size_t send_buf_free; @@ -90,6 +108,7 @@ struct wg_callback cdtime_t send_buf_init_time; pthread_mutex_t send_lock; + c_complain_t init_complaint; }; @@ -106,30 +125,27 @@ static void wg_reset_buffer (struct wg_callback *cb) static int wg_send_buffer (struct wg_callback *cb) { - int status = 0; + ssize_t status = 0; - status = write (cb->sock_fd, cb->send_buf, strlen (cb->send_buf)); - if (status < 0) + status = swrite (cb->sock_fd, cb->send_buf, strlen (cb->send_buf)); + if (cb->log_send_errors && status < 0) { - ERROR ("write_graphite plugin: send failed with " - "status %i (%s)", - status, - strerror (errno)); + char errbuf[1024]; + ERROR ("write_graphite plugin: send to %s:%s (%s) failed with status %zi (%s)", + cb->node, cb->service, cb->protocol, + status, sstrerror (errno, errbuf, sizeof (errbuf))); - pthread_mutex_trylock (&cb->send_lock); - DEBUG ("write_graphite plugin: closing socket and restting fd " - "so reinit will occur"); close (cb->sock_fd); cb->sock_fd = -1; - pthread_mutex_unlock (&cb->send_lock); - return (-1); } + return (0); } +/* NOTE: You must hold cb->send_lock when calling this function! */ static int wg_flush_nolock (cdtime_t timeout, struct wg_callback *cb) { int status; @@ -170,6 +186,7 @@ static int wg_callback_init (struct wg_callback *cb) 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; if (cb->sock_fd > 0) return (0); @@ -179,15 +196,25 @@ static int wg_callback_init (struct wg_callback *cb) ai_hints.ai_flags |= AI_ADDRCONFIG; #endif ai_hints.ai_family = AF_UNSPEC; - ai_hints.ai_socktype = SOCK_STREAM; + + if (0 == strcasecmp ("tcp", protocol)) + ai_hints.ai_socktype = SOCK_STREAM; + else if (0 == strcasecmp ("udp", protocol)) + ai_hints.ai_socktype = SOCK_DGRAM; + else + { + ERROR ("write_graphite plugin: unknown protocol (%s)", + protocol); + return (-1); + } ai_list = NULL; status = getaddrinfo (node, service, &ai_hints, &ai_list); if (status != 0) { - ERROR ("write_graphite plugin: getaddrinfo (%s, %s) failed: %s", - node, service, gai_strerror (status)); + ERROR ("write_graphite plugin: getaddrinfo (%s, %s, %s) failed: %s", + node, service, protocol, gai_strerror (status)); return (-1); } @@ -215,12 +242,19 @@ static int wg_callback_init (struct wg_callback *cb) if (cb->sock_fd < 0) { char errbuf[1024]; - ERROR ("write_graphite plugin: Connecting to %s:%s failed. " - "The last error was: %s", node, service, + 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, sstrerror (errno, errbuf, sizeof (errbuf))); close (cb->sock_fd); return (-1); } + else + { + c_release (LOG_INFO, &cb->init_complaint, + "write_graphite plugin: Successfully connected to %s:%s via %s.", + node, service, protocol); + } wg_reset_buffer (cb); @@ -236,14 +270,22 @@ static void wg_callback_free (void *data) cb = data; + pthread_mutex_lock (&cb->send_lock); + wg_flush_nolock (/* timeout = */ 0, cb); close(cb->sock_fd); + cb->sock_fd = -1; + + sfree(cb->name); sfree(cb->node); + sfree(cb->protocol); sfree(cb->service); sfree(cb->prefix); sfree(cb->postfix); + pthread_mutex_destroy (&cb->send_lock); + sfree(cb); } @@ -266,7 +308,7 @@ static int wg_flush (cdtime_t timeout, status = wg_callback_init (cb); if (status != 0) { - ERROR ("write_graphite plugin: wg_callback_init failed."); + /* An error message has already been printed. */ pthread_mutex_unlock (&cb->send_lock); return (-1); } @@ -278,255 +320,12 @@ static int wg_flush (cdtime_t timeout, return (status); } -static int wg_format_values (char *ret, size_t ret_len, - int ds_num, const data_set_t *ds, const value_list_t *vl, - _Bool store_rates) -{ - size_t offset = 0; - int status; - gauge_t *rates = NULL; - - assert (0 == strcmp (ds->type, vl->type)); - - memset (ret, 0, ret_len); - -#define BUFFER_ADD(...) do { \ - status = ssnprintf (ret + offset, ret_len - offset, \ - __VA_ARGS__); \ - if (status < 1) \ - { \ - sfree (rates); \ - return (-1); \ - } \ - else if (((size_t) status) >= (ret_len - offset)) \ - { \ - sfree (rates); \ - return (-1); \ - } \ - else \ - offset += ((size_t) status); \ -} while (0) - - if (ds->ds[ds_num].type == DS_TYPE_GAUGE) - BUFFER_ADD ("%f", vl->values[ds_num].gauge); - else if (store_rates) - { - if (rates == NULL) - rates = uc_get_rate (ds, vl); - if (rates == NULL) - { - WARNING ("format_values: " - "uc_get_rate failed."); - return (-1); - } - BUFFER_ADD ("%g", rates[ds_num]); - } - else if (ds->ds[ds_num].type == DS_TYPE_COUNTER) - BUFFER_ADD ("%llu", vl->values[ds_num].counter); - else if (ds->ds[ds_num].type == DS_TYPE_DERIVE) - BUFFER_ADD ("%"PRIi64, vl->values[ds_num].derive); - else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE) - BUFFER_ADD ("%"PRIu64, vl->values[ds_num].absolute); - else - { - ERROR ("format_values plugin: Unknown data source type: %i", - ds->ds[ds_num].type); - sfree (rates); - return (-1); - } - -#undef BUFFER_ADD - - sfree (rates); - return (0); -} - -static int swap_chars (char *dst, const char *src, - const char from, const char to) -{ - size_t i; - - int reps = 0; - - for (i = 0; i < strlen(src) ; i++) - { - if (src[i] == from) - { - dst[i] = to; - ++reps; - } - else - dst[i] = src[i]; - } - dst[i] = '\0'; - - return reps; -} - -static int wg_format_name (char *ret, int ret_len, - const char *hostname, - const char *plugin, const char *plugin_instance, - const char *type, const char *type_instance, - const char *prefix, const char *postfix, - const char *ds_name, const char dotchar) -{ - int status; - char *n_hostname = NULL; - char *n_plugin = NULL; - char *n_plugin_instance = NULL; - char *n_type = NULL; - char *n_type_instance = NULL; - - assert (plugin != NULL); - assert (type != NULL); - - if ((n_hostname = malloc(strlen(hostname)+1)) == NULL) - { - ERROR ("Unable to allocate memory for normalized hostname buffer"); - return (-1); - } - - if ((n_plugin = malloc(strlen(plugin)+1)) == NULL) - { - ERROR ("Unable to allocate memory for normalized plugin buffer"); - return (-1); - } - - if ((n_type = malloc(strlen(type)+1)) == NULL) - { - ERROR ("Unable to allocate memory for normalized type buffer"); - return (-1); - } - - if (swap_chars(n_hostname, hostname, '.', dotchar) == -1) - { - ERROR ("Unable to normalize hostname"); - return (-1); - } - - if (swap_chars(n_plugin, plugin, ' ', '_') == -1) - { - ERROR ("Unable to normalize plugin"); - return (-1); - } - - if (swap_chars(n_type, type, ' ', '_') == -1) - { - ERROR ("Unable to normalize type"); - return (-1); - } - - if (type_instance != NULL && type_instance[0] != '\0') - { - if ((n_type_instance = malloc(strlen(type_instance)+1)) == NULL) - { - ERROR ("Unable to allocate memory for normalized datasource name buffer"); - return (-1); - } - if (swap_chars(n_type_instance, type_instance, '.', dotchar) == -1) - { - ERROR ("Unable to normalize datasource name"); - return (-1); - } - if (swap_chars(n_type_instance, type_instance, ' ', '_') == -1) - { - ERROR ("Unable to normalize datasource name"); - return (-1); - } - } - - if (plugin_instance != NULL && plugin_instance[0] != '\0') - { - if ((n_plugin_instance = malloc(strlen(plugin_instance)+1)) == NULL) - { - ERROR ("Unable to allocate memory for normalized plugin instance buffer"); - return (-1); - } - if (swap_chars(n_plugin_instance, plugin_instance, ' ', '_') == -1) - { - ERROR ("Unable to normalize datasource name"); - return (-1); - } - } - - if ((n_plugin_instance == NULL) || (n_plugin_instance[0] == '\0')) - { - if ((n_type_instance == NULL) || (n_type_instance[0] == '\0')) - { - if ((ds_name == NULL) || (ds_name[0] == '\0')) - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s", - prefix, n_hostname, postfix, n_plugin, n_type); - else - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s", - prefix, n_hostname, postfix, n_plugin, n_type, ds_name); - } - else - { - if ((ds_name == NULL) || (ds_name[0] == '\0')) - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s-%s", - prefix, n_hostname, postfix, n_plugin, n_type, - n_type_instance); - else - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s-%s.%s", - prefix, n_hostname, postfix, n_plugin, n_type, - n_type_instance, ds_name); - } - } - else - { - if ((n_type_instance == NULL) || (n_type_instance[0] == '\0')) - { - if ((ds_name == NULL) || (ds_name[0] == '\0')) - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s", - prefix, n_hostname, postfix, n_plugin, - n_plugin_instance, n_type); - else - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s.%s", - prefix, n_hostname, postfix, n_plugin, - n_plugin_instance, n_type, ds_name); - } - else - { - if ((ds_name == NULL) || (ds_name[0] == '\0')) - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s-%s", - prefix, n_hostname, postfix, n_plugin, - n_plugin_instance, n_type, n_type_instance); - else - status = ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s-%s.%s", - prefix, n_hostname, postfix, n_plugin, - n_plugin_instance, n_type, n_type_instance, ds_name); - } - } - - sfree(n_hostname); - sfree(n_type_instance); - sfree(n_type); - sfree(n_plugin); - sfree(n_plugin_instance); - - if ((status < 1) || (status >= ret_len)) - return (-1); - return (0); -} - -static int wg_send_message (const char* key, const char* value, - cdtime_t time, struct wg_callback *cb) +static int wg_send_message (char const *message, struct wg_callback *cb) { int status; size_t message_len; - char message[1024]; - - message_len = (size_t) ssnprintf (message, sizeof (message), - "%s %s %.0f\n", - key, - value, - CDTIME_T_TO_DOUBLE(time)); - if (message_len >= sizeof (message)) { - ERROR ("write_graphite plugin: message buffer too small: " - "Need %zu bytes.", message_len + 1); - return (-1); - } + message_len = strlen (message); pthread_mutex_lock (&cb->send_lock); @@ -535,7 +334,7 @@ static int wg_send_message (const char* key, const char* value, status = wg_callback_init (cb); if (status != 0) { - ERROR ("write_graphite plugin: wg_callback_init failed."); + /* An error message has already been printed. */ pthread_mutex_unlock (&cb->send_lock); return (-1); } @@ -550,6 +349,8 @@ static int wg_send_message (const char* key, const char* value, return (status); } } + + /* Assert that we have enough space for this message. */ assert (message_len < cb->send_buf_free); /* `message_len + 1' because `message_len' does not include the @@ -559,14 +360,14 @@ static int wg_send_message (const char* key, const char* value, cb->send_buf_fill += message_len; cb->send_buf_free -= message_len; - DEBUG ("write_graphite plugin: <%s:%s> buf %zu/%zu (%g%%) \"%s\"", + DEBUG ("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"", 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); - /* Check if we have enough space for this message. */ pthread_mutex_unlock (&cb->send_lock); return (0); @@ -575,10 +376,8 @@ static int wg_send_message (const char* key, const char* value, static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, struct wg_callback *cb) { - char key[10*DATA_MAX_NAME_LEN]; - char values[512]; - - int status, i; + char buffer[WG_SEND_BUF_SIZE]; + int status; if (0 != strcmp (ds->type, vl->type)) { @@ -587,72 +386,22 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, return -1; } - if (ds->ds_num > 1) - { - for (i = 0; i < ds->ds_num; i++) - { - /* Copy the identifier to `key' and escape it. */ - status = WG_FORMAT_NAME (key, sizeof (key), vl, cb, ds->ds[i].name); - if (status != 0) - { - ERROR ("write_graphite plugin: error with format_name"); - return (status); - } - - escape_string (key, sizeof (key)); - /* Convert the values to an ASCII representation and put that - * into `values'. */ - status = wg_format_values (values, sizeof (values), i, ds, vl, 0); - if (status != 0) - { - ERROR ("write_graphite plugin: error with " - "wg_format_values"); - return (status); - } - - /* Send the message to graphite */ - status = wg_send_message (key, values, vl->time, cb); - if (status != 0) - { - ERROR ("write_graphite plugin: error with " - "wg_send_message"); - return (status); - } - } - } - else - { - /* Copy the identifier to `key' and escape it. */ - status = WG_FORMAT_NAME (key, sizeof (key), vl, cb, NULL); - if (status != 0) - { - ERROR ("write_graphite plugin: error with format_name"); - return (status); - } + 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. */ + return (status); - escape_string (key, sizeof (key)); - /* Convert the values to an ASCII representation and put that into - * `values'. */ - status = wg_format_values (values, sizeof (values), 0, ds, vl, 0); - if (status != 0) - { - ERROR ("write_graphite plugin: error with " - "wg_format_values"); - return (status); - } - - /* Send the message to graphite */ - status = wg_send_message (key, values, vl->time, cb); - if (status != 0) - { - ERROR ("write_graphite plugin: error with " - "wg_send_message"); - return (status); - } + /* Send the message to graphite */ + wg_send_message (buffer, cb); + if (status != 0) + { + /* An error message has already been printed. */ + return (status); } return (0); -} +} /* int wg_write_messages */ static int wg_write (const data_set_t *ds, const value_list_t *vl, user_data_t *user_data) @@ -661,7 +410,7 @@ static int wg_write (const data_set_t *ds, const value_list_t *vl, int status; if (user_data == NULL) - return (-EINVAL); + return (EINVAL); cb = user_data->data; @@ -673,22 +422,39 @@ 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) { - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) + char buffer[4]; + int status; + + memset (buffer, 0, sizeof (buffer)); + + status = cf_util_get_string_buffer (ci, buffer, sizeof (buffer)); + if (status != 0) + return (status); + + if (buffer[0] == 0) { - WARNING ("write_graphite plugin: The `%s' config option " - "needs exactly one string argument.", ci->key); + ERROR ("write_graphite plugin: Cannot use an empty string for the " + "\"EscapeCharacter\" option."); return (-1); } - *dest = ci->values[0].value.string[0]; + if (buffer[1] != 0) + { + WARNING ("write_graphite plugin: Only the first character of the " + "\"EscapeCharacter\" option ('%c') will be used.", + (int) buffer[0]); + } + + *dest = buffer[0]; return (0); } -static int wg_config_carbon (oconfig_item_t *ci) +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; cb = malloc (sizeof (*cb)); @@ -699,14 +465,29 @@ static int wg_config_carbon (oconfig_item_t *ci) } memset (cb, 0, sizeof (*cb)); cb->sock_fd = -1; + cb->name = NULL; cb->node = NULL; cb->service = NULL; + cb->protocol = NULL; + cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS; cb->prefix = NULL; cb->postfix = NULL; - cb->server = NULL; - cb->dotchar = '_'; + cb->escape_char = WG_DEFAULT_ESCAPE; + cb->format_flags = GRAPHITE_STORE_RATES; + + /* FIXME: Legacy configuration syntax. */ + if (strcasecmp ("Carbon", ci->key) != 0) + { + int status = cf_util_get_string (ci, &cb->name); + if (status != 0) + { + wg_callback_free (cb); + return (status); + } + } pthread_mutex_init (&cb->send_lock, /* attr = */ NULL); + C_COMPLAIN_INIT (&cb->init_complaint); for (i = 0; i < ci->children_num; i++) { @@ -715,13 +496,26 @@ static int wg_config_carbon (oconfig_item_t *ci) if (strcasecmp ("Host", child->key) == 0) cf_util_get_string (child, &cb->node); else if (strcasecmp ("Port", child->key) == 0) - cf_util_get_string (child, &cb->service); + cf_util_get_service (child, &cb->service); + else if (strcasecmp ("Protocol", child->key) == 0) + cf_util_get_string (child, &cb->protocol); + else if (strcasecmp ("LogSendErrors", child->key) == 0) + cf_util_get_boolean (child, &cb->log_send_errors); else if (strcasecmp ("Prefix", child->key) == 0) cf_util_get_string (child, &cb->prefix); else if (strcasecmp ("Postfix", child->key) == 0) cf_util_get_string (child, &cb->postfix); - else if (strcasecmp ("DotCharacter", child->key) == 0) - config_set_char (&cb->dotchar, child); + else if (strcasecmp ("StoreRates", child->key) == 0) + cf_util_get_flag (child, &cb->format_flags, + GRAPHITE_STORE_RATES); + else if (strcasecmp ("SeparateInstances", child->key) == 0) + cf_util_get_flag (child, &cb->format_flags, + GRAPHITE_SEPARATE_INSTANCES); + else if (strcasecmp ("AlwaysAppendDS", child->key) == 0) + cf_util_get_flag (child, &cb->format_flags, + GRAPHITE_ALWAYS_APPEND_DS); + else if (strcasecmp ("EscapeCharacter", child->key) == 0) + config_set_char (&cb->escape_char, child); else { ERROR ("write_graphite plugin: Invalid configuration " @@ -729,17 +523,23 @@ static int wg_config_carbon (oconfig_item_t *ci) } } - DEBUG ("write_graphite: Registering write callback to carbon agent %s:%s", - cb->node ? cb->node : WG_DEFAULT_NODE, - cb->service ? cb->service : WG_DEFAULT_SERVICE); + /* 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); + 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 = NULL; - plugin_register_flush ("write_graphite", wg_flush, &user_data); - user_data.free_func = wg_callback_free; - plugin_register_write ("write_graphite", wg_write, &user_data); + plugin_register_write (callback_name, wg_write, &user_data); + + user_data.free_func = NULL; + plugin_register_flush (callback_name, wg_flush, &user_data); return (0); } @@ -752,8 +552,11 @@ static int wg_config (oconfig_item_t *ci) { oconfig_item_t *child = ci->children + i; - if (strcasecmp ("Carbon", child->key) == 0) - wg_config_carbon (child); + if (strcasecmp ("Node", child->key) == 0) + wg_config_node (child); + /* FIXME: Remove this legacy mode in version 6. */ + else if (strcasecmp ("Carbon", child->key) == 0) + wg_config_node (child); else { ERROR ("write_graphite plugin: Invalid configuration "