Skip to content

Commit 34ed76b

Browse files
jukkarnashif
authored andcommitted
net: prometheus: Add way to format output by a metric
Instead of requiring one big buffer for formatting the output, have a walk function that can be used to generate output by one metric at a time. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 6803e34 commit 34ed76b

File tree

4 files changed

+320
-161
lines changed

4 files changed

+320
-161
lines changed

include/zephyr/net/prometheus/collector.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,60 @@ int prometheus_collector_register_metric(struct prometheus_collector *collector,
116116
const void *prometheus_collector_get_metric(struct prometheus_collector *collector,
117117
const char *name);
118118

119+
/** @cond INTERNAL_HIDDEN */
120+
121+
enum prometheus_walk_state {
122+
PROMETHEUS_WALK_START,
123+
PROMETHEUS_WALK_CONTINUE,
124+
PROMETHEUS_WALK_STOP,
125+
};
126+
127+
struct prometheus_collector_walk_context {
128+
struct prometheus_collector *collector;
129+
struct prometheus_metric *metric;
130+
struct prometheus_metric *tmp;
131+
enum prometheus_walk_state state;
132+
};
133+
134+
/** @endcond */
135+
136+
/**
137+
* @brief Walk through all metrics in a Prometheus collector and format them
138+
* into a buffer.
139+
*
140+
* @param ctx Pointer to the walker context.
141+
* @param buffer Pointer to the buffer to store the formatted metrics.
142+
* @param buffer_size Size of the buffer.
143+
* @return 0 if successful and we went through all metrics, -EAGAIN if we
144+
* need to call this function again, any other negative error code
145+
* means an error occurred.
146+
*/
147+
int prometheus_collector_walk_metrics(struct prometheus_collector_walk_context *ctx,
148+
uint8_t *buffer, size_t buffer_size);
149+
150+
/**
151+
* @brief Initialize the walker context to walk through all metrics.
152+
*
153+
* @param ctx Pointer to the walker context.
154+
* @param collector Pointer to the collector to walk through.
155+
*
156+
* @return 0 if successful, otherwise a negative error code.
157+
*/
158+
static inline int prometheus_collector_walk_init(struct prometheus_collector_walk_context *ctx,
159+
struct prometheus_collector *collector)
160+
{
161+
if (collector == NULL) {
162+
return -EINVAL;
163+
}
164+
165+
ctx->collector = collector;
166+
ctx->state = PROMETHEUS_WALK_START;
167+
ctx->metric = NULL;
168+
ctx->tmp = NULL;
169+
170+
return 0;
171+
}
172+
119173
/**
120174
* @}
121175
*/

include/zephyr/net/prometheus/formatter.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* @brief Format exposition data for Prometheus
2323
*
2424
* Formats the exposition data collected by the specified collector into the provided buffer.
25-
* Function to format metric data according to Prometheus text-based format
25+
* Function will format metric data according to Prometheus text-based format
2626
*
2727
* @param collector Pointer to the collector containing the data to format.
2828
* @param buffer Pointer to the buffer where the formatted exposition data will be stored.
@@ -33,6 +33,22 @@
3333
int prometheus_format_exposition(struct prometheus_collector *collector, char *buffer,
3434
size_t buffer_size);
3535

36+
/**
37+
* @brief Format exposition data for one metric for Prometheus
38+
*
39+
* Formats the exposition data of one specific metric into the provided buffer.
40+
* Function will format metric data according to Prometheus text-based format.
41+
*
42+
* @param metric Pointer to the metric containing the data to format.
43+
* @param buffer Pointer to the buffer where the formatted exposition data will be stored.
44+
* @param buffer_size Size of the buffer.
45+
* @param written How many bytes have been written to the buffer.
46+
*
47+
* @return 0 on success, negative errno on error.
48+
*/
49+
int prometheus_format_one_metric(struct prometheus_metric *metric, char *buffer,
50+
size_t buffer_size, int *written);
51+
3652
/**
3753
* @}
3854
*/

subsys/net/lib/prometheus/collector.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <zephyr/net/prometheus/summary.h>
1313
#include <zephyr/net/prometheus/counter.h>
1414
#include <zephyr/net/prometheus/gauge.h>
15+
#include <zephyr/net/prometheus/formatter.h>
1516

1617
#include <stdlib.h>
1718
#include <string.h>
@@ -157,3 +158,77 @@ const void *prometheus_collector_get_metric(struct prometheus_collector *collect
157158
out:
158159
return NULL;
159160
}
161+
162+
int prometheus_collector_walk_metrics(struct prometheus_collector_walk_context *ctx,
163+
uint8_t *buffer, size_t buffer_size)
164+
{
165+
int ret = 0;
166+
167+
if (ctx->collector == NULL) {
168+
LOG_ERR("Invalid arguments");
169+
return -EINVAL;
170+
}
171+
172+
if (ctx->state == PROMETHEUS_WALK_START) {
173+
k_mutex_lock(&ctx->collector->lock, K_FOREVER);
174+
ctx->state = PROMETHEUS_WALK_CONTINUE;
175+
176+
/* Start of the loop is taken from
177+
* SYS_SLIST_FOR_EACH_CONTAINER_SAFE macro to simulate
178+
* a loop.
179+
*/
180+
181+
ctx->metric = Z_GENLIST_PEEK_HEAD_CONTAINER(slist,
182+
&ctx->collector->metrics,
183+
ctx->metric,
184+
node);
185+
ctx->tmp = Z_GENLIST_PEEK_NEXT_CONTAINER(slist,
186+
ctx->metric,
187+
node);
188+
}
189+
190+
if (ctx->state == PROMETHEUS_WALK_CONTINUE) {
191+
int len = 0;
192+
193+
ctx->metric = ctx->tmp;
194+
ctx->tmp = Z_GENLIST_PEEK_NEXT_CONTAINER(slist,
195+
ctx->metric,
196+
node);
197+
198+
if (ctx->metric == NULL) {
199+
ctx->state = PROMETHEUS_WALK_STOP;
200+
goto out;
201+
}
202+
203+
/* If there is a user callback, use it to update the metric data. */
204+
if (ctx->collector->user_cb) {
205+
ret = ctx->collector->user_cb(ctx->collector, ctx->metric,
206+
ctx->collector->user_data);
207+
if (ret < 0) {
208+
if (ret != -EAGAIN) {
209+
ctx->state = PROMETHEUS_WALK_STOP;
210+
goto out;
211+
}
212+
213+
/* Skip this metric for now */
214+
goto out;
215+
}
216+
}
217+
218+
ret = prometheus_format_one_metric(ctx->metric, buffer, buffer_size, &len);
219+
if (ret < 0) {
220+
ctx->state = PROMETHEUS_WALK_STOP;
221+
goto out;
222+
}
223+
224+
ret = -EAGAIN;
225+
}
226+
227+
out:
228+
if (ctx->state == PROMETHEUS_WALK_STOP) {
229+
k_mutex_unlock(&ctx->collector->lock);
230+
ret = 0;
231+
}
232+
233+
return ret;
234+
}

0 commit comments

Comments
 (0)