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); \