return metric_list_add(&fam->metric, m);
}
+int metric_family_append(metric_family_t *fam, char const *lname,
+ char const *lvalue, value_t v, metric_t const *templ) {
+ if ((fam == NULL) || ((lname == NULL) != (lvalue == NULL))) {
+ return EINVAL;
+ }
+
+ metric_t m = {
+ .family = fam,
+ .value = v,
+ };
+ if (templ != NULL) {
+ int status = label_set_clone(&m.label, templ->label);
+ if (status != 0) {
+ return status;
+ }
+
+ m.time = templ->time;
+ m.interval = templ->interval;
+ m.meta = meta_data_clone(templ->meta);
+ }
+
+ if (lname != NULL) {
+ int status = metric_label_set(&m, lname, lvalue);
+ if (status != 0) {
+ return status;
+ }
+ }
+
+ int status = metric_family_metric_append(fam, m);
+ metric_reset(&m);
+ return status;
+}
+
int metric_family_metric_reset(metric_family_t *fam) {
if (fam == NULL) {
return EINVAL;
* allocates memory which must be freed using metric_family_metric_reset. */
int metric_family_metric_append(metric_family_t *fam, metric_t m);
+/* metric_family_append constructs a new metric_t and appends it to fam. It is
+ * a convenience function that is funcitonally approximately equivalent to the
+ * following code, but without modifying templ:
+ *
+ * metric_t m = *templ;
+ * m.value = v;
+ * metric_label_set(&m, lname, lvalue);
+ * metric_family_metric_append(fam, m);
+ */
+int metric_family_append(metric_family_t *fam, char const *lname,
+ char const *lvalue, value_t v, metric_t const *templ);
+
/* metric_family_metric_reset frees all metrics in the metric family and
* resets the count to zero. */
int metric_family_metric_reset(metric_family_t *fam);
return 0;
}
+DEF_TEST(metric_family_append) {
+ struct {
+ char const *lname;
+ char const *lvalue;
+ gauge_t v;
+ metric_t *templ;
+ int want_err;
+ label_t *want_labels;
+ size_t want_labels_num;
+ gauge_t want_value;
+ cdtime_t want_time;
+ cdtime_t want_interval;
+ } cases[] = {
+ {
+ .v = 42,
+ .want_value = 42,
+ },
+ {
+ .lname = "type",
+ .lvalue = "test",
+ .v = 42,
+ .want_labels =
+ (label_t[]){
+ {"type", "test"},
+ },
+ .want_labels_num = 1,
+ .want_value = 42,
+ },
+ {
+ .v = 42,
+ .templ =
+ &(metric_t){
+ .time = TIME_T_TO_CDTIME_T(1594107920),
+ },
+ .want_value = 42,
+ .want_time = TIME_T_TO_CDTIME_T(1594107920),
+ },
+ {
+ .v = 42,
+ .templ =
+ &(metric_t){
+ .interval = TIME_T_TO_CDTIME_T(10),
+ },
+ .want_value = 42,
+ .want_interval = TIME_T_TO_CDTIME_T(10),
+ },
+ {
+ .lname = "type",
+ .lvalue = "test",
+ .v = 42,
+ .templ =
+ &(metric_t){
+ .label =
+ {
+ .ptr = &(label_pair_t){"common", "label"},
+ .num = 1,
+ },
+ },
+ .want_labels =
+ (label_t[]){
+ {"common", "label"},
+ {"type", "test"},
+ },
+ .want_labels_num = 2,
+ .want_value = 42,
+ },
+ };
+
+ for (size_t i = 0; i < (sizeof(cases) / sizeof(cases[0])); i++) {
+ metric_family_t fam = {
+ .name = "test_total",
+ .type = METRIC_TYPE_GAUGE,
+ };
+
+ EXPECT_EQ_INT(cases[i].want_err,
+ metric_family_append(&fam, cases[i].lname, cases[i].lvalue,
+ (value_t){.gauge = cases[i].v},
+ cases[i].templ));
+ if (cases[i].want_err != 0) {
+ continue;
+ }
+
+ EXPECT_EQ_INT(1, fam.metric.num);
+ metric_t const *m = fam.metric.ptr;
+
+ EXPECT_EQ_INT(cases[i].want_labels_num, m->label.num);
+ for (size_t j = 0; j < cases[i].want_labels_num; j++) {
+ EXPECT_EQ_STR(cases[i].want_labels[j].value,
+ metric_label_get(m, cases[i].want_labels[j].name));
+ }
+
+ EXPECT_EQ_DOUBLE(cases[i].want_value, m->value.gauge);
+ EXPECT_EQ_UINT64(cases[i].want_time, m->time);
+ EXPECT_EQ_UINT64(cases[i].want_interval, m->interval);
+
+ metric_family_metric_reset(&fam);
+ }
+
+ return 0;
+}
+
int main(void) {
RUN_TEST(metric_label_set);
RUN_TEST(metric_identity);
+ RUN_TEST(metric_family_append);
END_TEST;
}