1 /*
2  * Copyright (c) 2024 Mustafa Abdullah Kus, Sparse Technology
3  * Copyright (c) 2024 Nordic Semiconductor
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #ifndef ZEPHYR_INCLUDE_PROMETHEUS_COLLECTOR_H_
9 #define ZEPHYR_INCLUDE_PROMETHEUS_COLLECTOR_H_
10 
11 /**
12  * @file
13  *
14  * @brief Prometheus collector APIs.
15  *
16  * @defgroup prometheus Prometheus API
17  * @since 4.0
18  * @version 0.1.0
19  * @ingroup networking
20  * @{
21  */
22 
23 #include <zephyr/kernel.h>
24 #include <zephyr/sys/iterable_sections.h>
25 #include <zephyr/net/prometheus/metric.h>
26 
27 #include <stddef.h>
28 
29 struct prometheus_collector;
30 
31 /**
32  * @typedef prometheus_scrape_cb_t
33  * @brief Callback used to scrape a collector for a specific metric.
34  *
35  * @param collector A valid pointer on the collector to scrape
36  * @param metric A valid pointer on the metric to scrape
37  * @param user_data A valid pointer to a user data or NULL
38  *
39  * @return 0 if successful, otherwise a negative error code.
40  */
41 typedef int (*prometheus_scrape_cb_t)(struct prometheus_collector *collector,
42 				      struct prometheus_metric *metric,
43 				      void *user_data);
44 
45 /**
46  * @brief Prometheus collector definition
47  *
48  * This structure defines a Prometheus collector.
49  */
50 struct prometheus_collector {
51 	/** Name of the collector */
52 	const char *name;
53 	/** Array of metrics associated with the collector */
54 	sys_slist_t metrics;
55 	/** Mutex to protect the metrics list manipulation */
56 	struct k_mutex lock;
57 	/** User callback function. If set, then the metric data is fetched
58 	 * via the function callback.
59 	 */
60 	prometheus_scrape_cb_t user_cb;
61 	/** User data */
62 	void *user_data;
63 };
64 
65 /**
66  * @brief Prometheus Collector definition.
67  *
68  * This macro defines a Collector.
69  *
70  * @param _name The collector's name.
71  * @param ... Optional user callback function. If set, this function is called
72  *            when the collector is scraped. The function should be of type
73  *            prometheus_scrape_cb_t.
74  *            Optional user data to pass to the user callback function.
75  */
76 #define PROMETHEUS_COLLECTOR_DEFINE(_name, ...)	\
77 	STRUCT_SECTION_ITERABLE(prometheus_collector, _name) = {	\
78 		.name = STRINGIFY(_name),				\
79 		.metrics = SYS_SLIST_STATIC_INIT(&_name.metrics),	\
80 		.lock = Z_MUTEX_INITIALIZER(_name.lock),		\
81 		.user_cb = COND_CODE_0(					\
82 			NUM_VA_ARGS_LESS_1(				\
83 				LIST_DROP_EMPTY(__VA_ARGS__, _)),	\
84 			(NULL),						\
85 			(GET_ARG_N(1, __VA_ARGS__))),			\
86 		.user_data = COND_CODE_0(				\
87 			NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL),	\
88 			(GET_ARG_N(1,					\
89 				   GET_ARGS_LESS_N(1, __VA_ARGS__)))),	\
90 	}
91 
92 /**
93  * @brief Register a metric with a Prometheus collector
94  *
95  * Registers the specified metric with the given collector.
96  *
97  * @param collector Pointer to the collector to register the metric with.
98  * @param metric Pointer to the metric to register.
99  *
100  * @return 0 if successful, otherwise a negative error code.
101  * @retval -EINVAL Invalid arguments.
102  * @retval -ENOMEM Not enough memory to register the metric.
103  */
104 int prometheus_collector_register_metric(struct prometheus_collector *collector,
105 					 struct prometheus_metric *metric);
106 
107 /**
108  * @brief Get a metric from a Prometheus collector
109  *
110  * Retrieves the metric with the specified name from the given collector.
111  *
112  * @param collector Pointer to the collector to retrieve the metric from.
113  * @param name Name of the metric to retrieve.
114  * @return Pointer to the retrieved metric, or NULL if not found.
115  */
116 const void *prometheus_collector_get_metric(struct prometheus_collector *collector,
117 					    const char *name);
118 
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  */
prometheus_collector_walk_init(struct prometheus_collector_walk_context * ctx,struct prometheus_collector * collector)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 
173 /**
174  * @}
175  */
176 
177 #endif /* ZEPHYR_INCLUDE_PROMETHEUS_COLLECTOR_H_ */
178