Asterisk - The Open Source Telephony Project GIT-master-2de1a68
res_prometheus.h
Go to the documentation of this file.
1/*
2 * res_prometheus: Asterisk Prometheus Metrics
3 *
4 * Copyright (C) 2019 Sangoma, Inc.
5 *
6 * Matt Jordan <mjordan@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19#ifndef RES_PROMETHEUS_H__
20#define RES_PROMETHEUS_H__
21
22/*!
23 * \file
24 *
25 * \brief Asterisk Prometheus Metrics
26 *
27 * This module provides the base APIs and functionality for exposing a
28 * metrics route in Asterisk's HTTP server suitable for consumption by
29 * a Prometheus server. It does not provide any metrics itself.
30 */
31
32#include "asterisk/lock.h"
35
36/*!
37 * \brief How many labels a single metric can have
38 */
39#define PROMETHEUS_MAX_LABELS 8
40
41/*!
42 * \brief How long a label name can be
43 */
44#define PROMETHEUS_MAX_NAME_LENGTH 64
45
46/*!
47 * \brief How long a label value can be
48 */
49#define PROMETHEUS_MAX_LABEL_LENGTH 128
50
51/*!
52 * \brief How large of a value we can store
53 */
54#define PROMETHEUS_MAX_VALUE_LENGTH 32
55
56/*!
57 * \brief Prometheus general configuration
58 *
59 * While the config file should generally provide the configuration
60 * for this module, it is useful for testing purposes to allow the
61 * configuration to be injected into the module. This struct is
62 * public to allow this to occur.
63 *
64 * \note
65 * Modifying the configuration outside of testing purposes is not
66 * encouraged.
67 */
69 /*! \brief Whether or not the module is enabled */
70 unsigned int enabled;
71 /*! \brief Whether or not core metrics are enabled */
74 /*! \brief The HTTP URI we register ourselves to */
76 /*! \brief Auth username for Basic Auth */
78 /*! \brief Auth password for Basic Auth */
80 /*! \brief Auth realm */
82 );
83};
84
85/*!
86 * \brief A function table for a metrics provider
87 *
88 * It's generally nice to separate out things that provide metrics
89 * from the core of this module. For those that want to be notified
90 * when things happen in the core module, they can provide an instance
91 * of this function table using \c prometheus_metrics_provider_register
92 * and be notified when module affecting changes occur.
93 */
95 /*!
96 * \brief Handy name of the provider for debugging purposes
97 */
98 const char *name;
99 /*!
100 * \brief Reload callback
101 *
102 * \param config The reloaded config
103 *
104 * \retval 0 success
105 * \retval -1 error
106 */
108 /*!
109 * \brief Unload callback.
110 */
111 void (* const unload_cb)(void);
112};
113
114/*!
115 * \brief Prometheus metric type
116 *
117 * \note
118 * Clearly, at some point, we should support summaries and histograms.
119 * As an initial implementation, counters / gauges give us quite a
120 * bit of functionality.
121 */
123 /*!
124 * \brief A metric whose value always goes up
125 */
127 /*!
128 * \brief A metric whose value can bounce around like a jackrabbit
129 */
131};
132
133/*!
134 * \brief How the metric was allocated.
135 *
136 * \note Clearly, you don't want to get this wrong.
137 */
139 /*!
140 * \brief The metric was allocated on the stack
141 */
143 /*!
144 * \brief The metric was allocated on the heap
145 */
147};
148
149/*!
150 * \brief A label that further defines a metric
151 */
153 /*!
154 * \brief The name of the label
155 */
157 /*!
158 * \brief The value of the label
159 */
161};
162
163/*!
164 * \brief An actual, honest to god, metric.
165 *
166 * A bit of effort has gone into making this structure as efficient as we
167 * possibly can. Given that a *lot* of metrics can theoretically be dumped out,
168 * and that Asterisk attempts to be a "real-time" system, we want this process
169 * to be as efficient as possible. Countering that is the ridiculous flexibility
170 * that Prometheus allows for (and, to an extent, wants) - namely the notion of
171 * families of metrics delineated by their labels.
172 *
173 * In order to balance this, metrics have arrays of labels. While this makes for
174 * a very large struct (such that loading one of these into memory is probably
175 * going to blow your cache), you will at least get the whole thing, since
176 * you're going to need those labels to figure out what you're looking like.
177 *
178 * A hierarchy of metrics occurs when all metrics have the same \c name, but
179 * different labels.
180 *
181 * We manage the hierarchy by allowing a metric to maintain their own list of
182 * related metrics. When metrics are registered (/c prometheus_metric_register),
183 * the function will automatically determine the hierarchy and place them into
184 * the appropriate lists. When you are creating metrics on the fly in a callback
185 * (\c prometheus_callback_register), you have to manage this hierarchy
186 * yourself, and only print out the first metric in a chain.
187 *
188 * Note that **EVERYTHING** in a metric is immutable once registered, save for
189 * its value. Modifying the hierarchy, labels, name, help, whatever is going to
190 * result in a "bad time", and is also expressly against Prometheus law. (Don't
191 * get your liver eaten.)
192 */
194 /*!
195 * \brief What type of metric we are
196 */
198 /*!
199 * \brief How this metric was allocated
200 */
202 /*!
203 * \brief A lock protecting the metric \c value
204 *
205 * \note The metric must be locked prior to updating its value!
206 */
208 /*!
209 * \brief Pointer to a static string defining this metric's help text.
210 */
211 const char *help;
212 /*!
213 * \brief Our metric name
214 */
216 /*!
217 * \brief The metric's labels
218 */
220 /*!
221 * \brief The current value.
222 *
223 * If \c get_metric_value is set, this value is ignored until the callback
224 * happens
225 */
227 /*!
228 * \brief Callback function to obtain the metric value
229 *
230 * If updates need to happen when the metric is gathered, provide the
231 * callback function. Otherwise, leave it \c NULL.
232 */
233 void (* get_metric_value)(struct prometheus_metric *metric);
234 /*!
235 * \brief A list of children metrics
236 *
237 * Children metrics have the same name but different label.
238 *
239 * Registration of a metric will automatically nest the metrics; otherwise
240 * they are treated independently.
241 *
242 * The help of the first metric in a chain of related metrics is the only
243 * one that will be printed.
244 *
245 * For metrics output during a callback, the handler is responsible for
246 * managing the children. For metrics that are registered, the registration
247 * automatically nests the metrics.
248 */
251};
252
253/*!
254 * \brief Convenience macro for initializing a metric on the stack
255 *
256 * When initializing a metric on the stack, various fields have to be provided
257 * to initialize the metric correctly. This macro can be used to simplify the
258 * process.
259 *
260 * Example Usage:
261 * \code
262 * struct prometheus_metric test_counter_one =
263 * PROMETHEUS_METRIC_STATIC_INITIALIZATION(
264 * PROMETHEUS_METRIC_COUNTER,
265 * "test_counter_one",
266 * "A test counter",
267 * NULL);
268 * struct prometheus_metric test_counter_two =
269 * PROMETHEUS_METRIC_STATIC_INITIALIZATION(
270 * PROMETHEUS_METRIC_COUNTER,
271 * "test_counter_two",
272 * "A test counter",
273 * metric_values_get_counter_value_cb);
274 * \endcode
275 *
276 * \param mtype The metric type. See \c prometheus_metric_type
277 * \param n Name of the metric
278 * \param h Help text for the metric
279 * \param cb Callback function. Optional; may be \c NULL
280 */
281#define PROMETHEUS_METRIC_STATIC_INITIALIZATION(mtype, n, h, cb) { \
282 .type = (mtype), \
283 .allocation_strategy = PROMETHEUS_METRIC_ALLOCD, \
284 .lock = AST_MUTEX_INIT_VALUE, \
285 .name = (n), \
286 .help = (h), \
287 .children = AST_LIST_HEAD_NOLOCK_INIT_VALUE, \
288 .get_metric_value = (cb), \
289}
290
291/*!
292 * \brief Convenience macro for setting a label / value in a metric
293 *
294 * When creating nested metrics, it's helpful to set their label after they have
295 * been declared but before they have been registered. This macro acts as a
296 * convenience function to set the labels properly on a declared metric.
297 *
298 * \note Setting labels *after* registration will lead to a "bad time"
299 *
300 * Example Usage:
301 * \code
302 * PROMETHEUS_METRIC_SET_LABEL(
303 * test_gauge_child_two, 0, "key_one", "value_two");
304 * PROMETHEUS_METRIC_SET_LABEL(
305 * test_gauge_child_two, 1, "key_two", "value_two");
306 * \endcode
307 *
308 * \param metric The metric to set the label on
309 * \param label Position of the label to set
310 * \param n Name of the label
311 * \param v Value of the label
312 */
313#define PROMETHEUS_METRIC_SET_LABEL(metric, label, n, v) do { \
314 ast_assert((label) < PROMETHEUS_MAX_LABELS); \
315 ast_copy_string((metric)->labels[(label)].name, (n), sizeof((metric)->labels[(label)].name)); \
316 ast_copy_string((metric)->labels[(label)].value, (v), sizeof((metric)->labels[(label)].value)); \
317} while (0)
318
319/*!
320 * \brief Destroy a metric and all its children
321 *
322 * \note If you still want the children, make sure you remove the head of the
323 * \c children list first.
324 *
325 * \param metric The metric to destroy
326 */
327void prometheus_metric_free(struct prometheus_metric *metric);
328
329/*!
330 * \brief Create a malloc'd counter metric
331 *
332 * \note The metric must be registered after creation
333 *
334 * \param name The name of the metric
335 * \param help Help text for the metric
336 *
337 * \retval prometheus_metric on success
338 * \retval NULL on error
339 */
341 const char *help);
342
343/*!
344 * \brief Create a malloc'd gauge metric
345 *
346 * \note The metric must be registered after creation
347 *
348 * \param name The name of the metric
349 * \param help Help text for the metric
350 *
351 * \retval prometheus_metric on success
352 * \retval NULL on error
353 */
355 const char *help);
356
357/*!
358 * \brief Convert a metric (and its children) into Prometheus compatible text
359 *
360 * \param metric The metric to convert to a string
361 * \param[out] output The \c ast_str string to populate with the metric(s)
362 */
364 struct ast_str **output);
365
366/*!
367 * \brief Defines a callback that will be invoked when the HTTP route is called
368 *
369 * This callback presents the second way of passing metrics to a Prometheus
370 * server. For metrics that are generated often or whose value needs to be
371 * stored, metrics can be created and registered. For metrics that can be
372 * obtained "on-the-fly", this mechanism is preferred. When the HTTP route is
373 * queried by prometheus, the registered callbacks are invoked. The string passed
374 * to the callback should be populated with stack-allocated metrics using
375 * \c prometheus_metric_to_string.
376 *
377 * Example Usage:
378 * \code
379 * static void prometheus_metric_callback(struct ast_str **output)
380 * {
381 * struct prometheus_metric test_counter =
382 * PROMETHEUS_METRIC_STATIC_INITIALIZATION(
383 * PROMETHEUS_METRIC_COUNTER,
384 * "test_counter",
385 * "A test counter",
386 * NULL);
387 *
388 * prometheus_metric_to_string(&test_counter, output);
389 * }
390 *
391 * static void load_module(void)
392 * {
393 * struct prometheus_callback callback = {
394 * .name = "test_callback",
395 * .callback_fn = &prometheus_metric_callback,
396 * };
397 *
398 * prometheus_callback_register(&callback);
399 * }
400 *
401 * \endcode
402 *
403 */
405 /*!
406 * \brief The name of our callback (always useful for debugging)
407 */
408 const char *name;
409 /*!
410 * \brief The callback function to invoke
411 */
412 void (* callback_fn)(struct ast_str **output);
413};
414
415/*!
416 * Register a metric for collection
417 *
418 * \param metric The metric to register
419 *
420 * \retval 0 success
421 * \retval -1 error
422 */
424
425/*!
426 * \brief Remove a registered metric
427 *
428 * \param metric The metric to unregister
429 *
430 * \note Unregistering also destroys the metric, if found
431 *
432 * \retval 0 The metric was found, unregistered, and disposed of
433 * \retval -1 The metric was not found
434 */
436
437/*!
438 * The current number of registered metrics
439 *
440 * \retval The current number of registered metrics
441 */
443
444/*!
445 * Register a metric callback
446 *
447 * \param callback The callback to register
448 *
449 * \retval 0 success
450 * \retval -1 error
451 */
453
454/*!
455 * \brief Remove a registered callback
456 *
457 * \param callback The callback to unregister
458 */
460
461/*!
462 * \brief Register a metrics provider
463 *
464 * \param provider The provider function table to register
465 */
467
468/*!
469 * \brief Retrieve the current configuration of the module
470 *
471 * config is an AO2 ref counted object
472 *
473 * \note
474 * This should primarily be done for testing purposes.
475 *
476 * \retval NULL on error
477 * \retval config on success
478 */
480
481/*!
482 * \brief Set the configuration for the module
483 *
484 * This is not a ref-stealing function. The reference count to \c config
485 * will be incremented as a result of calling this method.
486 *
487 * \note
488 * This should primarily be done for testing purposes
489 */
491
492/*!
493 * \brief Allocate a new configuration object
494 *
495 * The returned object is an AO2 ref counted object
496 *
497 * \retval NULL on error
498 * \retval config on success
499 */
501
502#endif /* #ifndef RES_PROMETHEUS_H__ */
static struct prometheus_metrics_provider provider
Definition: bridges.c:201
static const char config[]
Definition: chan_ooh323.c:111
static const char name[]
Definition: format_mp3.c:68
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
Asterisk locking-related definitions:
int prometheus_metric_unregister(struct prometheus_metric *metric)
Remove a registered metric.
int prometheus_metric_register(struct prometheus_metric *metric)
int prometheus_metric_registered_count(void)
#define PROMETHEUS_MAX_LABEL_LENGTH
How long a label value can be.
void prometheus_general_config_set(struct prometheus_general_config *config)
Set the configuration for the module.
prometheus_metric_type
Prometheus metric type.
@ PROMETHEUS_METRIC_GAUGE
A metric whose value can bounce around like a jackrabbit.
@ PROMETHEUS_METRIC_COUNTER
A metric whose value always goes up.
struct prometheus_metric * prometheus_gauge_create(const char *name, const char *help)
Create a malloc'd gauge metric.
void prometheus_callback_unregister(struct prometheus_callback *callback)
Remove a registered callback.
#define PROMETHEUS_MAX_NAME_LENGTH
How long a label name can be.
void * prometheus_general_config_alloc(void)
Allocate a new configuration object.
#define PROMETHEUS_MAX_LABELS
How many labels a single metric can have.
void prometheus_metric_free(struct prometheus_metric *metric)
Destroy a metric and all its children.
void prometheus_metric_to_string(struct prometheus_metric *metric, struct ast_str **output)
Convert a metric (and its children) into Prometheus compatible text.
#define PROMETHEUS_MAX_VALUE_LENGTH
How large of a value we can store.
void prometheus_metrics_provider_register(const struct prometheus_metrics_provider *provider)
Register a metrics provider.
int prometheus_callback_register(struct prometheus_callback *callback)
struct prometheus_general_config * prometheus_general_config_get(void)
Retrieve the current configuration of the module.
prometheus_metric_allocation_strategy
How the metric was allocated.
@ PROMETHEUS_METRIC_ALLOCD
The metric was allocated on the stack.
@ PROMETHEUS_METRIC_MALLOCD
The metric was allocated on the heap.
struct prometheus_metric * prometheus_counter_create(const char *name, const char *help)
Create a malloc'd counter metric.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
Structure for mutex and tracking information.
Definition: lock.h:135
Support for dynamic strings.
Definition: strings.h:623
Defines a callback that will be invoked when the HTTP route is called.
void(* callback_fn)(struct ast_str **output)
The callback function to invoke.
const char * name
The name of our callback (always useful for debugging)
Prometheus general configuration.
const ast_string_field uri
unsigned int enabled
Whether or not the module is enabled.
unsigned int core_metrics_enabled
Whether or not core metrics are enabled.
const ast_string_field auth_password
const ast_string_field auth_realm
const ast_string_field auth_username
A label that further defines a metric.
char name[PROMETHEUS_MAX_NAME_LENGTH]
The name of the label.
char value[PROMETHEUS_MAX_LABEL_LENGTH]
The value of the label.
An actual, honest to god, metric.
char name[PROMETHEUS_MAX_NAME_LENGTH]
Our metric name.
struct prometheus_metric::@270 children
A list of children metrics.
void(* get_metric_value)(struct prometheus_metric *metric)
Callback function to obtain the metric value.
struct prometheus_label labels[PROMETHEUS_MAX_LABELS]
The metric's labels.
struct prometheus_metric::@271 entry
enum prometheus_metric_allocation_strategy allocation_strategy
How this metric was allocated.
const char * help
Pointer to a static string defining this metric's help text.
ast_mutex_t lock
A lock protecting the metric value.
char value[PROMETHEUS_MAX_VALUE_LENGTH]
The current value.
enum prometheus_metric_type type
What type of metric we are.
A function table for a metrics provider.
void(*const unload_cb)(void)
Unload callback.
int(*const reload_cb)(struct prometheus_general_config *config)
Reload callback.
const char * name
Handy name of the provider for debugging purposes.