]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
Daemon: Add a new metric type for floating point counters.
authorFlorian Forster <octo@collectd.org>
Wed, 31 Jan 2024 07:42:16 +0000 (08:42 +0100)
committerFlorian Forster <octo@collectd.org>
Wed, 31 Jan 2024 13:39:14 +0000 (14:39 +0100)
src/daemon/metric.c
src/daemon/metric.h
src/daemon/plugin.h
src/daemon/utils_cache.c
src/daemon/utils_cache_test.c
src/utils/value_list/value_list.h

index daf735b1bde0587ffd66a52728b2a37b80a4cd3e..2247220ea70e0e2924a86741d93a7d42f15bb5fb 100644 (file)
@@ -52,7 +52,7 @@
 int value_marshal_text(strbuf_t *buf, value_t v, metric_type_t type) {
   switch (type) {
   case METRIC_TYPE_GAUGE:
-  case METRIC_TYPE_UNTYPED:
+  case METRIC_TYPE_FPCOUNTER:
     return strbuf_printf(buf, GAUGE_FORMAT, v.gauge);
   case METRIC_TYPE_COUNTER:
     return strbuf_printf(buf, "%" PRIu64, v.counter);
index e2e72b5a945fa9725492bb6ede42a8941ecd7880..c2e9d0f779cbc0da6f45aab13bc0898bf41c4348 100644 (file)
 #include "utils/strbuf/strbuf.h"
 #include "utils_time.h"
 
-#define VALUE_TYPE_GAUGE 1
-#define VALUE_TYPE_DERIVE 2
+#define METRIC_ATTR_DOUBLE 0x01
+#define METRIC_ATTR_CUMULATIVE 0x02
 
 typedef enum {
-  METRIC_TYPE_COUNTER = 0,
-  METRIC_TYPE_GAUGE = 1,
-  METRIC_TYPE_UNTYPED = 2,
+  METRIC_TYPE_UNTYPED = 0,
+  METRIC_TYPE_COUNTER = METRIC_ATTR_CUMULATIVE,
+  METRIC_TYPE_FPCOUNTER = METRIC_ATTR_DOUBLE | METRIC_ATTR_CUMULATIVE,
+  METRIC_TYPE_GAUGE = METRIC_ATTR_DOUBLE,
 } metric_type_t;
 
 typedef uint64_t counter_t;
+typedef double fpcounter_t;
 typedef double gauge_t;
 typedef int64_t derive_t;
 
 union value_u {
   counter_t counter;
+  fpcounter_t fpcounter;
   gauge_t gauge;
   derive_t derive;
 };
index e1c54627a6dfc8118507a8bff35fdf08a263bc74..ceca96d08d00ea0c3b3cce77508ce6b507650b33 100644 (file)
 #include <inttypes.h>
 #include <pthread.h>
 
-#define DS_TYPE_COUNTER 0
-#define DS_TYPE_GAUGE VALUE_TYPE_GAUGE
-#define DS_TYPE_DERIVE VALUE_TYPE_DERIVE
-
 #define DS_TYPE_TO_STRING(t)                                                   \
   (t == DS_TYPE_COUNTER)  ? "counter"                                          \
   : (t == DS_TYPE_GAUGE)  ? "gauge"                                            \
index 057531e1501a9768036ee3f7f27a5a9c58554441..df0a552ad9a4631ce21e3d5075ba043dbb01bd4b 100644 (file)
@@ -154,14 +154,14 @@ static int uc_insert(metric_t const *m, char const *key) {
   sstrncpy(ce->name, key, sizeof(ce->name));
 
   switch (m->family->type) {
-  case DS_TYPE_COUNTER:
-  case DS_TYPE_DERIVE:
+  case METRIC_TYPE_COUNTER:
+  case METRIC_TYPE_FPCOUNTER:
     // Non-gauge types will store the rate in values_gauge when the second data
     // point is available. Initially, NAN signifies "not enough data".
     ce->values_gauge = NAN;
     break;
 
-  case DS_TYPE_GAUGE:
+  case METRIC_TYPE_GAUGE:
     ce->values_gauge = m->value.gauge;
     break;
 
@@ -349,22 +349,28 @@ static int uc_update_metric(metric_t const *m) {
     break;
   }
 
-  case METRIC_TYPE_UNTYPED:
-  case METRIC_TYPE_GAUGE: {
-    ce->values_gauge = m->value.gauge;
+  case METRIC_TYPE_FPCOUNTER: {
+    // For floating point counters, the logic is slightly different from
+    // integer counters. Floating point counters don't have a (meaningful)
+    // overflow, and we will always assume a counter reset.
+    if (ce->last_value.fpcounter > m->value.fpcounter) {
+      // counter reset
+      ce->first_time = m->time;
+      ce->first_value = m->value;
+      ce->values_gauge = NAN;
+      break;
+    }
+    gauge_t diff = m->value.fpcounter - ce->last_value.fpcounter;
+    ce->values_gauge = diff / CDTIME_T_TO_DOUBLE(m->time - ce->last_time);
     break;
   }
 
-#if 0
-  case DS_TYPE_DERIVE: { /* TODO(octo): add support for DERIVE */
-    derive_t diff = m->value.derive - ce->values_raw.derive;
-    ce->values_gauge =
-        ((double)diff) / (CDTIME_T_TO_DOUBLE(m->time - ce->last_time));
-    ce->values_raw.derive = m->value.derive;
+  case METRIC_TYPE_GAUGE: {
+    ce->values_gauge = m->value.gauge;
     break;
   }
-#endif
 
+  case METRIC_TYPE_UNTYPED:
   default: {
     /* This shouldn't happen. */
     pthread_mutex_unlock(&cache_lock);
index 29d640b8de5584cdb003ac81ebdea84a7d664157..ef2c66fd4de5c879790f29f529e006f555b64a1c 100644 (file)
@@ -86,6 +86,24 @@ DEF_TEST(uc_get_rate) {
           .type = METRIC_TYPE_COUNTER,
           .want = (23. + 18. + 1.) / (110. - 100.),
       },
+      {
+          .name = "fpcounter",
+          .first_value = (value_t){.fpcounter = 4.2},
+          .second_value = (value_t){.fpcounter = 10.2},
+          .first_time = TIME_T_TO_CDTIME_T(100),
+          .second_time = TIME_T_TO_CDTIME_T(110),
+          .type = METRIC_TYPE_FPCOUNTER,
+          .want = (10.2 - 4.2) / (110 - 100),
+      },
+      {
+          .name = "fpcounter with reset",
+          .first_value = (value_t){.fpcounter = 100000.0},
+          .second_value = (value_t){.fpcounter = 0.2},
+          .first_time = TIME_T_TO_CDTIME_T(100),
+          .second_time = TIME_T_TO_CDTIME_T(110),
+          .type = METRIC_TYPE_FPCOUNTER,
+          .want = NAN,
+      },
   };
 
   for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
index 2b95fb8197f2389ffa02879daff4f44676bf8ee8..9ba6429b6ece776a6ecb09a670415e214b2905e2 100644 (file)
 #define UTILS_VALUE_LIST_H 1
 
 #include "daemon/data_set.h"
-#include "daemon/plugin.h"
+#include "daemon/metric.h" // for value_t
+
+#define DS_TYPE_COUNTER METRIC_TYPE_COUNTER
+#define DS_TYPE_GAUGE METRIC_TYPE_GAUGE
+#define DS_TYPE_DERIVE (65536 + METRIC_ATTR_CUMULATIVE + 1)
 
 struct value_list_s {
   value_t *values;