@cryptotaxi247 / netdata-1 / commits / 964ddcf81

HELP and TYPE in prometheus fix (#19261)

Costa Tsaousis committed Dec 21, 2024 at 14:50 UTC 964ddcf813ae378294df7884a4f1771726c4805c
2 files changed +67 -24
src/exporting/prometheus/prometheus.c
+64 -21
@@ -2,6 +2,13 @@
2
3 #include "prometheus.h"
4
5 +DEFINE_JUDYL_TYPED(PROM_CONTEXT_OPTIONS, PROMETHEUS_OUTPUT_OPTIONS);
6 +
7 +static void PROM_CONTEXT_OPTIONS_free_cb(Word_t index, PROMETHEUS_OUTPUT_OPTIONS options __maybe_unused) {
8 + STRING *context_id = (STRING *)index;
9 + string_freez(context_id);
10 +}
11 +
12 // ----------------------------------------------------------------------------
13 // PROMETHEUS
14 // /api/v1/allmetrics?format=prometheus and /api/v1/allmetrics?format=prometheus_all_hosts
@@ -335,6 +342,7 @@ struct host_variables_callback_options {
342 SIMPLE_PATTERN *pattern;
343 struct instance *instance;
344 STRING *prometheus;
345 + PROM_CONTEXT_OPTIONS_JudyLSet *context_options;
346 };
347
348 /**
@@ -458,10 +466,14 @@ static void generate_as_collected_from_metric(BUFFER *wb,
466 int prometheus_collector,
467 RRDLABELS *chart_labels)
468 {
461 - buffer_sprintf(wb, "%s_%s", p->prefix, p->context);
469 + buffer_strcat(wb, p->prefix);
470 + buffer_putc(wb, '_');
471 + buffer_strcat(wb, p->context);
472
463 - if (!homogeneous)
464 - buffer_sprintf(wb, "_%s", p->dimension);
473 + if (!homogeneous) {
474 + buffer_putc(wb, '_');
475 + buffer_strcat(wb, p->dimension);
476 + }
477
478 buffer_sprintf(wb, "%s{%schart=\"%s\"", p->suffix, p->labels_prefix, p->chart);
479
@@ -472,21 +484,23 @@ static void generate_as_collected_from_metric(BUFFER *wb,
484
485 rrdlabels_walkthrough_read(chart_labels, format_prometheus_chart_label_callback, wb);
486
475 - buffer_sprintf(wb, "%s} ", p->labels);
487 + buffer_strcat(wb, p->labels);
488 + buffer_putc(wb, '}');
489 + buffer_putc(wb, ' ');
490
491 if (prometheus_collector)
478 - buffer_sprintf(
479 - wb,
480 - NETDATA_DOUBLE_FORMAT,
492 + buffer_print_netdata_double(wb,
493 (NETDATA_DOUBLE)p->rd->collector.last_collected_value * (NETDATA_DOUBLE)p->rd->multiplier /
494 (NETDATA_DOUBLE)p->rd->divisor);
495 else
484 - buffer_sprintf(wb, COLLECTED_NUMBER_FORMAT, p->rd->collector.last_collected_value);
496 + buffer_print_int64(wb, p->rd->collector.last_collected_value);
497
486 - if (p->output_options & PROMETHEUS_OUTPUT_TIMESTAMPS)
487 - buffer_sprintf(wb, " %"PRIu64"\n", timeval_msec(&p->rd->collector.last_collected_time));
488 - else
489 - buffer_sprintf(wb, "\n");
498 + if (p->output_options & PROMETHEUS_OUTPUT_TIMESTAMPS) {
499 + buffer_putc(wb, ' ');
500 + buffer_print_uint64(wb, timeval_msec(&p->rd->collector.last_collected_time));
501 + }
502 +
503 + buffer_putc(wb, '\n');
504 }
505
506 static void prometheus_print_os_info(
@@ -605,6 +619,22 @@ static int prometheus_rrdset_to_json(RRDSET *st, void *data)
619 prometheus_label_copy(family, rrdset_family(st), sizeof(family));
620 prometheus_name_copy(context, rrdset_context(st), sizeof(context));
621
622 + if(opts->output_options & PROMETHEUS_OUTPUT_HELP_TYPE) {
623 + // we do not want to print HELP and TYPE for the same context twice
624 + STRING *context_id = string_strdupz(context);
625 + PROMETHEUS_OUTPUT_OPTIONS ctx_opts = PROM_CONTEXT_OPTIONS_GET(opts->context_options, (Word_t)context_id);
626 + if (!(ctx_opts & PROMETHEUS_OUTPUT_HELP_TYPE)) {
627 + // it is not printed for this context yet
628 + ctx_opts = opts->output_options;
629 + PROM_CONTEXT_OPTIONS_SET(opts->context_options, (Word_t)context_id, ctx_opts);
630 + }
631 + else {
632 + // we have printed HELP and TYPE for this context already
633 + opts->output_options &= ~PROMETHEUS_OUTPUT_HELP_TYPE;
634 + string_freez(context_id);
635 + }
636 + }
637 +
638 int as_collected = (EXPORTING_OPTIONS_DATA_SOURCE(opts->exporting_options)
639 == EXPORTING_SOURCE_DATA_AS_COLLECTED);
640 int homogeneous = 1;
@@ -667,7 +697,7 @@ static int prometheus_rrdset_to_json(RRDSET *st, void *data)
697 }
698
699 if (opts->output_options & PROMETHEUS_OUTPUT_HELP_TYPE) {
670 - generate_as_collected_prom_help(wb, prefix, context, units, suffix, st);
700 + generate_as_collected_prom_help(wb, prefix, context, units, p.suffix, st);
701 generate_as_collected_prom_type(wb, prefix, context, units, p.suffix, p.type);
702 opts->output_options &= ~PROMETHEUS_OUTPUT_HELP_TYPE;
703 }
@@ -699,8 +729,7 @@ static int prometheus_rrdset_to_json(RRDSET *st, void *data)
729 NETDATA_DOUBLE value = exporting_calculate_value_from_stored_data(opts->instance, rd, &last_time);
730
731 if (!isnan(value) && !isinf(value)) {
702 - if (EXPORTING_OPTIONS_DATA_SOURCE(opts->exporting_options)
703 - == EXPORTING_SOURCE_DATA_AVERAGE)
732 + if (EXPORTING_OPTIONS_DATA_SOURCE(opts->exporting_options) == EXPORTING_SOURCE_DATA_AVERAGE)
733 suffix = "_average";
734 else if (EXPORTING_OPTIONS_DATA_SOURCE(opts->exporting_options)
735 == EXPORTING_SOURCE_DATA_SUM)
@@ -713,7 +742,7 @@ static int prometheus_rrdset_to_json(RRDSET *st, void *data)
742
743 if (opts->output_options & PROMETHEUS_OUTPUT_HELP_TYPE) {
744 generate_as_collected_prom_help(wb, prefix, context, units, suffix, st);
716 - generate_as_collected_prom_type(wb, prefix, context, units, p.suffix, "gauge");
745 + generate_as_collected_prom_type(wb, prefix, context, units, suffix, "gauge");
746 opts->output_options &= ~PROMETHEUS_OUTPUT_HELP_TYPE;
747 }
748
@@ -740,7 +769,7 @@ static int prometheus_rrdset_to_json(RRDSET *st, void *data)
769 value,
770 last_time * MSEC_PER_SEC);
771 else
743 - buffer_sprintf(wb, "%s_%s%s%s{%s%s} " NETDATA_DOUBLE_FORMAT "\n",
772 + buffer_sprintf(wb, "%s_%s%s%s{%s%s} " NETDATA_DOUBLE_FORMAT "\n",
773 prefix,
774 context,
775 units,
@@ -783,6 +812,8 @@ static inline int prometheus_rrdcontext_callback(const DICTIONARY_ITEM *item, vo
812 return HTTP_RESP_OK;
813 }
814
815 +
816 +
817 /**
818 * Write metrics in Prometheus format to a buffer.
819 *
@@ -803,7 +834,8 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
834 const char *prefix,
835 EXPORTING_OPTIONS exporting_options,
836 int allhosts,
806 - PROMETHEUS_OUTPUT_OPTIONS output_options)
837 + PROMETHEUS_OUTPUT_OPTIONS output_options,
838 + PROM_CONTEXT_OPTIONS_JudyLSet *context_options)
839 {
840 SIMPLE_PATTERN *filter = simple_pattern_create(filter_string, NULL, SIMPLE_PATTERN_EXACT, true);
841
@@ -854,7 +886,8 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
886 .host_header_printed = 0,
887 .pattern = filter,
888 .instance = instance,
857 - .prometheus = string_strdupz("prometheus")
889 + .prometheus = string_strdupz("prometheus"),
890 + .context_options = context_options,
891 };
892
893 // send custom variables set for the host
@@ -946,8 +979,13 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
979 server,
980 prometheus_exporter_instance->before);
981
982 + PROM_CONTEXT_OPTIONS_JudyLSet context_options;
983 + PROM_CONTEXT_OPTIONS_INIT(&context_options);
984 +
985 rrd_stats_api_v1_charts_allmetrics_prometheus(
950 - prometheus_exporter_instance, host, filter_string, wb, prefix, exporting_options, 0, output_options);
986 + prometheus_exporter_instance, host, filter_string, wb, prefix, exporting_options, 0, output_options, &context_options);
987 +
988 + PROM_CONTEXT_OPTIONS_FREE(&context_options, PROM_CONTEXT_OPTIONS_free_cb);
989 }
990
991 /**
@@ -982,10 +1020,15 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(
1020 server,
1021 prometheus_exporter_instance->before);
1022
1023 + PROM_CONTEXT_OPTIONS_JudyLSet context_options;
1024 + PROM_CONTEXT_OPTIONS_INIT(&context_options);
1025 +
1026 dfe_start_reentrant(rrdhost_root_index, host)
1027 {
1028 rrd_stats_api_v1_charts_allmetrics_prometheus(
988 - prometheus_exporter_instance, host, filter_string, wb, prefix, exporting_options, 1, output_options);
1029 + prometheus_exporter_instance, host, filter_string, wb, prefix, exporting_options, 1, output_options, &context_options);
1030 }
1031 dfe_done(host);
1032 +
1033 + PROM_CONTEXT_OPTIONS_FREE(&context_options, PROM_CONTEXT_OPTIONS_free_cb);
1034 }
src/libnetdata/libjudy/judyl-typed.h
+3 -3
@@ -6,7 +6,7 @@
6 #include <Judy.h>
7
8 #define DEFINE_JUDYL_TYPED(NAME, TYPE) \
9 - _Static_assert(sizeof(TYPE) == sizeof(Word_t), \
9 + _Static_assert(sizeof(TYPE) <= sizeof(Word_t), \
10 #NAME "_type_must_have_same_size_as_Word_t"); \
11 typedef struct { \
12 Pvoid_t judyl; \
@@ -60,14 +60,14 @@
60 return (pValue != NULL) ? (TYPE)(uintptr_t)(*pValue) : (TYPE)0; \
61 } \
62 \
63 - static inline void NAME##_FREE(NAME##_JudyLSet *set, void (*callback)(TYPE)) { \
63 + static inline void NAME##_FREE(NAME##_JudyLSet *set, void (*callback)(Word_t, TYPE)) { \
64 Word_t index = 0; \
65 Pvoid_t *pValue; \
66 if (callback) { \
67 for (pValue = JudyLFirst(set->judyl, &index, PJE0); \
68 pValue != NULL; \
69 pValue = JudyLNext(set->judyl, &index, PJE0)) { \
70 - callback((TYPE)(uintptr_t)(*pValue)); \
70 + callback(index, (TYPE)(uintptr_t)(*pValue)); \
71 } \
72 } \
73 JudyLFreeArray(&set->judyl, PJE0); \