28 #include <curl/curl.h> 35 #define CATEGORY "/res/prometheus/" 47 curl_easy_cleanup(ptr);
57 #define GLOBAL_USERAGENT "asterisk-libcurl-agent/1.0" 80 curl = curl_easy_init();
85 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
86 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
88 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
89 curl_easy_setopt(curl, CURLOPT_URL,
server_uri);
96 struct ast_str **buffer = userdata;
97 size_t realsize = size * nmemb;
104 memcpy(rawdata, contents, realsize);
105 rawdata[realsize] = 0;
114 strcpy(metric->
value,
"2");
136 info->name = __func__;
138 info->summary =
"Test value generation/respecting in metrics";
140 "Metrics have two ways to provide values when the HTTP callback\n" 142 "1. By using the direct value that resides in the metric\n" 143 "2. By providing a callback function to specify the value\n" 144 "This test verifies that both function appropriately when the\n" 145 "HTTP callback is called.";
163 strcpy(test_counter_one.
value,
"1");
167 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
168 res = curl_easy_perform(curl);
169 if (res != CURLE_OK) {
172 goto metric_values_cleanup;
177 "# HELP test_counter_one A test counter\n" 178 "# TYPE test_counter_one counter\n" 179 "test_counter_one 1\n" 180 "# HELP test_counter_two A test counter\n" 181 "# TYPE test_counter_two counter\n" 182 "test_counter_two 2\n") !=
NULL, result, metric_values_cleanup);
184 metric_values_cleanup:
208 .
name =
"test_callback",
214 info->name = __func__;
216 info->summary =
"Test registration of callbacks";
218 "This test covers callback registration. It registers\n" 219 "a callback that is invoked when an HTTP request is made,\n" 220 "and it verifies that during said callback the output to\n" 221 "the response string is correctly appended to. It also verifies\n" 222 "that unregistered callbacks are not invoked.";
242 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
243 res = curl_easy_perform(curl);
244 if (res != CURLE_OK) {
251 "# HELP test_counter A test counter\n" 252 "# TYPE test_counter counter\n" 253 "test_counter 0\n") !=
NULL);
275 info->name = __func__;
277 info->summary =
"Test registration of metrics";
279 "This test covers the following registration scenarios:\n" 280 "- Nominal registration of simple metrics\n" 281 "- Registration of metrics with different allocation strategies\n" 282 "- Nested metrics with label families\n" 283 "- Off nominal registration with simple name collisions\n" 284 "- Off nominal registration with label collisions";
295 ast_test_validate(
test, test_gauge !=
NULL);
301 ast_test_validate_cleanup(
test, test_gauge_child_one !=
NULL, result, metric_register_cleanup);
305 ast_test_validate_cleanup(
test, test_gauge_child_two !=
NULL, result, metric_register_cleanup);
311 ast_test_validate_cleanup(
test, test_gauge->children.first == test_gauge_child_one, result, metric_register_cleanup);
312 ast_test_validate_cleanup(
test, test_gauge->children.last == test_gauge_child_two, result, metric_register_cleanup);
316 ast_test_validate_cleanup(
test, bad_metric !=
NULL, result, metric_register_cleanup);
323 ast_test_validate_cleanup(
test, bad_metric !=
NULL, result, metric_register_cleanup);
332 test_gauge_child_two =
NULL;
340 test_gauge_child_one =
NULL;
349 metric_register_cleanup:
375 info->name = __func__;
377 info->summary =
"Test formatting of counters";
379 "This test covers the formatting of printed counters";
398 "# HELP test_counter A test counter\n" 399 "# TYPE test_counter counter\n" 401 "test_counter{key_one=\"value_one\",key_two=\"value_one\"} 0\n" 402 "test_counter{key_one=\"value_two\",key_two=\"value_two\"} 0\n") == 0);
413 info->name = __func__;
415 info->summary =
"Test creation (and destruction) of malloc'd counters";
417 "This test covers creating a counter metric and destroying\n" 418 "it. The metric should be malloc'd.";
425 ast_test_validate(
test, metric !=
NULL);
428 ast_test_validate(
test, !strcmp(metric->help,
"A test counter"));
429 ast_test_validate(
test, !strcmp(metric->name,
"test_counter"));
430 ast_test_validate(
test, !strcmp(metric->value,
""));
431 ast_test_validate(
test, metric->children.first ==
NULL);
432 ast_test_validate(
test, metric->children.last ==
NULL);
458 info->name = __func__;
460 info->summary =
"Test formatting of gauges";
462 "This test covers the formatting of printed gauges";
481 "# HELP test_gauge A test gauge\n" 482 "# TYPE test_gauge gauge\n" 484 "test_gauge{key_one=\"value_one\",key_two=\"value_one\"} 0\n" 485 "test_gauge{key_one=\"value_two\",key_two=\"value_two\"} 0\n") == 0);
496 info->name = __func__;
498 info->summary =
"Test creation (and destruction) of malloc'd gauges";
500 "This test covers creating a gauge metric and destroying\n" 501 "it. The metric should be malloc'd.";
508 ast_test_validate(
test, metric !=
NULL);
511 ast_test_validate(
test, !strcmp(metric->help,
"A test gauge"));
512 ast_test_validate(
test, !strcmp(metric->name,
"test_gauge"));
513 ast_test_validate(
test, !strcmp(metric->value,
""));
514 ast_test_validate(
test, metric->children.first ==
NULL);
515 ast_test_validate(
test, metric->children.last ==
NULL);
529 info->name = __func__;
531 info->summary =
"Test basic auth handling";
533 "This test covers authentication of requests";
556 res = curl_easy_perform(curl);
557 if (res != CURLE_OK) {
561 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
563 ast_test_validate(
test, response_code == 401);
567 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
568 curl_easy_setopt(curl, CURLOPT_USERPWD,
"matt:jordan");
569 res = curl_easy_perform(curl);
570 if (res != CURLE_OK) {
574 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
576 ast_test_validate(
test, response_code == 401);
580 curl_easy_setopt(curl, CURLOPT_USERPWD,
"foo:bar");
581 res = curl_easy_perform(curl);
582 if (res != CURLE_OK) {
586 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
588 ast_test_validate(
test, response_code == 200);
602 info->name = __func__;
604 info->summary =
"Test handling of enable/disable";
606 "When disabled, the module should return a 503.\n" 607 "This test verifies that it actually occurs.";
628 res = curl_easy_perform(curl);
629 if (res != CURLE_OK) {
633 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
635 ast_test_validate(
test, response_code == 503);
649 info->name = __func__;
651 info->summary =
"Test producing core metrics";
653 "This test covers the core metrics that are produced\n" 654 "by the basic Prometheus module.";
681 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
682 res = curl_easy_perform(curl);
683 if (res != CURLE_OK) {
709 const char *bindport;
755 if (!new_module_config) {
763 ao2_ref(new_module_config, -1);
828 .requires =
"res_prometheus",
Contains all the initialization information required to store a new test definition.
unsigned int core_metrics_enabled
Whether or not core metrics are enabled.
Asterisk main include file. File version handling, generic pbx functions.
An actual, honest to god, metric.
int prometheus_metric_register(struct prometheus_metric *metric)
Prometheus general configuration.
int ast_test_register_init(const char *category, ast_test_init_cb_t *cb)
int prometheus_callback_register(struct prometheus_callback *callback)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define CONFIG_STATUS_FILEINVALID
A metric whose value always goes up.
const char * name
The name of our callback (always useful for debugging)
#define AST_TEST_REGISTER(cb)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
static struct prometheus_general_config * config_alloc(void)
static int reload_module(void)
int prometheus_metric_unregister(struct prometheus_metric *metric)
Remove a registered metric.
static char server_uri[512]
void prometheus_metric_free(struct prometheus_metric *metric)
Destroy a metric and all its children.
#define PROMETHEUS_METRIC_STATIC_INITIALIZATION(mtype, n, h, cb)
Convenience macro for initializing a metric on the stack.
void prometheus_general_config_set(struct prometheus_general_config *config)
Set the configuration for the module.
void prometheus_metric_to_string(struct prometheus_metric *metric, struct ast_str **output)
Convert a metric (and its children) into Prometheus compatible text.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
#define PROMETHEUS_METRIC_SET_LABEL(metric, label, n, v)
Convenience macro for setting a label / value in a metric.
static void metric_values_get_counter_value_cb(struct prometheus_metric *metric)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define ast_test_status_update(a, b, c...)
static int unload_module(void)
static int load_module(void)
const ast_string_field auth_password
Auth password for Basic Auth.
#define ao2_ref(o, delta)
void ast_config_destroy(struct ast_config *config)
Destroys a config.
#define ast_malloc(len)
A wrapper for malloc()
struct prometheus_metric * prometheus_gauge_create(const char *name, const char *help)
Create a malloc'd gauge metric.
int ast_test_register_cleanup(const char *category, ast_test_cleanup_cb_t *cb)
#define CONFIG_STATUS_FILEUNCHANGED
struct prometheus_metric::@312 children
A list of children metrics.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
static void prometheus_metric_free_wrapper(void *ptr)
static CURL * get_curl_instance(void)
#define AST_TEST_UNREGISTER(cb)
static size_t curl_write_string_callback(void *contents, size_t size, size_t nmemb, void *userdata)
char value[PROMETHEUS_MAX_VALUE_LENGTH]
The current value.
void * prometheus_general_config_alloc(void)
Allocate a new configuration object.
Module has failed to load, may be in an inconsistent state.
void prometheus_callback_unregister(struct prometheus_callback *callback)
Remove a registered callback.
struct prometheus_general_config * module_config
Structure used to handle boolean flags.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
const ast_string_field uri
The HTTP URI we register ourselves to.
struct prometheus_metric * prometheus_counter_create(const char *name, const char *help)
Create a malloc'd counter metric.
static void curl_free_wrapper(void *ptr)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
int prometheus_metric_registered_count(void)
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
The metric was allocated on the heap.
static int process_config(int reload)
struct prometheus_general_config * prometheus_general_config_get(void)
Retrieve the current configuration of the module.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
static void prometheus_metric_callback(struct ast_str **output)
static int test_init_cb(struct ast_test_info *info, struct ast_test *test)
Defines a callback that will be invoked when the HTTP route is called.
static int test_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
struct ast_sockaddr bindaddr
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
const ast_string_field auth_username
Auth username for Basic Auth.
static char prefix[MAX_PREFIX]
unsigned int enabled
Whether or not the module is enabled.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
AST_TEST_DEFINE(metric_values)