write_graphite plugin: Add option to reverse host
authorusev6 <use_v6@aglaz.de>
Fri, 23 Nov 2018 23:35:39 +0000 (00:35 +0100)
committerusev6 <use_v6@aglaz.de>
Fri, 23 Nov 2018 23:35:39 +0000 (00:35 +0100)
src/collectd.conf.in
src/collectd.conf.pod
src/utils_format_graphite.c
src/utils_format_graphite.h
src/write_graphite.c

index b7c1b27..8bae3b6 100644 (file)
 #    SeparateInstances false
 #    PreserveSeparator false
 #    DropDuplicateFields false
+#    ReverseHost false
 #  </Node>
 #</Plugin>
 
index 03b163e..5098fbe 100644 (file)
@@ -9445,6 +9445,7 @@ Synopsis:
      LogSendErrors true
      Prefix "collectd"
      UseTags false
+     ReverseHost false
    </Node>
  </Plugin>
 
@@ -9556,6 +9557,30 @@ are not used.
 
 Default value: B<false>.
 
+=item B<ReverseHost> B<false>|B<true>
+
+If set to B<true>, the (dot separated) parts of the B<host> field of the
+I<value list> will be rewritten in reverse order. The rewrite happens I<before>
+special characters are replaced with the B<EscapeCharacter>.
+
+This option might be convenient if the metrics are presented with Graphite in a
+DNS like tree structure (probably without replacing dots in hostnames).
+
+Example:
+ Hostname "node3.cluster1.example.com"
+ LoadPlugin "cpu"
+ LoadPlugin "write_graphite"
+ <Plugin "write_graphite">
+  <Node "graphite.example.com">
+   EscapeCharacter "."
+   ReverseHost true
+  </Node>
+ </Plugin>
+
+ result on the wire: com.example.cluster1.node3.cpu-0.cpu-idle 99.900993 1543010932
+
+Default value: B<false>.
+
 =back
 
 =head2 Plugin C<write_log>
index de3f0c2..41337d2 100644 (file)
 /* Utils functions to format data sets in graphite format.
  * Largely taken from write_graphite.c as it remains the same formatting */
 
+/* helper function for reverse_hostname */
+void reverse_string(char *r_host, int len) {
+  char t;
+  for (int i = 0; i < len / 2; i++) {
+    int j = len - i - 1;
+    t = r_host[i];
+    r_host[i] = r_host[j];
+    r_host[j] = t;
+  }
+}
+
+void reverse_hostname(char *r_host, char const *orig_host) {
+  int len_host = strlen(orig_host);
+
+  /* put reversed hostname into working copy */
+  for (int i = 0; i < len_host; i++)
+    r_host[i] = orig_host[len_host - 1 - i];
+  r_host[len_host] = '\0';
+
+  /* reverse labels (except last) */
+  int p = 0;
+  for (int i = 0; i < len_host; i++)
+    if (r_host[i] == '.') {
+      reverse_string(&r_host[p], i - p);
+      p = i + 1;
+    }
+
+  /* reverse last label */
+  reverse_string(&r_host[p], len_host - p);
+}
+
 static int gr_format_values(char *ret, size_t ret_len, int ds_num,
                             const data_set_t *ds, const value_list_t *vl,
                             gauge_t const *rates) {
@@ -120,7 +151,14 @@ static int gr_format_name_tagged(char *ret, int ret_len, value_list_t const *vl,
   if (postfix == NULL)
     postfix = "";
 
-  gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char, 1);
+  if (flags & GRAPHITE_REVERSE_HOST) {
+    int len_host = strlen(vl->host);
+    char r_host[len_host + 1];
+    reverse_hostname(r_host, vl->host);
+    gr_copy_escape_part(n_host, r_host, sizeof(n_host), escape_char, 1);
+  } else {
+    gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char, 1);
+  }
   gr_copy_escape_part(n_plugin, vl->plugin, sizeof(n_plugin), escape_char, 1);
   gr_copy_escape_part(n_plugin_instance, vl->plugin_instance,
                       sizeof(n_plugin_instance), escape_char, 1);
@@ -198,8 +236,16 @@ static int gr_format_name(char *ret, int ret_len, value_list_t const *vl,
 
   bool preserve_separator = (flags & GRAPHITE_PRESERVE_SEPARATOR);
 
-  gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char,
-                      preserve_separator);
+  if (flags & GRAPHITE_REVERSE_HOST) {
+    int len_host = strlen(vl->host);
+    char r_host[len_host + 1];
+    reverse_hostname(r_host, vl->host);
+    gr_copy_escape_part(n_host, r_host, sizeof(n_host), escape_char,
+                        preserve_separator);
+  } else {
+    gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char,
+                        preserve_separator);
+  }
   gr_copy_escape_part(n_plugin, vl->plugin, sizeof(n_plugin), escape_char,
                       preserve_separator);
   gr_copy_escape_part(n_plugin_instance, vl->plugin_instance,
index 60b89ae..4df7db3 100644 (file)
@@ -32,6 +32,7 @@
 #define GRAPHITE_DROP_DUPE_FIELDS 0x08
 #define GRAPHITE_PRESERVE_SEPARATOR 0x10
 #define GRAPHITE_USE_TAGS 0x20
+#define GRAPHITE_REVERSE_HOST 0x40
 
 int format_graphite(char *buffer, size_t buffer_size, const data_set_t *ds,
                     const value_list_t *vl, const char *prefix,
index 7624e24..3d0a854 100644 (file)
@@ -29,7 +29,7 @@
  * Based on the write_http plugin.
  **/
 
-/* write_graphite plugin configuation example
+/* write_graphite plugin configuration example
  *
  * <Plugin write_graphite>
  *   <Carbon>
@@ -39,6 +39,7 @@
  *     LogSendErrors true
  *     Prefix "collectd"
  *     UseTags true
+ *     ReverseHost false
  *   </Carbon>
  * </Plugin>
  */
@@ -521,6 +522,8 @@ static int wg_config_node(oconfig_item_t *ci) {
       cf_util_get_flag(child, &cb->format_flags, GRAPHITE_DROP_DUPE_FIELDS);
     else if (strcasecmp("UseTags", child->key) == 0)
       cf_util_get_flag(child, &cb->format_flags, GRAPHITE_USE_TAGS);
+    else if (strcasecmp("ReverseHost", child->key) == 0)
+      cf_util_get_flag(child, &cb->format_flags, GRAPHITE_REVERSE_HOST);
     else if (strcasecmp("EscapeCharacter", child->key) == 0)
       config_set_char(&cb->escape_char, child);
     else {