Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
res_prometheus.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
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/*!
20 * \file
21 * \brief Core Prometheus metrics API
22 *
23 * \author Matt Jordan <mjordan@digium.com>
24 *
25 */
26
27/*** MODULEINFO
28 <use>pjproject</use>
29 <use type="module">res_pjsip</use>
30 <use type="module">res_pjsip_outbound_registration</use>
31 <support_level>extended</support_level>
32 ***/
33
34/*** DOCUMENTATION
35 <configInfo name="res_prometheus" language="en_US">
36 <synopsis>Resource for integration with Prometheus</synopsis>
37 <configFile name="prometheus.conf">
38 <configObject name="general">
39 <synopsis>General settings.</synopsis>
40 <description>
41 <para>
42 The <emphasis>general</emphasis> settings section contains information
43 to configure Asterisk to serve up statistics for a Prometheus server.
44 </para>
45 <note>
46 <para>You must enable Asterisk's HTTP server in <filename>http.conf</filename>
47 for this module to function properly!
48 </para>
49 </note>
50 </description>
51 <configOption name="enabled" default="no">
52 <synopsis>Enable or disable Prometheus statistics.</synopsis>
53 <description>
54 <enumlist>
55 <enum name="no" />
56 <enum name="yes" />
57 </enumlist>
58 </description>
59 </configOption>
60 <configOption name="core_metrics_enabled" default="yes">
61 <synopsis>Enable or disable core metrics.</synopsis>
62 <description>
63 <para>
64 Core metrics show various properties of the Asterisk system, including
65 how the binary was built, the version, uptime, last reload time, etc.
66 Generally, these options are harmless and should always be enabled.
67 This option mostly exists to disable output of all options for testing
68 purposes, as well as for those foolish souls who really don't care
69 what version of Asterisk they're running.
70 </para>
71 <enumlist>
72 <enum name="no" />
73 <enum name="yes" />
74 </enumlist>
75 </description>
76 </configOption>
77 <configOption name="uri" default="metrics">
78 <synopsis>The HTTP URI to serve metrics up on.</synopsis>
79 </configOption>
80 <configOption name="auth_username">
81 <synopsis>Username to use for Basic Auth.</synopsis>
82 <description>
83 <para>
84 If set, use Basic Auth to authenticate requests to the route
85 specified by <replaceable>uri</replaceable>. Note that you
86 will need to configure your Prometheus server with the
87 appropriate auth credentials.
88 </para>
89 <para>
90 If set, <replaceable>auth_password</replaceable> must also
91 be set appropriately.
92 </para>
93 <warning>
94 <para>
95 It is highly recommended to set up Basic Auth. Failure
96 to do so may result in useful information about your
97 Asterisk system being made easily scrapable by the
98 wide world. Consider yourself duly warned.
99 </para>
100 </warning>
101 </description>
102 </configOption>
103 <configOption name="auth_password">
104 <synopsis>Password to use for Basic Auth.</synopsis>
105 <description>
106 <para>
107 If set, this is used in conjunction with <replaceable>auth_username</replaceable>
108 to require Basic Auth for all requests to the Prometheus metrics. Note that
109 setting this without <replaceable>auth_username</replaceable> will not
110 do anything.
111 </para>
112 </description>
113 </configOption>
114 <configOption name="auth_realm" default="Asterisk Prometheus Metrics">
115 <synopsis>Auth realm used in challenge responses</synopsis>
116 </configOption>
117 </configObject>
118 </configFile>
119 </configInfo>
120***/
121
122#define AST_MODULE_SELF_SYM __internal_res_prometheus_self
123
124#include "asterisk.h"
125
126#include "asterisk/module.h"
127#include "asterisk/vector.h"
128#include "asterisk/http.h"
130#include "asterisk/ast_version.h"
131#include "asterisk/buildinfo.h"
133
135
136/*! \brief Lock that protects data structures during an HTTP scrape */
138
140
142
144
145static struct timeval last_scrape;
146
147/*! \brief The actual module config */
148struct module_config {
149 /*! \brief General settings */
151};
152
153static struct aco_type global_option = {
154 .type = ACO_GLOBAL,
155 .name = "general",
156 .item_offset = offsetof(struct module_config, general),
157 .category_match = ACO_WHITELIST_EXACT,
158 .category = "general",
159};
160
162
164 .filename = "prometheus.conf",
165 .types = ACO_TYPES(&global_option),
166};
167
168/*! \brief The module configuration container */
170
171static void *module_config_alloc(void);
172static int prometheus_config_pre_apply(void);
173static void prometheus_config_post_apply(void);
174/*! \brief Register information about the configs being processed by this module */
176 .files = ACO_FILES(&prometheus_conf),
177 .pre_apply_config = prometheus_config_pre_apply,
178 .post_apply_config = prometheus_config_post_apply,
179);
180
181#define CORE_PROPERTIES_HELP "Asterisk instance properties. The value of this will always be 1."
182
183#define CORE_UPTIME_HELP "Asterisk instance uptime in seconds."
184
185#define CORE_LAST_RELOAD_HELP "Time since last Asterisk reload in seconds."
186
187#define CORE_METRICS_SCRAPE_TIME_HELP "Total time taken to collect metrics, in milliseconds"
188
189static void get_core_uptime_cb(struct prometheus_metric *metric)
190{
191 struct timeval now = ast_tvnow();
192 int64_t duration = ast_tvdiff_sec(now, ast_startuptime);
193
194 snprintf(metric->value, sizeof(metric->value), "%" PRIu64, duration);
195}
196
197static void get_last_reload_cb(struct prometheus_metric *metric)
198{
199 struct timeval now = ast_tvnow();
200 int64_t duration = ast_tvdiff_sec(now, ast_lastreloadtime);
201
202 snprintf(metric->value, sizeof(metric->value), "%" PRIu64, duration);
203}
204
205/*!
206 * \brief The scrape duration metric
207 *
208 * \details
209 * This metric is special in that it should never be registered.
210 * Instead, the HTTP callback function that walks the metrics will
211 * always populate this metric explicitly if core metrics
212 * are enabled.
213 */
217 "asterisk_core_scrape_time_ms",
219 NULL);
220
221#define METRIC_CORE_PROPS_ARRAY_INDEX 0
222/*!
223 * \brief Core metrics to scrape
224 */
228 "asterisk_core_properties",
230 NULL),
233 "asterisk_core_uptime_seconds",
238 "asterisk_core_last_reload_seconds",
241};
242
243/*!
244 * \internal
245 * \brief Compare two metrics to see if their name / labels / values match
246 *
247 * \param left The first metric to compare
248 * \param right The second metric to compare
249 *
250 * \retval 0 The metrics are not the same
251 * \retval 1 The metrics are the same
252 */
254 struct prometheus_metric *right)
255{
256 int i;
257 ast_debug(5, "Comparison: Names %s == %s\n", left->name, right->name);
258 if (strcmp(left->name, right->name)) {
259 return 0;
260 }
261
262 for (i = 0; i < PROMETHEUS_MAX_LABELS; i++) {
263 ast_debug(5, "Comparison: Label %d Names %s == %s\n", i,
264 left->labels[i].name, right->labels[i].name);
265 if (strcmp(left->labels[i].name, right->labels[i].name)) {
266 return 0;
267 }
268
269 ast_debug(5, "Comparison: Label %d Values %s == %s\n", i,
270 left->labels[i].value, right->labels[i].value);
271 if (strcmp(left->labels[i].value, right->labels[i].value)) {
272 return 0;
273 }
274 }
275
276 ast_debug(5, "Copmarison: %s (%p) is equal to %s (%p)\n",
277 left->name, left, right->name, right);
278 return 1;
279}
280
282{
284
285 return AST_VECTOR_SIZE(&metrics);
286}
287
289{
291 int i;
292
293 if (!metric) {
294 return -1;
295 }
296
297 for (i = 0; i < AST_VECTOR_SIZE(&metrics); i++) {
298 struct prometheus_metric *existing = AST_VECTOR_GET(&metrics, i);
299 struct prometheus_metric *child;
300
301 if (prometheus_metric_cmp(existing, metric)) {
303 "Refusing registration of existing Prometheus metric: %s\n",
304 metric->name);
305 return -1;
306 }
307
308 AST_LIST_TRAVERSE(&existing->children, child, entry) {
309 if (prometheus_metric_cmp(child, metric)) {
311 "Refusing registration of existing Prometheus metric: %s\n",
312 metric->name);
313 return -1;
314 }
315 }
316
317 if (!strcmp(metric->name, existing->name)) {
318 ast_debug(3, "Nesting metric '%s' as child (%p) under existing (%p)\n",
319 metric->name, metric, existing);
320 AST_LIST_INSERT_TAIL(&existing->children, metric, entry);
321 return 0;
322 }
323 }
324
325 ast_debug(3, "Tracking new root metric '%s'\n", metric->name);
326 if (AST_VECTOR_APPEND(&metrics, metric)) {
327 ast_log(AST_LOG_WARNING, "Failed to grow vector to make room for Prometheus metric: %s\n",
328 metric->name);
329 return -1;
330 }
331
332 return 0;
333}
334
336{
337 if (!metric) {
338 return -1;
339 }
340
341 {
343 int i;
344
345 ast_debug(3, "Removing metric '%s'\n", metric->name);
346 for (i = 0; i < AST_VECTOR_SIZE(&metrics); i++) {
347 struct prometheus_metric *existing = AST_VECTOR_GET(&metrics, i);
348
349 /*
350 * If this is a complete match, remove the matching metric
351 * and place its children back into the list
352 */
353 if (prometheus_metric_cmp(existing, metric)) {
354 struct prometheus_metric *root;
355
357 root = AST_LIST_REMOVE_HEAD(&existing->children, entry);
358 if (root) {
359 struct prometheus_metric *child;
360 AST_LIST_TRAVERSE_SAFE_BEGIN(&existing->children, child, entry) {
362 AST_LIST_INSERT_TAIL(&root->children, child, entry);
363 }
365 AST_VECTOR_INSERT_AT(&metrics, i, root);
366 }
367 prometheus_metric_free(existing);
368 return 0;
369 }
370
371 /*
372 * Name match, but labels don't match. Find the matching entry with
373 * labels and remove it along with all of its children
374 */
375 if (!strcmp(existing->name, metric->name)) {
376 struct prometheus_metric *child;
377
378 AST_LIST_TRAVERSE_SAFE_BEGIN(&existing->children, child, entry) {
379 if (prometheus_metric_cmp(child, metric)) {
382 return 0;
383 }
384 }
386 }
387 }
388 }
389
390 return -1;
391}
392
394{
395 struct prometheus_metric *child;
396
397 if (!metric) {
398 return;
399 }
400
401 while ((child = AST_LIST_REMOVE_HEAD(&metric->children, entry))) {
403 }
404 ast_mutex_destroy(&metric->lock);
405
407 return;
408 } else if (metric->allocation_strategy == PROMETHEUS_METRIC_MALLOCD) {
409 ast_free(metric);
410 }
411}
412
413/*!
414 * \internal
415 * \brief Common code for creating a metric
416 *
417 * \param name The name of the metric
418 * \param help Help string to output when rendered. This must be static.
419 *
420 * \retval NULL on failure
421 */
422static struct prometheus_metric *prometheus_metric_create(const char *name, const char *help)
423{
424 struct prometheus_metric *metric = NULL;
425
426 metric = ast_calloc(1, sizeof(*metric));
427 if (!metric) {
428 return NULL;
429 }
431 ast_mutex_init(&metric->lock);
432
433 ast_copy_string(metric->name, name, sizeof(metric->name));
434 metric->help = help;
435
436 return metric;
437}
438
439struct prometheus_metric *prometheus_gauge_create(const char *name, const char *help)
440{
441 struct prometheus_metric *metric;
442
444 if (!metric) {
445 return NULL;
446 }
448
449 return metric;
450}
451
452struct prometheus_metric *prometheus_counter_create(const char *name, const char *help)
453{
454 struct prometheus_metric *metric;
455
457 if (!metric) {
458 return NULL;
459 }
461
462 return metric;
463}
464
466{
467 switch (type) {
469 return "counter";
471 return "gauge";
472 default:
473 ast_assert(0);
474 return "unknown";
475 }
476}
477
478/*!
479 * \internal
480 * \brief Render a metric to text
481 *
482 * \param metric The metric to render
483 * \param output The string buffer to append the text to
484 */
486 struct ast_str **output)
487{
488 int i;
489 int labels_exist = 0;
490
491 ast_str_append(output, 0, "%s", metric->name);
492
493 for (i = 0; i < PROMETHEUS_MAX_LABELS; i++) {
494 if (!ast_strlen_zero(metric->labels[i].name)) {
495 labels_exist = 1;
496 if (i == 0) {
497 ast_str_append(output, 0, "%s", "{");
498 } else {
499 ast_str_append(output, 0, "%s", ",");
500 }
501 ast_str_append(output, 0, "%s=\"%s\"",
502 metric->labels[i].name,
503 metric->labels[i].value);
504 }
505 }
506
507 if (labels_exist) {
508 ast_str_append(output, 0, "%s", "}");
509 }
510
511 /*
512 * If no value exists, put in a 0. That ensures we don't anger Prometheus.
513 */
514 if (ast_strlen_zero(metric->value)) {
515 ast_str_append(output, 0, " 0\n");
516 } else {
517 ast_str_append(output, 0, " %s\n", metric->value);
518 }
519}
520
522 struct ast_str **output)
523{
524 struct prometheus_metric *child;
525
526 ast_str_append(output, 0, "# HELP %s %s\n", metric->name, metric->help);
527 ast_str_append(output, 0, "# TYPE %s %s\n", metric->name,
529 prometheus_metric_full_to_string(metric, output);
530 AST_LIST_TRAVERSE(&metric->children, child, entry) {
532 }
533}
534
536{
538
539 if (!callback || !callback->callback_fn || ast_strlen_zero(callback->name)) {
540 return -1;
541 }
542
543 AST_VECTOR_APPEND(&callbacks, callback);
544
545 return 0;
546}
547
549{
551 int i;
552
553 for (i = 0; i < AST_VECTOR_SIZE(&callbacks); i++) {
555
556 if (!strcmp(callback->name, entry->name)) {
558 return;
559 }
560 }
561}
562
563static void scrape_metrics(struct ast_str **response)
564{
565 int i;
566
567 for (i = 0; i < AST_VECTOR_SIZE(&callbacks); i++) {
568 struct prometheus_callback *callback = AST_VECTOR_GET(&callbacks, i);
569
570 if (!callback) {
571 continue;
572 }
573
574 callback->callback_fn(response);
575 }
576
577 for (i = 0; i < AST_VECTOR_SIZE(&metrics); i++) {
578 struct prometheus_metric *metric = AST_VECTOR_GET(&metrics, i);
579
580 if (!metric) {
581 continue;
582 }
583
584 ast_mutex_lock(&metric->lock);
585 if (metric->get_metric_value) {
586 metric->get_metric_value(metric);
587 }
588 prometheus_metric_to_string(metric, response);
589 ast_mutex_unlock(&metric->lock);
590 }
591}
592
594 const struct ast_http_uri *urih, const char *uri, enum ast_http_method method,
595 struct ast_variable *get_params, struct ast_variable *headers)
596{
598 struct ast_str *response = NULL;
599 struct timeval start;
600 struct timeval end;
601
602 /* If there is no module config or we're not enabled, we can't handle requests */
603 if (!mod_cfg || !mod_cfg->general->enabled) {
604 goto err503;
605 }
606
607 if (!ast_strlen_zero(mod_cfg->general->auth_username)) {
608 struct ast_http_auth *http_auth;
609
610 http_auth = ast_http_get_auth(headers);
611 if (!http_auth) {
612 goto err401;
613 }
614
615 if (strcmp(http_auth->userid, mod_cfg->general->auth_username)) {
616 ast_debug(5, "Invalid username provided for auth request: %s\n", http_auth->userid);
617 ao2_ref(http_auth, -1);
618 goto err401;
619 }
620
621 if (strcmp(http_auth->password, mod_cfg->general->auth_password)) {
622 ast_debug(5, "Invalid password provided for auth request: %s\n", http_auth->password);
623 ao2_ref(http_auth, -1);
624 goto err401;
625 }
626
627 ao2_ref(http_auth, -1);
628 }
629
630 response = ast_str_create(512);
631 if (!response) {
632 goto err500;
633 }
634
635 start = ast_tvnow();
636
638
639 last_scrape = start;
640 scrape_metrics(&response);
641
642 if (mod_cfg->general->core_metrics_enabled) {
643 int64_t duration;
644
645 end = ast_tvnow();
646 duration = ast_tvdiff_ms(end, start);
647 snprintf(core_scrape_metric.value,
649 "%" PRIu64,
650 duration);
652 }
654
655 ast_http_send(ser, method, 200, "OK", NULL, response, 0, 0);
656
657 return 0;
658
659err401:
660 {
661 struct ast_str *auth_challenge_headers;
662
663 auth_challenge_headers = ast_str_create(128);
664 if (!auth_challenge_headers) {
665 goto err500;
666 }
667 ast_str_append(&auth_challenge_headers, 0,
668 "WWW-Authenticate: Basic realm=\"%s\"\r\n",
669 mod_cfg->general->auth_realm);
670 /* ast_http_send takes ownership of the ast_str */
671 ast_http_send(ser, method, 401, "Unauthorized", auth_challenge_headers, NULL, 0, 1);
672 }
673 ast_free(response);
674 return 0;
675err503:
676 ast_http_send(ser, method, 503, "Service Unavailable", NULL, NULL, 0, 1);
677 ast_free(response);
678 return 0;
679err500:
680 ast_http_send(ser, method, 500, "Server Error", NULL, NULL, 0, 1);
681 ast_free(response);
682 return 0;
683}
684
686{
687 struct ast_str *response;
688
689 response = ast_str_create(512);
690 if (!response) {
691 return NULL;
692 }
693
695 scrape_metrics(&response);
697
698 return response;
699}
700
702{
703 int64_t duration;
704
705 if (sscanf(core_scrape_metric.value, "%" PRIu64, &duration) != 1) {
706 return -1;
707 }
708
709 return duration;
710}
711
713{
715
716 return last_scrape;
717}
718
719static void prometheus_general_config_dtor(void *obj)
720{
721 struct prometheus_general_config *config = obj;
722
724}
725
727{
729
731 if (!config || ast_string_field_init(config, 32)) {
732 return NULL;
733 }
734
735 return config;
736}
737
739{
741
742 if (!mod_cfg) {
743 return NULL;
744 }
745 ao2_bump(mod_cfg->general);
746
747 return mod_cfg->general;
748}
749
751{
753
754 if (!mod_cfg) {
755 return;
756 }
757 ao2_replace(mod_cfg->general, config);
759}
760
761
762/*! \brief Configuration object destructor */
763static void module_config_dtor(void *obj)
764{
765 struct module_config *config = obj;
766
767 if (config->general) {
768 ao2_ref(config->general, -1);
769 }
770}
771
772/*! \brief Module config constructor */
773static void *module_config_alloc(void)
774{
775 struct module_config *config;
776
778 if (!config) {
779 return NULL;
780 }
781
783 if (!config->general) {
784 ao2_ref(config, -1);
785 config = NULL;
786 }
787
788 return config;
789}
790
792 .description = "Prometheus Metrics URI",
793 .callback = http_callback,
794 .has_subtree = 1,
795 .data = NULL,
796 .key = __FILE__,
797};
798
799/*!
800 * \brief Pre-apply callback for the config framework.
801 *
802 * This validates that required fields exist and are populated.
803 */
805{
806 struct module_config *config = aco_pending_config(&cfg_info);
807
808 if (!config->general->enabled) {
809 /* If we're not enabled, we don't care about anything else */
810 return 0;
811 }
812
813 if (!ast_strlen_zero(config->general->auth_username)
814 && ast_strlen_zero(config->general->auth_password)) {
815 ast_log(AST_LOG_ERROR, "'auth_username' set without a corresponding 'auth_password'\n");
816 return -1;
817 }
818
819 return 0;
820}
821
822/*!
823 * \brief Post-apply callback for the config framework.
824 *
825 * This sets any run-time information derived from the configuration
826 */
828{
830 int i;
831
832 /* We can get away with this as the lifetime of the URI
833 * registered with the HTTP core is contained within
834 * the lifetime of the module configuration
835 */
836 prometheus_uri.uri = mod_cfg->general->uri;
837
838 /* Re-register the core metrics */
839 for (i = 0; i < ARRAY_LEN(core_metrics); i++) {
841 }
842 if (mod_cfg->general->core_metrics_enabled) {
843 char eid_str[32];
844 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
845
847
849 1, "version", ast_get_version());
851 2, "build_options", ast_get_build_opts());
853 3, "build_date", ast_build_date);
855 4, "build_os", ast_build_os);
857 5, "build_kernel", ast_build_kernel);
859 6, "build_host", ast_build_hostname);
862 "%d", 1);
863
864 for (i = 0; i < ARRAY_LEN(core_metrics); i++) {
865 PROMETHEUS_METRIC_SET_LABEL(&core_metrics[i], 0, "eid", eid_str);
867 }
868 }
869}
870
872{
874}
875
876static int unload_module(void)
877{
879 int i;
880
882
883 for (i = 0; i < AST_VECTOR_SIZE(&providers); i++) {
885
886 if (!provider->unload_cb) {
887 continue;
888 }
889
891 }
892
893 for (i = 0; i < AST_VECTOR_SIZE(&metrics); i++) {
894 struct prometheus_metric *metric = AST_VECTOR_GET(&metrics, i);
895
897 }
899
901
903
904 aco_info_destroy(&cfg_info);
906
907 return 0;
908}
909
910static int reload_module(void) {
912 int i;
913 struct prometheus_general_config *general_config;
914
916 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
917 return -1;
918 }
919
920 /* Our config should be all reloaded now */
921 general_config = prometheus_general_config_get();
922 for (i = 0; i < AST_VECTOR_SIZE(&providers); i++) {
924
925 if (!provider->reload_cb) {
926 continue;
927 }
928
929 if (provider->reload_cb(general_config)) {
930 ast_log(AST_LOG_WARNING, "Failed to reload metrics provider %s\n", provider->name);
931 ao2_ref(general_config, -1);
932 return -1;
933 }
934 }
935 ao2_ref(general_config, -1);
936
938 ast_log(AST_LOG_WARNING, "Failed to re-register Prometheus Metrics URI during reload\n");
939 return -1;
940 }
941
942 return 0;
943}
944
945static int load_module(void)
946{
948
949 if (AST_VECTOR_INIT(&metrics, 64)) {
950 goto cleanup;
951 }
952
953 if (AST_VECTOR_INIT(&callbacks, 8)) {
954 goto cleanup;
955 }
956
957 if (AST_VECTOR_INIT(&providers, 8)) {
958 goto cleanup;
959 }
960
961 if (aco_info_init(&cfg_info)) {
962 goto cleanup;
963 }
965 aco_option_register(&cfg_info, "core_metrics_enabled", ACO_EXACT, global_options, "yes", OPT_BOOL_T, 1, FLDSET(struct prometheus_general_config, core_metrics_enabled));
967 aco_option_register(&cfg_info, "auth_username", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct prometheus_general_config, auth_username));
968 aco_option_register(&cfg_info, "auth_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct prometheus_general_config, auth_password));
969 aco_option_register(&cfg_info, "auth_realm", ACO_EXACT, global_options, "Asterisk Prometheus Metrics", OPT_STRINGFIELD_T, 0, STRFLDSET(struct prometheus_general_config, auth_realm));
970 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
971 goto cleanup;
972 }
973
974 if (cli_init()
977 || bridge_metrics_init()) {
978 goto cleanup;
979 }
980
981 if(ast_module_check("res_pjsip_outbound_registration.so")) {
982 /* Call a local function, used in the core prometheus code only */
984 goto cleanup;
985 }
986
988 goto cleanup;
989 }
990
992
993cleanup:
995 aco_info_destroy(&cfg_info);
999
1001}
1002
1003
1005 .support_level = AST_MODULE_SUPPORT_EXTENDED,
1006 .load = load_module,
1007 .unload = unload_module,
1009 .load_pri = AST_MODPRI_DEFAULT,
1010#ifdef HAVE_PJPROJECT
1011 /* This module explicitly calls into res_pjsip if Asterisk is built with PJSIP support, so they are required. */
1012 .requires = "res_pjsip",
1013 .optional_modules = "res_pjsip_outbound_registration",
1014#endif
ast_mutex_t lock
Definition: app_sla.c:331
Asterisk version information.
const char * ast_get_build_opts(void)
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static struct prometheus_metrics_provider provider
Definition: bridges.c:201
int bridge_metrics_init(void)
Initialize bridge metrics.
Definition: bridges.c:206
const char * ast_build_os
Definition: buildinfo.c:32
const char * ast_build_hostname
Definition: buildinfo.c:29
const char * ast_build_date
Definition: buildinfo.c:33
const char * ast_build_kernel
Definition: buildinfo.c:30
static const char type[]
Definition: chan_ooh323.c:109
static const char config[]
Definition: chan_ooh323.c:111
int channel_metrics_init(void)
Initialize channel metrics.
Definition: channels.c:241
Configuration option-handling.
@ ACO_EXACT
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ACO_FILES(...)
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
@ ACO_GLOBAL
@ ACO_WHITELIST_EXACT
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
static int enabled
Definition: dnsmgr.c:91
char * end
Definition: eagi_proxy.c:73
static const char name[]
Definition: format_mp3.c:68
Support for Private Asterisk HTTP Servers.
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
Definition: http.c:459
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:58
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:708
struct ast_http_auth * ast_http_get_auth(struct ast_variable *headers)
Get HTTP authentication information from headers.
Definition: http.c:1582
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:676
#define AST_LOG_WARNING
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:589
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
int ast_module_check(const char *name)
Check if module with the name given is loaded.
Definition: loader.c:2823
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_DEFAULT
Definition: module.h:346
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct timeval ast_lastreloadtime
Definition: asterisk.c:337
struct timeval ast_startuptime
Definition: asterisk.c:336
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
int pjsip_outbound_registration_metrics_init(void)
Initialize PJSIP outbound registration metrics.
Prometheus Metric Internal API.
int cli_init(void)
Initialize CLI command.
int endpoint_metrics_init(void)
Initialize endpoint metrics.
static int reload(void)
const char * method
Definition: res_pjsip.c:1279
#define CORE_LAST_RELOAD_HELP
int prometheus_metric_unregister(struct prometheus_metric *metric)
Remove a registered metric.
struct aco_type * global_options[]
static struct timeval last_scrape
struct @468 callbacks
int prometheus_metric_register(struct prometheus_metric *metric)
int prometheus_metric_registered_count(void)
CONFIG_INFO_STANDARD(cfg_info, global_config, module_config_alloc,.files=ACO_FILES(&prometheus_conf),.pre_apply_config=prometheus_config_pre_apply,.post_apply_config=prometheus_config_post_apply,)
Register information about the configs being processed by this module.
void prometheus_general_config_set(struct prometheus_general_config *config)
Set the configuration for the module.
static void prometheus_metric_full_to_string(struct prometheus_metric *metric, struct ast_str **output)
static void get_core_uptime_cb(struct prometheus_metric *metric)
struct @467 metrics
static int http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static void prometheus_general_config_dtor(void *obj)
struct ast_str * prometheus_scrape_to_string(void)
Get the raw output of what a scrape would produce.
static void prometheus_config_post_apply(void)
Post-apply callback for the config framework.
static ast_mutex_t scrape_lock
Lock that protects data structures during an HTTP scrape.
static struct prometheus_metric core_metrics[]
Core metrics to scrape.
static AO2_GLOBAL_OBJ_STATIC(global_config)
The module configuration container.
struct timeval prometheus_last_scrape_time_get(void)
Retrieve the timestamp when the last scrape occurred.
struct prometheus_metric * prometheus_gauge_create(const char *name, const char *help)
Create a malloc'd gauge metric.
static int reload_module(void)
struct @469 providers
void prometheus_callback_unregister(struct prometheus_callback *callback)
Remove a registered callback.
static void get_last_reload_cb(struct prometheus_metric *metric)
static struct prometheus_metric core_scrape_metric
The scrape duration metric.
static int prometheus_metric_cmp(struct prometheus_metric *left, struct prometheus_metric *right)
static const char * prometheus_metric_type_to_string(enum prometheus_metric_type type)
#define CORE_UPTIME_HELP
static void module_config_dtor(void *obj)
Configuration object destructor.
void * prometheus_general_config_alloc(void)
Allocate a new configuration object.
int64_t prometheus_last_scrape_duration_get(void)
Retrieve the amount of time it took to perform the last scrape.
static struct ast_http_uri prometheus_uri
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.
static int load_module(void)
struct aco_file prometheus_conf
static int prometheus_config_pre_apply(void)
Pre-apply callback for the config framework.
void prometheus_metrics_provider_register(const struct prometheus_metrics_provider *provider)
Register a metrics provider.
static int unload_module(void)
#define CORE_PROPERTIES_HELP
static void * module_config_alloc(void)
Module config constructor.
#define CORE_METRICS_SCRAPE_TIME_HELP
int prometheus_callback_register(struct prometheus_callback *callback)
struct prometheus_general_config * prometheus_general_config_get(void)
Retrieve the current configuration of the module.
static struct aco_type global_option
static void scrape_metrics(struct ast_str **response)
#define METRIC_CORE_PROPS_ARRAY_INDEX
static struct prometheus_metric * prometheus_metric_create(const char *name, const char *help)
struct prometheus_metric * prometheus_counter_create(const char *name, const char *help)
Create a malloc'd counter metric.
Asterisk Prometheus Metrics.
#define PROMETHEUS_METRIC_SET_LABEL(metric, label, n, v)
Convenience macro for setting a label / value in a metric.
#define PROMETHEUS_METRIC_STATIC_INITIALIZATION(mtype, n, h, cb)
Convenience macro for initializing a metric on the stack.
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.
#define PROMETHEUS_MAX_LABELS
How many labels a single metric can have.
@ PROMETHEUS_METRIC_ALLOCD
The metric was allocated on the stack.
@ PROMETHEUS_METRIC_MALLOCD
The metric was allocated on the heap.
#define NULL
Definition: resample.c:96
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
enum aco_type_t type
HTTP authentication information.
Definition: http.h:125
char * password
Definition: http.h:129
char * userid
Definition: http.h:127
Definition of a URI handler.
Definition: http.h:102
const char * description
Definition: http.h:104
const char * uri
Definition: http.h:105
Support for dynamic strings.
Definition: strings.h:623
describes a server instance
Definition: tcptls.h:150
Structure for variables, used for configurations and for channel variables.
Definition: search.h:40
The configuration settings for this module.
Definition: cdr.c:264
struct prometheus_general_config * general
General settings.
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.
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.
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.
int value
Definition: syslog.c:37
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:73
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2839
#define ARRAY_LEN(a)
Definition: utils.h:666
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_INSERT_AT(vec, idx, elem)
Insert an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:338
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680