Make the dot substitution char configurable
[collectd.git] / src / write_graphite.c
index 322b825..0de419f 100644 (file)
@@ -24,7 +24,7 @@
  /* write_graphite plugin configuation example
   *
   * <Plugin write_graphite>
-  *   <Carbon "local-agent">
+  *   <Carbon>
   *     Host "localhost"
   *     Port 2003
   *     Prefix "collectd"
 #include <netdb.h>
 
 #ifndef WG_FORMAT_NAME
-#define WG_FORMAT_NAME(ret, ret_len, vl, prefix, name) \
-        wg_format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
-                        (vl)->type, (vl)->type_instance, prefix, 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, name, (cb)->dotchar)
+#endif
+
+#ifndef WG_SEND_BUF_SIZE
+#define WG_SEND_BUF_SIZE 4096
 #endif
 
 /*
  */
 struct wg_callback
 {
-    char    *name;
-
     int      sock_fd;
     struct hostent *server;
 
     char    *host;
     int      port;
     char    *prefix;
+    char     dotchar;
 
-    char     send_buf[4096];
+    char     send_buf[WG_SEND_BUF_SIZE];
     size_t   send_buf_free;
     size_t   send_buf_fill;
     cdtime_t send_buf_init_time;
@@ -82,15 +86,15 @@ struct wg_callback
 /*
  * Functions
  */
-static void wg_reset_buffer (struct wg_callback *cb) /* {{{ */
+static void wg_reset_buffer (struct wg_callback *cb)
 {
     memset (cb->send_buf, 0, sizeof (cb->send_buf));
     cb->send_buf_free = sizeof (cb->send_buf);
     cb->send_buf_fill = 0;
     cb->send_buf_init_time = cdtime ();
-} /* }}} wg_reset_buffer */
+}
 
-static int wg_send_buffer (struct wg_callback *cb) /* {{{ */
+static int wg_send_buffer (struct wg_callback *cb)
 {
     int status = 0;
 
@@ -114,9 +118,9 @@ static int wg_send_buffer (struct wg_callback *cb) /* {{{ */
         return (-1);
     }
     return (0);
-} /* }}} wg_send_buffer */
+}
 
-static int wg_flush_nolock (cdtime_t timeout, struct wg_callback *cb) /* {{{ */
+static int wg_flush_nolock (cdtime_t timeout, struct wg_callback *cb)
 {
     int status;
 
@@ -145,9 +149,9 @@ static int wg_flush_nolock (cdtime_t timeout, struct wg_callback *cb) /* {{{ */
     wg_reset_buffer (cb);
 
     return (status);
-} /* }}} wg_flush_nolock */
+}
 
-static int wg_callback_init (struct wg_callback *cb) /* {{{ */
+static int wg_callback_init (struct wg_callback *cb)
 {
     int status;
 
@@ -171,11 +175,13 @@ static int wg_callback_init (struct wg_callback *cb) /* {{{ */
     memset (&serv_addr, 0, sizeof (serv_addr));
     serv_addr.sin_family = AF_INET;
     memcpy (&serv_addr.sin_addr.s_addr,
-                cb->server->h_addr,
-                cb->server->h_length);
+             cb->server->h_addr,
+             cb->server->h_length);
     serv_addr.sin_port = htons(cb->port);
 
-    status = connect(cb->sock_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
+    status = connect(cb->sock_fd,
+                      (struct sockaddr *) &serv_addr,
+                      sizeof(serv_addr));
     if (status < 0)
     {
         char errbuf[1024];
@@ -189,9 +195,9 @@ static int wg_callback_init (struct wg_callback *cb) /* {{{ */
     wg_reset_buffer (cb);
 
     return (0);
-} /* }}} int wg_callback_init */
+}
 
-static void wg_callback_free (void *data) /* {{{ */
+static void wg_callback_free (void *data)
 {
     struct wg_callback *cb;
 
@@ -203,14 +209,13 @@ static void wg_callback_free (void *data) /* {{{ */
     wg_flush_nolock (/* timeout = */ 0, cb);
 
     close(cb->sock_fd);
-    sfree(cb->name);
     sfree(cb->host);
     sfree(cb->prefix);
 
     sfree(cb);
-} /* }}} void wg_callback_free */
+}
 
