Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
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 */
73 /*! \brief Whether or not channel detail metrics are enabled */
75 /*! \brief Whether or not bridge detail metrics are enabled */
78 /*! \brief The HTTP URI we register ourselves to */
80 /*! \brief Auth username for Basic Auth */
82 /*! \brief Auth password for Basic Auth */
84 /*! \brief Auth realm */
86 );
87};
88
89/*!
90 * \brief A function table for a metrics provider
91 *
92 * It's generally nice to separate out things that provide metrics
93 * from the core of this module. For those that want to be notified
94 * when things happen in the core module, they can provide an instance
95 * of this function table using \c prometheus_metrics_provider_register
96 * and be notified when module affecting changes occur.
97 */
99 /*!
100 * \brief Handy name of the provider for debugging purposes
101 */
102 const char *name;
103 /*!
104 * \brief Reload callback
105 *
106 * \param config The reloaded config
107 *
108 * \retval 0 success
109 * \retval -1 error
110 */
112 /*!
113 * \brief Unload callback.
114 */
115 void (* const unload_cb)(void);
116};
117
118/*!
119 * \brief Prometheus metric type
120 *
121 * \note
122 * Clearly, at some point, we should support summaries and histograms.
123 * As an initial implementation, counters / gauges give us quite a
124 * bit of functionality.
125 */
127 /*!
128 * \brief A metric whose value always goes up
129 */
131 /*!
132 * \brief A metric whose value can bounce around like a jackrabbit
133 */
135};
136
137/*!
138 * \brief How the metric was allocated.
139 *
140 * \note Clearly, you don't want to get this wrong.
141 */
143 /*!
144 * \brief The metric was allocated on the stack
145 */
147 /*!
148 * \brief The metric was allocated on the heap
149 */
151};
152
153/*!
154 * \brief A label that further defines a metric
155 */
157 /*!
158 * \brief The name of the label
159 */
161 /*!
162 * \brief The value of the label
163 */
165};
166
167/*!
168 * \brief An actual, honest to god, metric.
169 *
170 * A bit of effort has gone into making this structure as efficient as we
171 * possibly can. Given that a *lot* of metrics can theoretically be dumped out,
172 * and that Asterisk attempts to be a "real-time" system, we want this process
173 * to be as efficient as possible. Countering that is the ridiculous flexibility
174 * that Prometheus allows for (and, to an extent, wants) - namely the notion of
175 * families of metrics delineated by their labels.
176 *
177 * In order to balance this, metrics have arrays of labels. While this makes for
178 * a very large struct (such that loading one of these into memory is probably
179 * going to blow your cache), you will at least get the whole thing, since
180 * you're going to need those labels to figure out what you're looking like.
181 *
182 * A hierarchy of metrics occurs when all metrics have the same \c name, but
183 * different labels.
184 *
185 * We manage the hierarchy by allowing a metric to maintain their own list of
186 * related metrics. When metrics are registered (/c prometheus_metric_register),
187 * the function will automatically determine the hierarchy and place them into
188 * the appropriate lists. When you are creating metrics on the fly in a callback
189 * (\c prometheus_callback_register), you have to manage this hierarchy
190 * yourself, and only print out the first metric in a chain.
191 *
192 * Note that **EVERYTHING** in a metric is immutable once registered, save for
193 * its value. Modifying the hierarchy, labels, name, help, whatever is going to
194 * result in a "bad time", and is also expressly against Prometheus law. (Don't
195 * get your liver eaten.)
196 */
198 /*!
199 * \brief What type of metric we are
200 */
202 /*!
203 * \brief How this metric was allocated
204 */
206 /*!
207 * \brief A lock protecting the metric \c value
208 *
209 * \note The metric must be locked prior to updating its value!
210 */
212 /*!
213 * \brief Pointer to a static string defining this metric's help text.
214 */
215 const char *help;
216 /*!
217 * \brief Our metric name
218 */
220 /*!
221 * \brief The metric's labels
222 */
224 /*!
225 * \brief The current value.
226 *
227 * If \c get_metric_value is set, this value is ignored until the callback
228 * happens
229 */
231 /*!
232 * \brief Callback function to obtain the metric value
233 *
234 * If updates need to happen when the metric is gathered, provide the
235 * callback function. Otherwise, leave it \c NULL.
236 */
237 void (* get_metric_value)(struct prometheus_metric *metric);
238 /*!
239 * \brief A list of children metrics
240 *
241 * Children metrics have the same name but different label.
242 *
243 * Registration of a metric will automatically nest the metrics; otherwise
244 * they are treated independently.
245 *
246 * The help of the first metric in a chain of related metrics is the only
247 * one that will be printed.
248 *
249 * For metrics output during a callback, the handler is responsible for
250 * managing the children. For metrics that are registered, the registration
251 * automatically nests the metrics.
252 */
255};
256
257/*!
258 * \brief Convenience macro for initializing a metric on the stack
259 *
260 * When initializing a metric on the stack, various fields have to be provided
261 * to initialize the metric correctly. This macro can be used to simplify the
262 * process.
263 *
264 * Example Usage:
265 * \code
266 * struct prometheus_metric test_counter_one =
267 * PROMETHEUS_METRIC_STATIC_INITIALIZATION(
268 * PROMETHEUS_METRIC_COUNTER,
269 * "test_counter_one",
270 * "A test counter",
271 * NULL);
272 * struct prometheus_metric test_counter_two =
273 * PROMETHEUS_METRIC_STATIC_INITIALIZATION(
274 * PROMETHEUS_METRIC_COUNTER,
275 * "test_counter_two",
276 * "A test counter",
277 * metric_values_get_counter_value_cb);
278 * \endcode
279 *
280 * \param mtype The metric type. See \c prometheus_metric_type
281 * \param n Name of the metric
282 * \param h Help text for the metric
283 * \param cb Callback function. Optional; may be \c NULL
284 */
285#define PROMETHEUS_METRIC_STATIC_INITIALIZATION(mtype, n, h, cb) { \
286 .type = (mtype), \
287 .allocation_strategy = PROMETHEUS_METRIC_ALLOCD, \
288 .lock = AST_MUTEX_INIT_VALUE, \
289 .name = (n), \
290 .help = (h), \
291 .children = AST_LIST_HEAD_NOLOCK_INIT_VALUE, \
292 .get_metric_value = (cb), \
293}
294
295/*!
296 * \brief Convenience macro for setting a label / value in a metric
297 *
298 * When creating nested metrics, it's helpful to set their label after they have
299 * been declared but before they have been registered. This macro acts as a
300 * convenience function to set the labels properly on a declared metric.
301 *
302 * \note Setting labels *after* registration will lead to a "bad time"
303 *
304 * Example Usage:
305 * \code
306 * PROMETHEUS_METRIC_SET_LABEL(
307 * test_gauge_child_two, 0, "key_one", "value_two");
308 * PROMETHEUS_METRIC_SET_LABEL(
309 * test_gauge_child_two, 1, "key_two", "value_two");
310 * \endcode
311 *
312 * \param metric The metric to set the label on
313 * \param label Position of the label to set
314 * \param n Name of the label
315 * \param v Value of the label
316 */
317#define PROMETHEUS_METRIC_SET_LABEL(metric, label, n, v) do { \
318 ast_assert((label) < PROMETHEUS_MAX_LABELS); \
319 ast_copy_string((metric)->labels[(label)].name, (n), sizeof((metric)->labels[(label)].name)); \
320 ast_copy_string((metric)->labels[(label)].value, (v), sizeof((metric)->labels[(label)].value)); \
321} while (0)
322
323/*!
324 * \brief Destroy a metric and all its children
325 *
326 * \note If you still want the children, make sure you remove the head of the
327 * \c children list first.
328 *
329 * \param metric The metric to destroy
330 */
331void prometheus_metric_free(struct prometheus_metric *metric);
332
333/*!
334 * \brief Create a malloc'd counter metric
335 *
336 * \note The metric must be registered after creation
337 *
338 * \param name The name of the metric
339 * \param help Help text for the metric
340 *
341 * \retval prometheus_metric on success
342 * \retval NULL on error
343 */
345 const char *help);
346
347/*!
348 * \brief Create a malloc'd gauge metric
349 *
350 * \note The metric must be registered after creation
351 *
352 * \param name The name of the metric
353 * \param help Help text for the metric
354 *
355 * \retval prometheus_metric on success
356 * \retval NULL on error
357 */
359 const char *help);
360
361/*!
362 * \brief Convert a metric (and its children) into Prometheus compatible text
363 *
364 * \param metric The metric to convert to a string
365 * \param[out] output The \c ast_str string to populate with the metric(s)
366 */
368 struct ast_str **output);
369
370/*!
371 * \brief Defines a callback that will be invoked when the HTTP route is called
372 *
373 * This callback presents the second way of passing metrics to a Prometheus
374 * server. For metrics that are generated often or whose value needs to be
375 * stored, metrics can be created and registered. For metrics that can be
376 * obtained "on-the-fly", this mechanism is preferred. When the HTTP route is
377 * queried by prometheus, the registered callbacks are invoked. The string passed
378 * to the callback should be populated with stack-allocated metrics using
379 * \c prometheus_metric_to_string.
380 *
381 * Example Usage:
382 * \code
383 * static void prometheus_metric_callback(struct ast_str **output)
384 * {
385 * struct prometheus_metric test_counter =
386 * PROMETHEUS_METRIC_STATIC_INITIALIZATION(
387 * PROMETHEUS_METRIC_COUNTER,
388 * "test_counter",
389 * "A test counter",
390 * NULL);
391 *
392 * prometheus_metric_to_string(&test_counter, output);
393 * }
394 *
395 * static void load_module(void)
396 * {
397 * struct prometheus_callback callback = {
398 * .name = "test_callback",
399 * .callback_fn = &prometheus_metric_callback,
400 * };
401 *
402 * prometheus_callback_register(&callback);
403 * }
404 *
405 * \endcode
406 *
407 */
409 /*!
410 * \brief The name of our callback (always useful for debugging)
411 */
412 const char *name;
413 /*!
414 * \brief The callback function to invoke
415 */
416 void (* callback_fn)(struct ast_str **output);
417};
418
419/*!
420 * Register a metric for collection
421 *
422 * \param metric The metric to register
423 *
424 * \retval 0 success
425 * \retval -1 error
426 */
428
429/*!
430 * \brief Remove a registered metric
431 *
432 * \param metric The metric to unregister
433 *
434 * \note Unregistering also destroys the metric, if found
435 *
436 * \retval 0 The metric was found, unregistered, and disposed of
437 * \retval -1 The metric was not found
438 */
440
441/*!
442 * The current number of registered metrics
443 *
444 * \retval The current number of registered metrics
445 */
447
448/*!
449 * Register a metric callback
450 *
451 * \param callback The callback to register
452 *
453 * \retval 0 success
454 * \retval -1 error
455 */
457
458/*!
459 * \brief Remove a registered callback
460 *
461 * \param callback The callback to unregister
462 */
464
465/*!
466 * \brief Register a metrics provider
467 *
468 * \param provider The provider function table to register
469 */
471
472/*!
473 * \brief Retrieve the current configuration of the module
474 *
475 * config is an AO2 ref counted object
476 *
477 * \note
478 * This should primarily be done for testing purposes.
479 *
480 * \retval NULL on error
481 * \retval config on success
482 */
484
485/*!
486 * \brief Set the configuration for the module
487 *
488 * This is not a ref-stealing function. The reference count to \c config
489 * will be incremented as a result of calling this method.
490 *
491 * \note
492 * This should primarily be done for testing purposes
493 */
495
496/*!
497 * \brief Allocate a new configuration object
498 *
499 * The returned object is an AO2 ref counted object
500 *
501 * \retval NULL on error
502 * \retval config on success
503 */
505
506#endif /* #ifndef RES_PROMETHEUS_H__ */
static struct prometheus_metrics_provider provider
Definition bridges.c:207
static const char config[]
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
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).
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
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.
#define AST_STRING_FIELD(name)
Declare a string field.
Structure for mutex and tracking information.
Definition lock.h:142
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 channels_detail_metrics_enabled
Whether or not channel detail metrics are enabled.
unsigned int bridges_detail_metrics_enabled
Whether or not bridge detail metrics are enabled.
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.
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::@288 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.
struct prometheus_metric::@287 children
A list of children metrics.
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.