]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
format_graphite: Basically a rewrite for metric_t.
authorFlorian Forster <octo@collectd.org>
Sun, 21 Jun 2020 14:46:02 +0000 (16:46 +0200)
committerFlorian Forster <octo@google.com>
Wed, 29 Jul 2020 11:40:03 +0000 (13:40 +0200)
Makefile.am
src/utils/format_graphite/format_graphite.c
src/utils/format_graphite/format_graphite.h
src/utils/format_graphite/format_graphite_test.c

index d468b19c36559e15820b2d783fd748335b2c67a7..c5576f77693b54802aa2dec4cc733e5debeaab7a 100644 (file)
@@ -134,6 +134,7 @@ noinst_LTLIBRARIES = \
        libformat_graphite.la \
        libformat_json.la \
        libheap.la \
+       libidentity.la \
        libignorelist.la \
        liblatency.la \
        libllist.la \
@@ -270,6 +271,7 @@ collectd_LDADD = \
        libavltree.la \
        libcommon.la \
        libheap.la \
+       libidentity.la \
        libllist.la \
        libmetric.la \
        liboconfig.la \
@@ -442,6 +444,11 @@ libheap_la_SOURCES = \
        src/utils/heap/heap.c \
        src/utils/heap/heap.h
 
+libidentity_la_SOURCES = \
+                        src/daemon/identity.c \
+                        src/daemon/identity.h
+libidentity_la_LIBADD = libavltree.la $(COMMON_LIBS)
+
 libignorelist_la_SOURCES = \
        src/utils/ignorelist/ignorelist.c \
        src/utils/ignorelist/ignorelist.h
@@ -473,12 +480,14 @@ libplugin_mock_la_LIBADD = libcommon.la libignorelist.la $(COMMON_LIBS)
 libformat_graphite_la_SOURCES = \
        src/utils/format_graphite/format_graphite.c \
        src/utils/format_graphite/format_graphite.h
+libformat_graphite_la_LIBADD = libstrbuf.la $(COMMON_LIBS)
 
 test_format_graphite_SOURCES = \
        src/utils/format_graphite/format_graphite_test.c \
        src/testing.h
 test_format_graphite_LDADD = \
        libformat_graphite.la \
+       libidentity.la \
        libmetadata.la \
        libplugin_mock.la \
        -lm
index 6e671c49e638019bb7b0d7a5813818fb1f5e8cfc..2eedf0ddf87fa01913e6a1b5e3c3b4d60cd8b3eb 100644 (file)
@@ -25,9 +25,8 @@
 #include "collectd.h"
 
 #include "plugin.h"
-#include "utils/common/common.h"
 #include "utils/avltree/avltree.h"
-
+#include "utils/common/common.h"
 #include "utils/format_graphite/format_graphite.h"
 #include "utils_cache.h"
 
 /* Utils functions to format data sets in graphite format.
  * Largely taken from write_graphite.c as it remains the same formatting */
 