-static int wg_flush (cdtime_t timeout, /* {{{ */
+static int wg_flush (cdtime_t timeout,
         const char *identifier __attribute__((unused)),
         user_data_t *user_data)
 {
@@ -239,9 +244,9 @@ static int wg_flush (cdtime_t timeout, /* {{{ */
     pthread_mutex_unlock (&cb->send_lock);
 
     return (status);
-} /* }}} int wg_flush */
+}
 
-static int wg_format_values (char *ret, size_t ret_len, /* {{{ */
+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)
 {
@@ -302,9 +307,10 @@ static int wg_format_values (char *ret, size_t ret_len, /* {{{ */
 
     sfree (rates);
     return (0);
-} /* }}} int wg_format_values */
+}
 
-static int normalize_hostname (char *dst, const char *src) /* {{{ */
+static int swap_chars (char *dst, const char *src,
+        const char from, const char to)
 {
     size_t i;
 
@@ -312,9 +318,9 @@ static int normalize_hostname (char *dst, const char *src) /* {{{ */
 
     for (i = 0; i < strlen(src) ; i++)
     {
-        if (src[i] == '.')
+        if (src[i] == from)
         {
-            dst[i] = '_';
+            dst[i] = to;
             ++reps;
         }
         else
@@ -323,16 +329,17 @@ static int normalize_hostname (char *dst, const char *src) /* {{{ */
     dst[i] = '\0';
 
     return reps;
-} /* }}} int normalize_hostname */
+}
 
-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 *ds_name)
+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 *ds_name, const char dotchar)
 {
     int  status;
-    char *n_hostname;
+    char *n_hostname = 0;
+    char *n_type_instance = 0;
 
     assert (plugin != NULL);
     assert (type != NULL);
@@ -343,17 +350,30 @@ static int wg_format_name (char *ret, int ret_len, /* {{{ */
         return (-1);
     }
 
-    if (normalize_hostname(n_hostname, hostname) == -1)
+    if (swap_chars(n_hostname, hostname, '.', dotchar) == -1)
     {
         ERROR ("Unable to normalize hostname");
         return (-1);
     }
 
-    if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
+    if (type_instance && 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 ((plugin_instance == NULL) || (plugin_instance[0] == '\0'))
     {
-        if ((type_instance == NULL) || (strlen (type_instance) == 0))
+        if ((n_type_instance == NULL) || (n_type_instance[0] == '\0'))
         {
-            if ((ds_name == NULL) || (strlen (ds_name) == 0))
+            if ((ds_name == NULL) || (ds_name[0] == '\0'))
                 status = ssnprintf (ret, ret_len, "%s.%s.%s.%s",
                         prefix, n_hostname, plugin, type);
             else
@@ -362,21 +382,21 @@ static int wg_format_name (char *ret, int ret_len, /* {{{ */
         }
         else
         {
-            if ((ds_name == NULL) || (strlen (ds_name) == 0))
+            if ((ds_name == NULL) || (ds_name[0] == '\0'))
                 status = ssnprintf (ret, ret_len, "%s.%s.%s.%s-%s",
                         prefix, n_hostname, plugin, type,
-                        type_instance);
+                        n_type_instance);
             else
                 status = ssnprintf (ret, ret_len, "%s.%s.%s.%s-%s.%s",
                         prefix, n_hostname, plugin, type,
-                        type_instance, ds_name);
+                        n_type_instance, ds_name);
         }
     }
     else
     {
-        if ((type_instance == NULL) || (strlen (type_instance) == 0))
+        if ((n_type_instance == NULL) || (n_type_instance[0] == '\0'))
         {
-            if ((ds_name == NULL) || (strlen (ds_name) == 0))
+            if ((ds_name == NULL) || (ds_name[0] == '\0'))
                 status = ssnprintf (ret, ret_len, "%s.%s.%s.%s.%s",
                         prefix, n_hostname, plugin,
                         plugin_instance, type);
@@ -387,25 +407,27 @@ static int wg_format_name (char *ret, int ret_len, /* {{{ */
         }
         else
         {
-            if ((ds_name == NULL) || (strlen (ds_name) == 0))
+            if ((ds_name == NULL) || (ds_name[0] == '\0'))
                 status = ssnprintf (ret, ret_len, "%s.%s.%s.%s.%s-%s",
                         prefix, n_hostname, plugin,
-                        plugin_instance, type, type_instance);
+                        plugin_instance, type, n_type_instance);
             else
                 status = ssnprintf (ret, ret_len, "%s.%s.%s.%s.%s-%s.%s",
                         prefix, n_hostname, plugin,
-                        plugin_instance, type, type_instance, ds_name);
+                        plugin_instance, type, n_type_instance, ds_name);
         }
     }
 
     sfree(n_hostname);
+    sfree(n_type_instance);
 
     if ((status < 1) || (status >= ret_len))
         return (-1);
     return (0);
-} /* }}} int wg_format_name */
+}
 
-static int wg_send_message (const char* key, const char* value, cdtime_t time, struct wg_callback *cb) /* {{{ */
+static int wg_send_message (const char* key, const char* value,
+        cdtime_t time, struct wg_callback *cb)
 {
     int status;
     size_t message_len;
@@ -465,10 +487,10 @@ static int wg_send_message (const char* key, const char* value, cdtime_t time, s
     pthread_mutex_unlock (&cb->send_lock);
 
     return (0);
-} /* }}} int wg_send_message */
+}
 
