Skip to content

Commit 90fb4b3

Browse files
jukkarnashif
authored andcommitted
net: prometheus: Use linked list for metrics
Save same memory and store metrics into a linked list inside a collector entry. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 460e2f8 commit 90fb4b3

File tree

6 files changed

+86
-50
lines changed

6 files changed

+86
-50
lines changed

include/zephyr/net/prometheus/collector.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* @{
2020
*/
2121

22+
#include <zephyr/kernel.h>
2223
#include <zephyr/sys/iterable_sections.h>
2324
#include <zephyr/net/prometheus/metric.h>
2425

@@ -33,9 +34,9 @@ struct prometheus_collector {
3334
/** Name of the collector */
3435
const char *name;
3536
/** Array of metrics associated with the collector */
36-
struct prometheus_metric *metric[CONFIG_PROMETHEUS_MAX_METRICS];
37-
/** Number of metrics associated with the collector */
38-
size_t size;
37+
sys_slist_t metrics;
38+
/** Mutex to protect the metrics list manipulation */
39+
struct k_mutex lock;
3940
};
4041

4142
/**
@@ -45,9 +46,12 @@ struct prometheus_collector {
4546
*
4647
* @param _name The collector's name.
4748
*/
48-
#define PROMETHEUS_COLLECTOR_DEFINE(_name) \
49-
static STRUCT_SECTION_ITERABLE(prometheus_collector, _name) = { \
50-
.name = STRINGIFY(_name), .size = 0, .metric = {0}}
49+
#define PROMETHEUS_COLLECTOR_DEFINE(_name) \
50+
static STRUCT_SECTION_ITERABLE(prometheus_collector, _name) = { \
51+
.name = STRINGIFY(_name), \
52+
.metrics = SYS_SLIST_STATIC_INIT(&_name.metrics), \
53+
.lock = Z_MUTEX_INITIALIZER(_name.lock), \
54+
}
5155

5256
/**
5357
* @brief Register a metric with a Prometheus collector
@@ -73,7 +77,7 @@ int prometheus_collector_register_metric(struct prometheus_collector *collector,
7377
* @param name Name of the metric to retrieve.
7478
* @return Pointer to the retrieved metric, or NULL if not found.
7579
*/
76-
const void *prometheus_collector_get_metric(const struct prometheus_collector *collector,
80+
const void *prometheus_collector_get_metric(struct prometheus_collector *collector,
7781
const char *name);
7882

7983
/**

include/zephyr/net/prometheus/formatter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*
3131
* @return 0 on success, negative errno on error.
3232
*/
33-
int prometheus_format_exposition(const struct prometheus_collector *collector, char *buffer,
33+
int prometheus_format_exposition(struct prometheus_collector *collector, char *buffer,
3434
size_t buffer_size);
3535

3636
/**

include/zephyr/net/prometheus/metric.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include <zephyr/sys/iterable_sections.h>
20+
#include <zephyr/sys/slist.h>
2021
#include <zephyr/net/prometheus/label.h>
2122

2223
/**
@@ -46,6 +47,8 @@ enum prometheus_metric_type {
4647
* to control the metric access and usage.
4748
*/
4849
struct prometheus_metric {
50+
/** Slist metric list node */
51+
sys_snode_t node;
4952
/** Type of the Prometheus metric. */
5053
enum prometheus_metric_type type;
5154
/** Name of the Prometheus metric. */

subsys/net/lib/prometheus/Kconfig

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,4 @@ module-str = Log level for PROMETHEUS
1616
module-help = Enable debug message of PROMETHEUS client library.
1717
source "subsys/net/Kconfig.template.log_config.net"
1818

19-
config PROMETHEUS_MAX_METRICS
20-
int "Maximum number of metrics"
21-
default 10
22-
help
23-
Maximum number of metrics that can be registered.
24-
2519
endif # PROMETHEUS

subsys/net/lib/prometheus/collector.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,16 @@ int prometheus_collector_register_metric(struct prometheus_collector *collector,
3131

3232
LOG_DBG("Registering metric type=%d", metric->type);
3333

34-
for (int i = 0; i < CONFIG_PROMETHEUS_MAX_METRICS; i++) {
35-
if (!collector->metric[i]) {
36-
collector->metric[i] = metric;
37-
collector->size++;
38-
return 0;
39-
}
40-
}
34+
k_mutex_lock(&collector->lock, K_FOREVER);
35+
36+
/* Node cannot be added to list twice */
37+
(void)sys_slist_find_and_remove(&collector->metrics, &metric->node);
4138

42-
return -ENOMEM;
39+
sys_slist_prepend(&collector->metrics, &metric->node);
40+
41+
k_mutex_unlock(&collector->lock);
42+
43+
return 0;
4344
}
4445

4546
const struct prometheus_counter *prometheus_get_counter_metric(const char *name)
@@ -106,24 +107,35 @@ const struct prometheus_summary *prometheus_get_summary_metric(const char *name)
106107
return NULL;
107108
}
108109

109-
const void *prometheus_collector_get_metric(const struct prometheus_collector *collector,
110+
const void *prometheus_collector_get_metric(struct prometheus_collector *collector,
110111
const char *name)
111112
{
112113
bool is_found = false;
113114
enum prometheus_metric_type type = 0;
115+
struct prometheus_metric *metric;
116+
struct prometheus_metric *tmp;
114117

115-
for (size_t i = 0; i < collector->size; ++i) {
116-
if (strncmp(collector->metric[i]->name, name, sizeof(collector->metric[i]->name)) ==
117-
0) {
118-
type = collector->metric[i]->type;
118+
if (collector == NULL || name == NULL) {
119+
return NULL;
120+
}
121+
122+
k_mutex_lock(&collector->lock, K_FOREVER);
123+
124+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&collector->metrics, metric, tmp, node) {
125+
126+
if (strncmp(metric->name, name, sizeof(metric->name)) == 0) {
127+
type = metric->type;
119128
is_found = true;
120129

121-
LOG_DBG("metric found: %s", collector->metric[i]->name);
130+
LOG_DBG("metric found: %s", metric->name);
131+
break;
122132
}
123133
}
124134

135+
k_mutex_unlock(&collector->lock);
136+
125137
if (!is_found) {
126-
LOG_ERR("Metric not found");
138+
LOG_ERR("Metric %s not found", name);
127139
return NULL;
128140
}
129141

subsys/net/lib/prometheus/formatter.c

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2024 Mustafa Abdullah Kus, Sparse Technology
3+
* Copyright (c) 2024 Nordic Semiconductor
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -45,21 +46,22 @@ static int write_metric_to_buffer(char *buffer, size_t buffer_size, const char *
4546
return 0;
4647
}
4748

48-
int prometheus_format_exposition(const struct prometheus_collector *collector, char *buffer,
49+
int prometheus_format_exposition(struct prometheus_collector *collector, char *buffer,
4950
size_t buffer_size)
5051
{
51-
int ret;
52+
struct prometheus_metric *metric;
53+
struct prometheus_metric *tmp;
5254
int written = 0;
55+
int ret = 0;
5356

5457
if (collector == NULL || buffer == NULL || buffer_size == 0) {
5558
LOG_ERR("Invalid arguments");
5659
return -EINVAL;
5760
}
5861

59-
/* iterate through each metric in the collector */
60-
for (size_t ind = 0; ind < collector->size; ind++) {
62+
k_mutex_lock(&collector->lock, K_FOREVER);
6163

62-
const struct prometheus_metric *metric = collector->metric[ind];
64+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&collector->metrics, metric, tmp, node) {
6365

6466
/* write HELP line if available */
6567
if (metric->description[0] != '\0') {
@@ -68,7 +70,7 @@ int prometheus_format_exposition(const struct prometheus_collector *collector, c
6870
metric->description);
6971
if (ret < 0) {
7072
LOG_ERR("Error writing to buffer");
71-
return ret;
73+
goto out;
7274
}
7375
}
7476

@@ -79,40 +81,49 @@ int prometheus_format_exposition(const struct prometheus_collector *collector, c
7981
"# TYPE %s counter\n", metric->name);
8082
if (ret < 0) {
8183
LOG_ERR("Error writing counter");
82-
return ret;
84+
goto out;
8385
}
86+
8487
break;
88+
8589
case PROMETHEUS_GAUGE:
8690
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
8791
"# TYPE %s gauge\n", metric->name);
8892
if (ret < 0) {
8993
LOG_ERR("Error writing gauge");
90-
return ret;
94+
goto out;
9195
}
96+
9297
break;
98+
9399
case PROMETHEUS_HISTOGRAM:
94100
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
95101
"# TYPE %s histogram\n", metric->name);
96102
if (ret < 0) {
97103
LOG_ERR("Error writing histogram");
98-
return ret;
104+
goto out;
99105
}
106+
100107
break;
108+
101109
case PROMETHEUS_SUMMARY:
102110
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
103111
"# TYPE %s summary\n", metric->name);
104112
if (ret < 0) {
105113
LOG_ERR("Error writing summary");
106-
return ret;
114+
goto out;
107115
}
116+
108117
break;
118+
109119
default:
110120
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
111121
"# TYPE %s untyped\n", metric->name);
112122
if (ret < 0) {
113123
LOG_ERR("Error writing untyped");
114-
return ret;
124+
goto out;
115125
}
126+
116127
break;
117128
}
118129

@@ -132,11 +143,13 @@ int prometheus_format_exposition(const struct prometheus_collector *collector, c
132143
metric->labels[i].value, counter->value);
133144
if (ret < 0) {
134145
LOG_ERR("Error writing counter");
135-
return ret;
146+
goto out;
136147
}
137148
}
149+
138150
break;
139151
}
152+
140153
case PROMETHEUS_GAUGE: {
141154
const struct prometheus_gauge *gauge =
142155
(const struct prometheus_gauge *)prometheus_collector_get_metric(
@@ -151,11 +164,13 @@ int prometheus_format_exposition(const struct prometheus_collector *collector, c
151164
metric->labels[i].value, gauge->value);
152165
if (ret < 0) {
153166
LOG_ERR("Error writing gauge");
154-
return ret;
167+
goto out;
155168
}
156169
}
170+
157171
break;
158172
}
173+
159174
case PROMETHEUS_HISTOGRAM: {
160175
const struct prometheus_histogram *histogram =
161176
(const struct prometheus_histogram *)
@@ -171,26 +186,28 @@ int prometheus_format_exposition(const struct prometheus_collector *collector, c
171186
histogram->buckets[i].count);
172187
if (ret < 0) {
173188
LOG_ERR("Error writing histogram");
174-
return ret;
189+
goto out;
175190
}
176191
}
177192

178193
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
179194
"%s_sum %f\n", metric->name, histogram->sum);
180195
if (ret < 0) {
181196
LOG_ERR("Error writing histogram");
182-
return ret;
197+
goto out;
183198
}
184199

185200
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
186201
"%s_count %lu\n", metric->name,
187202
histogram->count);
188203
if (ret < 0) {
189204
LOG_ERR("Error writing histogram");
190-
return ret;
205+
goto out;
191206
}
207+
192208
break;
193209
}
210+
194211
case PROMETHEUS_SUMMARY: {
195212
const struct prometheus_summary *summary =
196213
(const struct prometheus_summary *)prometheus_collector_get_metric(
@@ -206,32 +223,38 @@ int prometheus_format_exposition(const struct prometheus_collector *collector, c
206223
summary->quantiles[i].value);
207224
if (ret < 0) {
208225
LOG_ERR("Error writing summary");
209-
return ret;
226+
goto out;
210227
}
211228
}
212229

213230
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
214231
"%s_sum %f\n", metric->name, summary->sum);
215232
if (ret < 0) {
216233
LOG_ERR("Error writing summary");
217-
return ret;
234+
goto out;
218235
}
219236

220237
ret = write_metric_to_buffer(buffer + written, buffer_size - written,
221238
"%s_count %lu\n", metric->name,
222239
summary->count);
223240
if (ret < 0) {
224241
LOG_ERR("Error writing summary");
225-
return ret;
242+
goto out;
226243
}
244+
227245
break;
228246
}
247+
229248
default:
230249
/* should not happen */
231250
LOG_ERR("Unsupported metric type %d", metric->type);
232-
return -EINVAL;
251+
ret = -EINVAL;
252+
goto out;
233253
}
234254
}
235255

236-
return 0;
256+
out:
257+
k_mutex_unlock(&collector->lock);
258+
259+
return ret;
237260
}

0 commit comments

Comments
 (0)