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);
#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;
};
#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" \
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;
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);
.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++) {
#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;