-static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, /* {{{ */
-                        struct wg_callback *cb)
+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];
@@ -487,7 +509,7 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, /* {
         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->prefix, ds->ds[i].name);
+            status = WG_FORMAT_NAME (key, sizeof (key), vl, cb, ds->ds[i].name);
             if (status != 0)
             {
                 ERROR ("write_graphite plugin: error with format_name");
@@ -495,8 +517,8 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, /* {
             }
 
             escape_string (key, sizeof (key));
-            /* Convert the values to an ASCII representation and put that into
-             * `values'. */
+            /* 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)
             {
@@ -518,7 +540,7 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, /* {
     else
     {
         /* Copy the identifier to `key' and escape it. */
-        status = WG_FORMAT_NAME (key, sizeof (key), vl, cb->prefix, NULL);
+        status = WG_FORMAT_NAME (key, sizeof (key), vl, cb, NULL);
         if (status != 0)
         {
             ERROR ("write_graphite plugin: error with format_name");
@@ -547,9 +569,9 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl, /* {
     }
 
     return (0);
-} /* }}} int wg_write_messages */
+}
 
-static int wg_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+static int wg_write (const data_set_t *ds, const value_list_t *vl,
         user_data_t *user_data)
 {
     struct wg_callback *cb;
@@ -563,9 +585,9 @@ static int wg_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
     status = wg_write_messages (ds, vl, cb);
 
     return (status);
-} /* }}} int wg_write */
+}
 
-static int config_set_number (int *dest, /* {{{ */
+static int config_set_number (int *dest,
         oconfig_item_t *ci)
 {
     if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
@@ -578,9 +600,24 @@ static int config_set_number (int *dest, /* {{{ */
     *dest = ci->values[0].value.number;
 
     return (0);
-} /* }}} int config_set_number */
+}
 
-static int config_set_string (char **ret_string, /* {{{ */
+static int config_set_char (char *dest,
+        oconfig_item_t *ci)
+{
+    if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+    {
+        WARNING ("write_graphite plugin: The `%s' config option "
+                "needs exactly one string argument.", ci->key);
+        return (-1);
+    }
+
+    *dest = ci->values[0].value.string[0];
+
+    return (0);
+}
+
+static int config_set_string (char **ret_string,
         oconfig_item_t *ci)
 {
     char *string;
@@ -605,9 +642,9 @@ static int config_set_string (char **ret_string, /* {{{ */
     *ret_string = string;
 
     return (0);
-} /* }}} int config_set_string */
+}
 
-static int wg_config_carbon (oconfig_item_t *ci) /* {{{ */
+static int wg_config_carbon (oconfig_item_t *ci)
 {
     struct wg_callback *cb;
     user_data_t user_data;
@@ -622,17 +659,13 @@ static int wg_config_carbon (oconfig_item_t *ci) /* {{{ */
     memset (cb, 0, sizeof (*cb));
     cb->sock_fd = -1;
     cb->host = NULL;
-    cb->name = NULL;
     cb->port = 2003;
     cb->prefix = NULL;
     cb->server = NULL;
+    cb->dotchar = '_';
 
     pthread_mutex_init (&cb->send_lock, /* attr = */ NULL);
 
-    config_set_string (&cb->name, ci);
-    if (cb->name == NULL)
-        return (-1);
-
     for (i = 0; i < ci->children_num; i++)
     {
         oconfig_item_t *child = ci->children + i;
@@ -643,6 +676,8 @@ static int wg_config_carbon (oconfig_item_t *ci) /* {{{ */
             config_set_number (&cb->port, child);
         else if (strcasecmp ("Prefix", child->key) == 0)
             config_set_string (&cb->prefix, child);
+        else if (strcasecmp ("DotCharacter", child->key) == 0)
+            config_set_char (&cb->dotchar, child);
         else
         {
             ERROR ("write_graphite plugin: Invalid configuration "
@@ -662,9 +697,9 @@ static int wg_config_carbon (oconfig_item_t *ci) /* {{{ */
     plugin_register_write ("write_graphite", wg_write, &user_data);
 
     return (0);
-} /* }}} int wg_config_carbon */
+}
 
-static int wg_config (oconfig_item_t *ci) /* {{{ */
+static int wg_config (oconfig_item_t *ci)
 {
     int i;
 
@@ -677,16 +712,16 @@ static int wg_config (oconfig_item_t *ci) /* {{{ */
         else
         {
             ERROR ("write_graphite plugin: Invalid configuration "
-                        "option: %s.", child->key);
+                    "option: %s.", child->key);
         }
     }
 
     return (0);
-} /* }}} int wg_config */
+}
 
-void module_register (void) /* {{{ */
+void module_register (void)
 {
     plugin_register_complex_config ("write_graphite", wg_config);
-} /* }}} void module_register */
+}
 
-/* vim: set fdm=marker sw=4 ts=4 sts=4 tw=78 et : */
+/* vim: set sw=4 ts=4 sts=4 tw=78 et : */