122 #define AST_MODULE_SELF_SYM __internal_res_prometheus_self
131 #include "asterisk/buildinfo.h"
145 static struct timeval last_scrape;
158 .category =
"general",
176 .files = ACO_FILES(&prometheus_conf),
181 #define CORE_PROPERTIES_HELP "Asterisk instance properties. The value of this will always be 1."
183 #define CORE_UPTIME_HELP "Asterisk instance uptime in seconds."
185 #define CORE_LAST_RELOAD_HELP "Time since last Asterisk reload in seconds."
187 #define CORE_METRICS_SCRAPE_TIME_HELP "Total time taken to collect metrics, in milliseconds"
194 snprintf(metric->
value,
sizeof(metric->
value),
"%" PRIu64, duration);
202 snprintf(metric->
value,
sizeof(metric->
value),
"%" PRIu64, duration);
217 "asterisk_core_scrape_time_ms",
218 CORE_METRICS_SCRAPE_TIME_HELP,
221 #define METRIC_CORE_PROPS_ARRAY_INDEX 0
228 "asterisk_core_properties",
229 CORE_PROPERTIES_HELP,
233 "asterisk_core_uptime_seconds",
238 "asterisk_core_last_reload_seconds",
239 CORE_LAST_RELOAD_HELP,
258 if (strcmp(left->
name, right->
name)) {
263 ast_debug(5,
"Comparison: Label %d Names %s == %s\n", i,
269 ast_debug(5,
"Comparison: Label %d Values %s == %s\n", i,
276 ast_debug(5,
"Copmarison: %s (%p) is equal to %s (%p)\n",
277 left->
name, left, right->
name, right);
301 if (prometheus_metric_cmp(existing, metric)) {
302 ast_log(AST_LOG_NOTICE,
303 "Refusing registration of existing Prometheus metric: %s\n",
309 if (prometheus_metric_cmp(child, metric)) {
310 ast_log(AST_LOG_NOTICE,
311 "Refusing registration of existing Prometheus metric: %s\n",
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);
325 ast_debug(3,
"Tracking new root metric '%s'\n", metric->
name);
327 ast_log(AST_LOG_WARNING,
"Failed to grow vector to make room for Prometheus metric: %s\n",
353 if (prometheus_metric_cmp(existing, metric)) {
375 if (!strcmp(existing->
name, metric->
name)) {
379 if (prometheus_metric_cmp(child, metric)) {
404 ast_mutex_destroy(&metric->
lock);
431 ast_mutex_init(&metric->
lock);
443 metric = prometheus_metric_create(name, help);
456 metric = prometheus_metric_create(name, help);
489 int labels_exist = 0;
494 if (!ast_strlen_zero(metric->
labels[i].
name)) {
514 if (ast_strlen_zero(metric->
value)) {
528 prometheus_metric_type_to_string(metric->
type));
529 prometheus_metric_full_to_string(metric, output);
531 prometheus_metric_full_to_string(child, output);
539 if (!callback || !callback->
callback_fn || ast_strlen_zero(callback->
name)) {
556 if (!strcmp(callback->
name, entry->
name)) {
563 static void scrape_metrics(
struct ast_str **response)
584 ast_mutex_lock(&metric->
lock);
589 ast_mutex_unlock(&metric->
lock);
598 struct ast_str *response = NULL;
599 struct timeval start;
603 if (!mod_cfg || !mod_cfg->general->enabled) {
607 if (!ast_strlen_zero(mod_cfg->general->auth_username)) {
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);
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);
640 scrape_metrics(&response);
642 if (mod_cfg->general->core_metrics_enabled) {
647 snprintf(core_scrape_metric.
value,
648 sizeof(core_scrape_metric.
value),
661 struct ast_str *auth_challenge_headers;
664 if (!auth_challenge_headers) {
668 "WWW-Authenticate: Basic realm=\"%s\"\r\n",
669 mod_cfg->general->auth_realm);
671 ast_http_send(ser, method, 401,
"Unauthorized", auth_challenge_headers, NULL, 0, 1);
676 ast_http_send(ser, method, 503,
"Service Unavailable", NULL, NULL, 0, 1);
680 ast_http_send(ser, method, 500,
"Server Error", NULL, NULL, 0, 1);
695 scrape_metrics(&response);
705 if (sscanf(core_scrape_metric.
value,
"%" PRIu64, &duration) != 1) {
719 static void prometheus_general_config_dtor(
void *obj)
730 config = ao2_alloc(
sizeof(*config), prometheus_general_config_dtor);
747 return mod_cfg->general;
792 .description =
"Prometheus Metrics URI",
793 .callback = http_callback,
808 if (!config->
general->enabled) {
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");
836 prometheus_uri.uri = mod_cfg->general->uri;
839 for (i = 0; i < ARRAY_LEN(core_metrics); i++) {
842 if (mod_cfg->general->core_metrics_enabled) {
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);
860 snprintf(core_metrics[METRIC_CORE_PROPS_ARRAY_INDEX].value,
861 sizeof(core_metrics[METRIC_CORE_PROPS_ARRAY_INDEX].value),
864 for (i = 0; i < ARRAY_LEN(core_metrics); i++) {
876 static int unload_module(
void)
910 static int reload_module(
void) {
929 if (provider->
reload_cb(general_config)) {
930 ast_log(AST_LOG_WARNING,
"Failed to reload metrics provider %s\n", provider->
name);
938 ast_log(AST_LOG_WARNING,
"Failed to re-register Prometheus Metrics URI during reload\n");
945 static int load_module(
void)
1004 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Asterisk Prometheus Module",
1005 .support_level = AST_MODULE_SUPPORT_EXTENDED,
1006 .load = load_module,
1007 .unload = unload_module,
1008 .reload = reload_module,
1010 #ifdef HAVE_PJPROJECT
1012 .requires =
"res_pjsip",
1013 .optional_modules =
"res_pjsip_outbound_registration",
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
struct prometheus_metric * prometheus_counter_create(const char *name, const char *help)
Create a malloc'd counter metric.
int prometheus_metric_unregister(struct prometheus_metric *metric)
Remove a registered metric.
Asterisk main include file. File version handling, generic pbx functions.
An actual, honest to god, metric.
void(*const unload_cb)(void)
Unload callback.
int pjsip_outbound_registration_metrics_init(void)
Initialize PJSIP outbound registration metrics.
void prometheus_metrics_provider_register(const struct prometheus_metrics_provider *provider)
Register a metrics provider.
Asterisk version information.
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Prometheus general configuration.
Prometheus Metric Internal API.
struct prometheus_general_config * prometheus_general_config_get(void)
Retrieve the current configuration of the module.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
A metric whose value always goes up.
const char * ast_get_build_opts(void)
Structure for variables, used for configurations and for channel variables.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
const char * name
The name of our callback (always useful for debugging)
enum prometheus_metric_allocation_strategy allocation_strategy
How this metric was allocated.
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
enum prometheus_metric_type type
What type of metric we are.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
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 ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
void * prometheus_general_config_alloc(void)
Allocate a new configuration object.
void(* get_metric_value)(struct prometheus_metric *metric)
Callback function to obtain the metric value.
int endpoint_metrics_init(void)
Initialize endpoint metrics.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
The representation of a single configuration file to be processed.
void prometheus_callback_unregister(struct prometheus_callback *callback)
Remove a registered callback.
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.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
int cli_init(void)
Initialize CLI command.
static void module_config_dtor(void *obj)
Configuration object destructor.
#define PROMETHEUS_METRIC_STATIC_INITIALIZATION(mtype, n, h, cb)
Convenience macro for initializing a metric on the stack.
int ast_module_check(const char *name)
Check if module with the name given is loaded.
The metric was allocated on the stack.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Support for Private Asterisk HTTP Servers.
static void cleanup(void)
Clean up any old apps that we don't need any more.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
void(* callback_fn)(struct ast_str **output)
The callback function to invoke.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define PROMETHEUS_METRIC_SET_LABEL(metric, label, n, v)
Convenience macro for setting a label / value in a metric.
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
#define PROMETHEUS_MAX_LABELS
How many labels a single metric can have.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct prometheus_metric::@274 children
A list of children metrics.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
char name[PROMETHEUS_MAX_NAME_LENGTH]
The name of the label.
The configuration settings for this module.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
describes a server instance
Their was an error and no changes were applied.
int64_t prometheus_last_scrape_duration_get(void)
Retrieve the amount of time it took to perform the last scrape.
Configuration option-handling.
static int prometheus_config_pre_apply(void)
Pre-apply callback for the config framework.
Asterisk Prometheus Metrics.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Support for dynamic strings.
int prometheus_metric_registered_count(void)
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
int channel_metrics_init(void)
Initialize channel metrics.
Type for default option handler for bools (ast_true/ast_false)
struct ast_str * prometheus_scrape_to_string(void)
Get the raw output of what a scrape would produce.
struct prometheus_label labels[PROMETHEUS_MAX_LABELS]
The metric's labels.
int(*const reload_cb)(struct prometheus_general_config *config)
Reload callback.
char value[PROMETHEUS_MAX_VALUE_LENGTH]
The current value.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
const char * help
Pointer to a static string defining this metric's help text.
char value[PROMETHEUS_MAX_LABEL_LENGTH]
The value of the label.
#define ast_calloc(num, len)
A wrapper for calloc()
int prometheus_metric_register(struct prometheus_metric *metric)
static AO2_GLOBAL_OBJ_STATIC(global_config)
The module configuration container.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
Vector container support.
static struct aco_type global_option
An aco_type structure to link the "general" category to the skel_global_config type.
static struct prometheus_metric core_metrics[]
Core metrics to scrape.
struct prometheus_general_config * general
General settings.
const char * name
Handy name of the provider for debugging purposes.
char name[PROMETHEUS_MAX_NAME_LENGTH]
Our metric name.
struct ast_eid ast_eid_default
Global EID.
static ast_mutex_t scrape_lock
Lock that protects data structures during an HTTP scrape.
void prometheus_metric_to_string(struct prometheus_metric *metric, struct ast_str **output)
Convert a metric (and its children) into Prometheus compatible text.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
HTTP authentication information.
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Type information about a category-level configurable object.
static int enabled
Whether or not we are storing history.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
A function table for a metrics provider.
Definition of a URI handler.
static void * module_config_alloc(void)
Module config constructor.
ast_mutex_t lock
A lock protecting the metric value.
static void prometheus_config_post_apply(void)
Post-apply callback for the config framework.
struct ast_http_auth * ast_http_get_auth(struct ast_variable *headers)
Get HTTP authentication information from headers.
prometheus_metric_type
Prometheus metric type.
#define AST_VECTOR_INSERT_AT(vec, idx, elem)
Insert an element at a specific position in a vector, growing the vector if needed.
Type for default option handler for stringfields.
A metric whose value can bounce around like a jackrabbit.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
The metric was allocated on the heap.
ast_http_method
HTTP Request methods known by Asterisk.
void prometheus_metric_free(struct prometheus_metric *metric)
Destroy a metric and all its children.
int prometheus_callback_register(struct prometheus_callback *callback)
#define ASTERISK_GPL_KEY
The text the key() function should return.
struct ast_cdr_config * general
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
struct prometheus_metric * prometheus_gauge_create(const char *name, const char *help)
Create a malloc'd gauge metric.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
static struct prometheus_metric core_scrape_metric
The scrape duration metric.
Defines a callback that will be invoked when the HTTP route is called.
void prometheus_general_config_set(struct prometheus_general_config *config)
Set the configuration for the module.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
struct timeval prometheus_last_scrape_time_get(void)
Retrieve the timestamp when the last scrape occurred.
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.
int bridge_metrics_init(void)
Initialize bridge metrics.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.