Merge remote-tracking branch 'github/pr/1967'
[collectd.git] / src / write_prometheus.c
index 4a9761a..fe7a5b5 100644 (file)
@@ -37,7 +37,7 @@
 #include <microhttpd.h>
 
 #ifndef PROMETHEUS_DEFAULT_STALENESS_DELTA
-#define PROMETHEUS_DEFAULT_STALENESS_DELTA TIME_T_TO_CDTIME_T(300)
+#define PROMETHEUS_DEFAULT_STALENESS_DELTA TIME_T_TO_CDTIME_T_STATIC(300)
 #endif
 
 #define VARINT_UINT32_BYTES 5
@@ -210,8 +210,13 @@ static int http_handler(void *cls, struct MHD_Connection *connection,
   else
     format_text(buffer);
 
+#if defined(MHD_VERSION) && MHD_VERSION >= 0x00090500
+  struct MHD_Response *res = MHD_create_response_from_buffer(
+      simple.len, simple.data, MHD_RESPMEM_MUST_COPY);
+#else
   struct MHD_Response *res = MHD_create_response_from_data(
       simple.len, simple.data, /* must_free = */ 0, /* must_copy = */ 1);
+#endif
   MHD_add_response_header(res, MHD_HTTP_HEADER_CONTENT_TYPE,
                           want_proto ? CONTENT_TYPE_PROTO : CONTENT_TYPE_TEXT);
 
@@ -297,17 +302,37 @@ static int metric_cmp(void const *a, void const *b) {
     return 1;
 
   /* Prometheus does not care about the order of labels. All labels in this
-   * plugin are created by metric_add_labels(), though, and therefore always
+   * plugin are created by METRIC_ADD_LABELS(), though, and therefore always
    * appear in the same order. We take advantage of this and simplify the check
-   * by making sure all labels are the same in each position. */
+   * by making sure all labels are the same in each position.
+   *
+   * We also only need to check the label values, because the label names are
+   * the same for all metrics in a metric family.
+   *
+   * 3 labels:
+   * [0] $plugin="$plugin_instance" => $plugin is the same within a family
+   * [1] type="$type_instance"      => "type" is a static string
+   * [2] instance="$host"           => "instance" is a static string
+   *
+   * 2 labels, variant 1:
+   * [0] $plugin="$plugin_instance" => $plugin is the same within a family
+   * [1] instance="$host"           => "instance" is a static string
+   *
+   * 2 labels, variant 2:
+   * [0] $plugin="$type_instance"   => $plugin is the same within a family
+   * [1] instance="$host"           => "instance" is a static string
+   *
+   * 1 label:
+   * [1] instance="$host"           => "instance" is a static string
+   */
   for (size_t i = 0; i < m_a->n_label; i++) {
-    int status = strcmp(m_a->label[i]->name, m_b->label[i]->name);
+    int status = strcmp(m_a->label[i]->value, m_b->label[i]->value);
     if (status != 0)
       return status;
 
-    status = strcmp(m_a->label[i]->value, m_b->label[i]->value);
-    if (status != 0)
-      return status;
+#if COLLECT_DEBUG
+    assert(strcmp(m_a->label[i]->name, m_b->label[i]->name) == 0);
+#endif
   }
 
   return 0;
@@ -611,8 +636,8 @@ static char *metric_family_name(data_set_t const *ds, value_list_t const *vl,
 /* metric_family_get looks up the matching metric family, allocating it if
  * necessary. */
 static Io__Prometheus__Client__MetricFamily *
-metric_family_get(data_set_t const *ds, value_list_t const *vl,
-                  size_t ds_index) {
+metric_family_get(data_set_t const *ds, value_list_t const *vl, size_t ds_index,
+                  _Bool allocate) {
   char *name = metric_family_name(ds, vl, ds_index);
   if (name == NULL) {
     ERROR("write_prometheus plugin: Allocating metric family name failed.");
@@ -626,6 +651,9 @@ metric_family_get(data_set_t const *ds, value_list_t const *vl,
     return fam;
   }
 
+  if (!allocate)
+    return NULL;
+
   fam = metric_family_create(name, ds, vl, ds_index);
   if (fam == NULL) {
     ERROR("write_prometheus plugin: Allocating metric family failed.");
@@ -707,7 +735,8 @@ static int prom_write(data_set_t const *ds, value_list_t const *vl,
   pthread_mutex_lock(&metrics_lock);
 
   for (size_t i = 0; i < ds->ds_num; i++) {
-    Io__Prometheus__Client__MetricFamily *fam = metric_family_get(ds, vl, i);
+    Io__Prometheus__Client__MetricFamily *fam =
+        metric_family_get(ds, vl, i, /* allocate = */ 1);
     if (fam == NULL)
       continue;
 
@@ -733,7 +762,8 @@ static int prom_missing(value_list_t const *vl,
   pthread_mutex_lock(&metrics_lock);
 
   for (size_t i = 0; i < ds->ds_num; i++) {
-    Io__Prometheus__Client__MetricFamily *fam = metric_family_get(ds, vl, i);
+    Io__Prometheus__Client__MetricFamily *fam =
+        metric_family_get(ds, vl, i, /* allocate = */ 0);
     if (fam == NULL)
       continue;
 
@@ -742,6 +772,7 @@ static int prom_missing(value_list_t const *vl,
       ERROR("write_prometheus plugin: Deleting a metric in family \"%s\" "
             "failed with status %d",
             fam->name, status);
+
       continue;
     }