]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
write_prometheus plugin: Use the `unit` field to create metric names.
authorFlorian Forster <octo@collectd.org>
Fri, 29 Dec 2023 15:58:37 +0000 (16:58 +0100)
committerFlorian Forster <octo@collectd.org>
Fri, 29 Dec 2023 15:58:37 +0000 (16:58 +0100)
Reference:
https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#metric-metadata-1

src/write_prometheus.c
src/write_prometheus_test.c

index d4c4f812e516102926fa516db3d0765a120cdba7..631f1b47c04c7cec354e3fc3f2665b95a02cf94c 100644 (file)
@@ -76,6 +76,70 @@ static struct MHD_Daemon *httpd;
 
 static cdtime_t staleness_delta = PROMETHEUS_DEFAULT_STALENESS_DELTA;
 
+typedef struct {
+  char const *open_telemetry;
+  char const *prometheus;
+} unit_map_t;
+
+/* The list is sorted at runtime (in `unit_map_lookup`) to avoid issues with
+ * different locales sorting the list in a different order. */
+static unit_map_t unit_map[] = {
+    // Time
+    {"d", "days"},
+    {"h", "hours"},
+    {"min", "minutes"},
+    {"s", "seconds"},
+    {"ms", "milliseconds"},
+    {"us", "microseconds"},
+    {"ns", "nanoseconds"},
+    // Bytes
+    {"By", "bytes"},
+    {"KiBy", "kibibytes"},
+    {"MiBy", "mebibytes"},
+    {"GiBy", "gibibytes"},
+    {"TiBy", "tibibytes"},
+    {"KBy", "kilobytes"},
+    {"MBy", "megabytes"},
+    {"GBy", "gigabytes"},
+    {"TBy", "terabytes"},
+    // SI units
+    {"m", "meters"},
+    {"V", "volts"},
+    {"A", "amperes"},
+    {"J", "joules"},
+    {"W", "watts"},
+    {"g", "grams"},
+    // Misc
+    {"1", "ratio"},
+    {"%", "percent"},
+    {"Cel", "celsius"},
+    {"Hz", "hertz"},
+};
+
+static int unit_map_compare(void const *a, void const *b) {
+  unit_map_t const *ma = a;
+  unit_map_t const *mb = b;
+
+  return strcmp(ma->open_telemetry, mb->open_telemetry);
+}
+
+static unit_map_t const *unit_map_lookup(char const *unit) {
+  static bool is_sorted;
+  if (!is_sorted) {
+    qsort(unit_map, STATIC_ARRAY_SIZE(unit_map), sizeof(unit_map[0]), unit_map_compare);
+    is_sorted = true;
+  }
+
+  if (unit == NULL) {
+    return NULL;
+  }
+
+  unit_map_t key = {
+    .open_telemetry = unit,
+  };
+  return bsearch(&key, unit_map, STATIC_ARRAY_SIZE(unit_map), sizeof(unit_map[0]), unit_map_compare);
+}
+
 /* Visible for testing */
 int format_label_name(strbuf_t *buf, char const *name) {
   int status = 0;
@@ -193,6 +257,13 @@ void format_metric_family_name(strbuf_t *buf, metric_family_t const *fam) {
 
   strbuf_print(buf, name);
 
+  unit_map_t const *unit = unit_map_lookup(fam->unit);
+  if (unit != NULL) {
+    strbuf_printf(buf, "_%s", unit->prometheus);
+  } else if (fam->unit != NULL && fam->unit[0] != '{') {
+    strbuf_printf(buf, "_%s", fam->unit);
+  }
+
   if (fam->type == METRIC_TYPE_COUNTER) {
     strbuf_print(buf, "_total");
   }
index ecbaa9a075beeec22510e983a1fd9dab4f955105..61d1de5cfccd9f76a099d5a262096d7fc1f1ec56 100644 (file)
@@ -65,12 +65,57 @@ DEF_TEST(format_metric_family_name) {
   struct {
     char *name;
     metric_type_t type;
+    char *unit;
     char *want;
   } cases[] = {
-      {"(lambda).function.executions(#)", METRIC_TYPE_UNTYPED,
-       "lambda_function_executions"},
-      {"system.processes.created", METRIC_TYPE_COUNTER,
-       "system_processes_created_total"},
+      {
+          .name = "(lambda).function.executions(#)",
+          .type = METRIC_TYPE_UNTYPED,
+          .want = "lambda_function_executions",
+      },
+      {
+          .name = "system.processes.created",
+          .type = METRIC_TYPE_COUNTER,
+          .want = "system_processes_created_total",
+      },
+      {
+          .name = "system.filesystem.usage",
+          .type = METRIC_TYPE_GAUGE,
+          .unit = "By",
+          .want = "system_filesystem_usage_bytes",
+      },
+      {
+          .name = "system.network.dropped",
+          .type = METRIC_TYPE_GAUGE,
+          .unit = "{packets}",
+          .want = "system_network_dropped",
+      },
+      {
+          .name = "system.network.dropped",
+          .type = METRIC_TYPE_GAUGE,
+          .unit = "packets",
+          .want = "system_network_dropped_packets",
+      },
+      {
+          .name = "system.memory.utilization",
+          .type = METRIC_TYPE_GAUGE,
+          .unit = "1",
+          .want = "system_memory_utilization_ratio",
+      },
+      {
+          .name = "storage.filesystem.utilization",
+          .type = METRIC_TYPE_GAUGE,
+          .unit = "%",
+          .want = "storage_filesystem_utilization_percent",
+      },
+      /* Not yet supported:
+      {
+          .name = "astro.light.speed",
+          .type = METRIC_TYPE_GAUGE,
+          .unit = "m/s",
+          .want = "astro_light_speed_meters_per_second",
+      },
+      */
   };
 
   for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
@@ -80,6 +125,7 @@ DEF_TEST(format_metric_family_name) {
     metric_family_t fam = {
         .name = cases[i].name,
         .type = cases[i].type,
+        .unit = cases[i].unit,
     };
 
     format_metric_family_name(&got, &fam);