-static int gr_format_values(char *ret, size_t ret_len, const metric_t *metric_p,
-                            gauge_t rate) {
-  size_t offset = 0;
-  int status;
-
-  memset(ret, 0, ret_len);
-
-#define BUFFER_ADD(...)                                                        \
-  do {                                                                         \
-    status = snprintf(ret + offset, ret_len - offset, __VA_ARGS__);            \
-    if (status < 1) {                                                          \
-      return -1;                                                               \
-    } else if (((size_t)status) >= (ret_len - offset)) {                       \
-      return -1;                                                               \
-    } else                                                                     \
-      offset += ((size_t)status);                                              \
-  } while (0)
-
-  if (metric_p->value_type == DS_TYPE_GAUGE)
-    BUFFER_ADD(GAUGE_FORMAT, metric_p->value.gauge);
+static int gr_format_values(strbuf_t *buf, const metric_t *m, gauge_t rate) {
+  if (m->value_type == DS_TYPE_GAUGE)
+    return strbuf_printf(buf, GAUGE_FORMAT, m->value.gauge);
   else if (rate != -1)
-    BUFFER_ADD("%f", rate);
-  else if (metric_p->value_type == DS_TYPE_COUNTER)
-    BUFFER_ADD("%" PRIu64, (uint64_t)metric_p->value.counter);
-  else if (metric_p->value_type == DS_TYPE_DERIVE)
-    BUFFER_ADD("%" PRIi64, metric_p->value.derive);
-  else {
-    P_ERROR("gr_format_values: Unknown data source type: %i",
-            metric_p->value_type);
-    return -1;
-  }
-
-#undef BUFFER_ADD
-
-  return 0;
+    return strbuf_printf(buf, "%f", rate);
+  else if (m->value_type == DS_TYPE_COUNTER)
+    return strbuf_printf(buf, "%" PRIu64, (uint64_t)m->value.counter);
+  else if (m->value_type == DS_TYPE_DERIVE)
+    return strbuf_printf(buf, "%" PRIi64, m->value.derive);
+
+  P_ERROR("gr_format_values: Unknown data source type: %d", m->value_type);
+  return EINVAL;
 }
 
-static void gr_copy_escape_part(char *dst, const char *src, size_t dst_len,
-                                char escape_char, bool preserve_separator) {
-  if (src == NULL)
-    return;
-
-  for (size_t i = 0; i < dst_len; i++) {
-    if (src[i] == 0) {
-      dst[i] = 0;
-      break;
-    }
-
-    if ((!preserve_separator && (src[i] == '.')) || ((src[i] == '/')) ||
-        isspace((int)src[i]) || iscntrl((int)src[i]))
-      dst[i] = escape_char;
-    else
-      dst[i] = src[i];
+static int graphite_print_escaped(strbuf_t *buf, char const *s,
+                                  char escape_char) {
+  if ((buf == NULL) || (s == NULL)) {
+    return EINVAL;
   }
-}
 
-static int gr_format_name_tagged(char *ret, int ret_len,
-                                 metric_t const *metric_p, char const *prefix,
-                                 char const *postfix, char const escape_char,
-                                 unsigned int flags) {
-  int starting_len = ret_len;
-  if (prefix == NULL)
-    prefix = "";
-
-  if (postfix == NULL)
-    postfix = "";
-
-  memset(ret, 0, ret_len);
-
-  int tmp_str_len = 0;
-  tmp_str_len = strlen(prefix);
-  if (tmp_str_len < ret_len) {
-    snprintf(ret, tmp_str_len + 1, "%s", prefix);
-    ret += tmp_str_len; /* This is the location of the trailing nul */
-    ret_len -= tmp_str_len;
-  } else {
-    snprintf(ret, ret_len, "%s", prefix);
-    return starting_len;
-  }
-
-  tmp_str_len = strlen(metric_p->identity->name);
-  if (tmp_str_len < ret_len) {
-    gr_copy_escape_part(ret, metric_p->identity->name, tmp_str_len + 1,
-                        escape_char, 1);
-    ret += tmp_str_len;
-    ret_len -= tmp_str_len;
-  } else {
-    gr_copy_escape_part(ret, metric_p->identity->name, ret_len, escape_char, 1);
-    return starting_len;
-  }
+  size_t s_len = strlen(s);
+  while (s_len > 0) {
+    size_t valid_len = strcspn(s, GRAPHITE_FORBIDDEN);
+    if (valid_len == s_len) {
+      return strbuf_print(buf, s);
+    }
+    if (valid_len != 0) {
+      char tmp[valid_len + 1];
+      strncpy(tmp, s, valid_len);
+      tmp[valid_len] = 0;
+      int status = strbuf_print(buf, tmp);
+      if (status != 0) {
+        return status;
+      }
 
-  tmp_str_len = strlen(postfix);
-  if (tmp_str_len < ret_len) {
-    snprintf(ret, tmp_str_len + 1, "%s", postfix);
-    ret += tmp_str_len; /* This is the location of the trailing nul */
-    ret_len -= tmp_str_len;
-  } else {
-    snprintf(ret, ret_len, "%s", postfix);
-    return starting_len;
-  }
+      s += valid_len;
+      s_len -= valid_len;
+      continue;
+    }
 
-  if (metric_p->identity->root_p != NULL) {
-    c_avl_iterator_t *iter_p = c_avl_get_iterator(metric_p->identity->root_p);
-    if (iter_p != NULL) {
-      char *key_p = NULL;
-      char *value_p = NULL;
-      while ((c_avl_iterator_next(iter_p, (void **)&key_p,
-                                  (void **)&value_p)) == 0) {
-        if ((key_p != NULL) && (value_p != NULL)) {
-          tmp_str_len = strlen(key_p) + strlen(value_p) + 2;
-          if (tmp_str_len < ret_len) {
-            snprintf(ret, tmp_str_len + 1, ";%s=%s", key_p, value_p);
-            ret += tmp_str_len;
-            ret_len -= tmp_str_len;
-          } else {
-            snprintf(ret, ret_len, ";%s=%s", key_p, value_p);
-            return starting_len;
-          }
-        }
-      }
-      c_avl_iterator_destroy(iter_p);
+    char tmp[2] = {escape_char, 0};
+    int status = strbuf_print(buf, tmp);
+    if (status != 0) {
+      return status;
     }
+
+    s++;
+    s_len--;
   }
 
-  return starting_len - ret_len; /* Characters appended */
+  return 0;
 }
 
-static int gr_format_name(char *ret, int ret_len, metric_t const *metric_p,
-                          char const *prefix, char const *postfix,
-                          char const escape_char, unsigned int flags) {
-  int starting_len = ret_len;
-  if (prefix == NULL)
-    prefix = "";
-
-  if (postfix == NULL)
-    postfix = "";
-
-  memset(ret, 0, ret_len);
-
-  int tmp_str_len = 0;
-  tmp_str_len = strlen(prefix);
-  if (tmp_str_len < ret_len) {
-    snprintf(ret, tmp_str_len + 1, "%s", prefix);
-    ret += tmp_str_len; /* This is the location of the trailing nul */
-    ret_len -= tmp_str_len;
-  } else {
-    snprintf(ret, ret_len, "%s", prefix);
-    return starting_len;
+static int gr_format_name(strbuf_t *buf, metric_t const *m, char const *prefix,
+                          char const *suffix, char const escape_char,
+                          unsigned int flags) {
+  if (prefix != NULL) {
+    strbuf_print(buf, prefix);
   }
-
-  tmp_str_len = strlen(metric_p->identity->name);
-  if (tmp_str_len < ret_len) {
-    gr_copy_escape_part(ret, metric_p->identity->name, tmp_str_len + 1,
-                        escape_char, 1);
-    ret += tmp_str_len;
-    ret_len -= tmp_str_len;
-  } else {
-    gr_copy_escape_part(ret, metric_p->identity->name, ret_len, escape_char, 1);
-    return starting_len;
+  graphite_print_escaped(buf, m->identity->name, escape_char);
+  if (suffix != NULL) {
+    strbuf_print(buf, suffix);
   }
 
-  tmp_str_len = strlen(postfix);
-  if (tmp_str_len < ret_len) {
-    snprintf(ret, tmp_str_len + 1, "%s", postfix);
-    ret += tmp_str_len; /* This is the location of the trailing nul */
-    ret_len -= tmp_str_len;
-  } else {
-    snprintf(ret, ret_len, "%s", postfix);
-    return starting_len;
+  c_avl_iterator_t *iter = c_avl_get_iterator(m->identity->labels);
+  char *k = NULL, *v = NULL;
+  while ((c_avl_iterator_next(iter, (void **)&k, (void **)&v)) == 0) {
+    strbuf_print(buf, ".");
+    graphite_print_escaped(buf, k, escape_char);
+    strbuf_print(buf, (flags & GRAPHITE_SEPARATE_INSTANCES) ? "." : "=");
+    graphite_print_escaped(buf, v, escape_char);
   }
+  c_avl_iterator_destroy(iter);
 
-  if (metric_p->identity->root_p != NULL) {
-    c_avl_iterator_t *iter_p = c_avl_get_iterator(metric_p->identity->root_p);
-    if (iter_p != NULL) {
-      char *key_p = NULL;
-      char *value_p = NULL;
-      while ((c_avl_iterator_next(iter_p, (void **)&key_p,
-                                  (void **)&value_p)) == 0) {
-        if ((key_p != NULL) && (value_p != NULL)) {
-          tmp_str_len = strlen(value_p) + 1;
-          if (tmp_str_len < ret_len) {
-            snprintf(ret, tmp_str_len + 1, ";%s", value_p);
-            ret += tmp_str_len;
-            ret_len -= tmp_str_len;
-          } else {
-            snprintf(ret, ret_len, ";%s", value_p);
-            return starting_len;
-          }
-        }
-      }
-      c_avl_iterator_destroy(iter_p);
-    }
-  }
-
-  return starting_len - ret_len; /* Characters appended */
-}
-
-static void escape_graphite_string(char *buffer, char escape_char) {
-  assert(strchr(GRAPHITE_FORBIDDEN, escape_char) == NULL);
-
-  for (char *head = buffer + strcspn(buffer, GRAPHITE_FORBIDDEN); *head != '\0';
-       head += strcspn(head, GRAPHITE_FORBIDDEN))
-    *head = escape_char;
+  return 0;
 }
 
-int format_graphite(char *buffer, size_t buffer_size, metric_t const *metric_p,
-                    char const *prefix, char const *postfix,
-                    char const escape_char, unsigned int flags) {
-  int status = 0;
-  int buffer_pos = 0;
-
+int format_graphite(strbuf_t *buf, metric_t const *m, char const *prefix,
+                    char const *postfix, char const escape_char,
+                    unsigned int flags) {
   gauge_t rate = -1;
   if (flags & GRAPHITE_STORE_RATES) {
-    status = uc_get_rate(metric_p, &rate);
+    int status = uc_get_rate(m, &rate);
     if (status != 0) {
       P_ERROR("format_graphite: error with uc_get_rate");
       return -1;
     }
   }
 
-  char key[10 * DATA_MAX_NAME_LEN];
-  char values[512];
-  size_t message_len;
-  char message[1024];
+  /* format:
+   * <name> <value> <time> '\r' '\n'
+   */
 
-  /* Copy the identifier to `key' and escape it. */
-  if (flags & GRAPHITE_USE_TAGS) {
-    status = gr_format_name_tagged(key, sizeof(key), metric_p, prefix, postfix,
-                                   escape_char, flags);
-    if (status != 0) {
-      P_ERROR("format_graphite: error with gr_format_name_tagged");
-      return status;
-    }
-  } else {
-    status = gr_format_name(key, sizeof(key), metric_p, prefix, postfix,
-                            escape_char, flags);
-    if (status != 0) {
-      P_ERROR("format_graphite: error with gr_format_name");
-      return status;
-    }
-  }
+  gr_format_name(buf, m, prefix, postfix, escape_char, flags);
 
-  escape_graphite_string(key, escape_char);
+  strbuf_print(buf, " ");
 
   /* Convert the values to an ASCII representation and put that into
    * `values'. */
-  status = gr_format_values(values, sizeof(values), metric_p, rate);
+  int status = gr_format_values(buf, m, rate);
   if (status != 0) {
     P_ERROR("format_graphite: error with gr_format_values");
     return status;
   }
 
-  /* Compute the graphite command */
-  message_len =
-      (size_t)snprintf(message, sizeof(message), "%s %s %u\r\n", key, values,
-                       (unsigned int)CDTIME_T_TO_TIME_T(metric_p->time));
-  if (message_len >= sizeof(message)) {
-    P_ERROR("format_graphite: message buffer too small: "
-            "Need %" PRIsz " bytes.",
-            message_len + 1);
-    return -ENOMEM;
-  }
-
-  /* Append it in case we got multiple data set */
-  if ((buffer_pos + message_len) >= buffer_size) {
-    P_ERROR("format_graphite: target buffer too small");
-    return -ENOMEM;
-  }
-  memcpy((void *)(buffer + buffer_pos), message, message_len);
-  buffer_pos += message_len;
-  buffer[buffer_pos] = '\0';
-
-  return status;
+  return strbuf_printf(buf, " %lu\r\n",
+                       (unsigned long)CDTIME_T_TO_TIME_T(m->time));
 } /* int format_graphite */
index 0a8b253d7d27b8b7706d130e046d7d5f2f16b117..3f85fbc377d590f992d6e990b8ea8c15c0aefdc1 100644 (file)
@@ -25,6 +25,7 @@
 #include "collectd.h"
 
 #include "plugin.h"
+#include "utils/strbuf/strbuf.h"
 
 #define GRAPHITE_STORE_RATES 0x01
 #define GRAPHITE_SEPARATE_INSTANCES 0x02
@@ -34,8 +35,8 @@
 #define GRAPHITE_USE_TAGS 0x20
 #define GRAPHITE_REVERSE_HOST 0x40
 
-int format_graphite(char *buffer, size_t buffer_size, const metric_t *metric_p,
-                    const char *prefix, const char *postfix,
-                    const char escape_char, unsigned int flags);
+int format_graphite(strbuf_t *buf, const metric_t *metric_p, const char *prefix,
+                    const char *postfix, const char escape_char,
+                    unsigned int flags);
 
 #endif /* UTILS_FORMAT_GRAPHITE_H */
index 5e4439bc327f37de2f1bd89a4d383bbac92a7890..a5f57368738c448b6503486ea316ae2bfc5d9573 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_format_graphite_test.c
- * Copyright (C) 2016       Florian octo Forster
+ * Copyright (C) 2016-2020  Florian octo Forster
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 #include "utils/common/common.h" /* for STATIC_ARRAY_SIZE */
 #include "utils/format_graphite/format_graphite.h"
 
-static data_set_t ds_single = {
-    .type = "single",
-    .ds_num = 1,
-    .ds = &(data_source_t){"value", DS_TYPE_GAUGE, NAN, NAN},
-};
-
-/*
-static data_set_t ds_double = {
-    .type = "double",
-    .ds_num = 2,
-    .ds =
-        (data_source_t[]){
-            {"one", DS_TYPE_DERIVE, 0, NAN}, {"two", DS_TYPE_DERIVE, 0, NAN},
-        },
-};
-*/
-
 DEF_TEST(metric_name) {
   struct {
-    const char *plugin_instance;
-    const char *type_instance;
-    const char *prefix;
-    const char *suffix;
+    char const *name;
+    size_t labels_num;
+    char const **keys;
+    char const **values;
+    value_t value;
+    int value_type;
     unsigned int flags;
-    const char *want_name;
+    const char *want;
   } cases[] = {
       {
-          .want_name = "example@com.test.single",
-      },
-      /* plugin and type instances */
-      {
-          .plugin_instance = "foo",
-          .type_instance = "bar",
-          .want_name = "example@com.test-foo.single-bar",
-      },
-      {
-          .plugin_instance = NULL,
-          .type_instance = "bar",
-          .want_name = "example@com.test.single-bar",
-      },
-      {
-          .plugin_instance = "foo",
-          .type_instance = NULL,
-          .want_name = "example@com.test-foo.single",
+          .name = "unit_test",
+          .value = (value_t){.gauge = 42},
+          .value_type = DS_TYPE_GAUGE,
+          .want = "unit_test 42",
       },
-      /* special chars */
       {
-          .plugin_instance = "foo (test)",
-          .type_instance = "test: \"hello\"",
-          .want_name = "example@com.test-foo@@test@.single-test@@@hello@",
+          .name = "test_with_label",
+          .labels_num = 2,
+          .keys = (char const *[]){"beta", "alpha"},
+          .values = (char const *[]){"second", "first"},
+          .value = (value_t){.derive = -9223372036854775807LL},
+          .value_type = DS_TYPE_DERIVE,
+          .want =
+              "test_with_label.alpha=first.beta=second -9223372036854775807",
       },
-      /* test escaping comma */
       {
-          .plugin_instance = "foo (test)",
-          .type_instance = "test,123,",
-          .want_name = "example@com.test-foo@@test@.single-test@123@",
-      },
-      /* flag GRAPHITE_SEPARATE_INSTANCES */
-      {
-          .plugin_instance = "foo",
-          .type_instance = "bar",
+          .name = "separate_instances_test",
+          .labels_num = 2,
+          .keys = (char const *[]){"beta", "alpha"},
+          .values = (char const *[]){"second", "first"},
+          .value = (value_t){.derive = 9223372036854775807LL},
+          .value_type = DS_TYPE_DERIVE,
           .flags = GRAPHITE_SEPARATE_INSTANCES,
-          .want_name = "example@com.test.foo.single.bar",
-      },
-      /* flag GRAPHITE_ALWAYS_APPEND_DS */
-      {
-          .plugin_instance = "foo",
-          .type_instance = "bar",
-          .flags = GRAPHITE_ALWAYS_APPEND_DS,
-          .want_name = "example@com.test-foo.single-bar.value",
+          .want = "separate_instances_test.alpha.first.beta.second "
+                  "9223372036854775807",
       },
-      /* flag GRAPHITE_PRESERVE_SEPARATOR */
       {
-          .plugin_instance = "f.o.o",
-          .type_instance = "b.a.r",
-          .flags = 0,
-          .want_name = "example@com.test-f@o@o.single-b@a@r",
+          .name = "escaped:metric_name",
+          .value = (value_t){.gauge = NAN},
+          .value_type = DS_TYPE_GAUGE,
+          .want = "escaped_metric_name nan",
       },
       {
-          .plugin_instance = "f.o.o",
-          .type_instance = "b.a.r",
-          .flags = GRAPHITE_PRESERVE_SEPARATOR,
-          .want_name = "example.com.test-f.o.o.single-b.a.r",
+          .name = "escaped_label_value",
+          .labels_num = 2,
+          .keys = (char const *[]){"beta", "alpha"},
+          .values = (char const *[]){"second value", "first/value"},
+          .value = (value_t){.counter = 18446744073709551615LLU},
+          .value_type = DS_TYPE_COUNTER,
+          .want = "escaped_label_value.alpha=first_value.beta=second_value "
+                  "18446744073709551615",
       },
-      /* prefix and suffix */
-      {
-          .prefix = "foo.",
-          .suffix = ".bar",
-          .want_name = "foo.example@com.bar.test.single",
-      },
-      {
-          .prefix = NULL,
-          .suffix = ".bar",
-          .want_name = "example@com.bar.test.single",
-      },
-      {
-          .prefix = "foo.",
-          .suffix = NULL,
-          .want_name = "foo.example@com.test.single",
-      },
-      /* flag GRAPHITE_USE_TAGS */
-      {.flags = GRAPHITE_USE_TAGS,
-       .want_name = "test.single;host=example.com;plugin=test;type=single"},
-      {.plugin_instance = "f.o.o",
-       .type_instance = "b.a.r",
-       .flags = GRAPHITE_USE_TAGS,
-       .want_name = "test.single;host=example.com;plugin=test;plugin_instance="
-                    "f.o.o;type=single;type_instance=b.a.r"},
-      {.flags = GRAPHITE_USE_TAGS ^ GRAPHITE_ALWAYS_APPEND_DS,
-       .want_name = "test.single.value;host=example.com;plugin=test;type="
-                    "single;ds_name=value"},
-      {.plugin_instance = "foo",
-       .type_instance = "foo",
-       .flags = GRAPHITE_USE_TAGS ^ GRAPHITE_DROP_DUPE_FIELDS,
-       .want_name = "test.single;host=example.com;plugin=test;plugin_instance="
-                    "foo;type=single"},
   };
 
   for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
-    value_list_t vl = {
-        .values = &(value_t){.gauge = 42},
-        .values_len = 1,
-        .time = TIME_T_TO_CDTIME_T_STATIC(1480063672),
-        .interval = TIME_T_TO_CDTIME_T_STATIC(10),
-        .host = "example.com",
-        .plugin = "test",
-        .type = "single",
+    identity_t *id;
+    CHECK_NOT_NULL(id = identity_create(cases[i].name));
+    for (size_t j = 0; j < cases[i].labels_num; j++) {
+      CHECK_ZERO(identity_add_label(id, cases[i].keys[j], cases[i].values[j]));
+    }
+
+    metric_t m = {
+        .identity = id,
+        .value = cases[i].value,
+        .value_type = cases[i].value_type,
+        .time = 1710200311404036096, /* 1592748157.125 */
     };
 
+    strbuf_t buf = STRBUF_CREATE;
+    EXPECT_EQ_INT(0, format_graphite(&buf, &m, "", "", '_', cases[i].flags));
+
     strbuf_t want = STRBUF_CREATE;
-    if (cases[i].want_name != NULL) {
-      strbuf_print(&want, cases[i].want_name);
-      strbuf_print(&want, " 42 1480063672\r\n");
+    if (cases[i].want != NULL) {
+      strbuf_print(&want, cases[i].want);
+      strbuf_print(&want, " 1480063672\r\n");
     }
+    EXPECT_EQ_STR(want.ptr, buf.ptr);
 
-    if (cases[i].plugin_instance != NULL)
-      sstrncpy(vl.plugin_instance, cases[i].plugin_instance,
-               sizeof(vl.plugin_instance));
-    if (cases[i].type_instance != NULL)
-      sstrncpy(vl.type_instance, cases[i].type_instance,
-               sizeof(vl.type_instance));
-
-    char got[1024];
-    EXPECT_EQ_INT(0, format_graphite(got, sizeof(got), &ds_single, &vl,
-                                     cases[i].prefix, cases[i].suffix, '@',
-                                     cases[i].flags));
-    EXPECT_EQ_STR(want.ptr, got);
     STRBUF_DESTROY(want);
+    STRBUF_DESTROY(buf);
+    identity_destroy(id);
   }
 
   return 0;
 }
 
-DEF_TEST(null_termination) {
-  value_list_t vl = {
-      .values = &(value_t){.gauge = 1337},
-      .values_len = 1,
-      .time = TIME_T_TO_CDTIME_T_STATIC(1480063672),
-      .interval = TIME_T_TO_CDTIME_T_STATIC(10),
-      .host = "example.com",
-      .plugin = "test",
-      .type = "single",
-  };
-  char const *want = "example_com.test.single 1337 1480063672\r\n";
-
-  char buffer[128];
-  for (size_t i = 0; i < sizeof(buffer); i++)
-    buffer[i] = (char)i;
-
-  EXPECT_EQ_INT(0, format_graphite(buffer, sizeof(buffer), &ds_single, &vl,
-                                   NULL, NULL, '_', 0));
-  EXPECT_EQ_STR(want, buffer);
-  EXPECT_EQ_INT(0, buffer[strlen(want)]);
-  for (size_t i = strlen(want) + 1; i < sizeof(buffer); i++)
-    EXPECT_EQ_INT((int)i, (int)buffer[i]);
-
-  return 0;
-}
-
 int main(void) {
   RUN_TEST(metric_name);
-  RUN_TEST(null_termination);
 
   END_TEST;
 }