36#include "../res/prometheus/prometheus_internal.h"
38#define CATEGORY "/res/prometheus/"
50 curl_easy_cleanup(ptr);
72 config->core_metrics_enabled = 0;
81 curl = curl_easy_init();
86 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
87 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
89 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
90 curl_easy_setopt(curl, CURLOPT_URL,
server_uri);
97 struct ast_str **buffer = userdata;
98 size_t realsize = size * nmemb;
105 memcpy(rawdata,
contents, realsize);
106 rawdata[realsize] = 0;
115 strcpy(metric->
value,
"2");
137 info->name = __func__;
139 info->summary =
"Test value generation/respecting in metrics";
141 "Metrics have two ways to provide values when the HTTP callback\n"
143 "1. By using the direct value that resides in the metric\n"
144 "2. By providing a callback function to specify the value\n"
145 "This test verifies that both function appropriately when the\n"
146 "HTTP callback is called.";
164 strcpy(test_counter_one.
value,
"1");
168 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
169 res = curl_easy_perform(curl);
170 if (res != CURLE_OK) {
173 goto metric_values_cleanup;
178 "# HELP test_counter_one A test counter\n"
179 "# TYPE test_counter_one counter\n"
180 "test_counter_one 1\n"
181 "# HELP test_counter_two A test counter\n"
182 "# TYPE test_counter_two counter\n"
183 "test_counter_two 2\n") !=
NULL,
result, metric_values_cleanup);
185metric_values_cleanup:
209 .
name =
"test_callback",
215 info->name = __func__;
217 info->summary =
"Test registration of callbacks";
219 "This test covers callback registration. It registers\n"
220 "a callback that is invoked when an HTTP request is made,\n"
221 "and it verifies that during said callback the output to\n"
222 "the response string is correctly appended to. It also verifies\n"
223 "that unregistered callbacks are not invoked.";
243 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
244 res = curl_easy_perform(curl);
245 if (res != CURLE_OK) {
252 "# HELP test_counter A test counter\n"
253 "# TYPE test_counter counter\n"
254 "test_counter 0\n") !=
NULL);
276 info->name = __func__;
278 info->summary =
"Test registration of metrics";
280 "This test covers the following registration scenarios:\n"
281 "- Nominal registration of simple metrics\n"
282 "- Registration of metrics with different allocation strategies\n"
283 "- Nested metrics with label families\n"
284 "- Off nominal registration with simple name collisions\n"
285 "- Off nominal registration with label collisions";
296 ast_test_validate(
test, test_gauge !=
NULL);
302 ast_test_validate_cleanup(
test, test_gauge_child_one !=
NULL,
result, metric_register_cleanup);
306 ast_test_validate_cleanup(
test, test_gauge_child_two !=
NULL,
result, metric_register_cleanup);
312 ast_test_validate_cleanup(
test, test_gauge->children.first == test_gauge_child_one,
result, metric_register_cleanup);
313 ast_test_validate_cleanup(
test, test_gauge->children.last == test_gauge_child_two,
result, metric_register_cleanup);
317 ast_test_validate_cleanup(
test, bad_metric !=
NULL,
result, metric_register_cleanup);
324 ast_test_validate_cleanup(
test, bad_metric !=
NULL,
result, metric_register_cleanup);
333 test_gauge_child_two =
NULL;
341 test_gauge_child_one =
NULL;
350metric_register_cleanup:
376 info->name = __func__;
378 info->summary =
"Test formatting of counters";
380 "This test covers the formatting of printed counters";
399 "# HELP test_counter A test counter\n"
400 "# TYPE test_counter counter\n"
402 "test_counter{key_one=\"value_one\",key_two=\"value_one\"} 0\n"
403 "test_counter{key_one=\"value_two\",key_two=\"value_two\"} 0\n") == 0);
414 info->name = __func__;
416 info->summary =
"Test creation (and destruction) of malloc'd counters";
418 "This test covers creating a counter metric and destroying\n"
419 "it. The metric should be malloc'd.";
426 ast_test_validate(
test, metric !=
NULL);
429 ast_test_validate(
test, !strcmp(metric->help,
"A test counter"));
430 ast_test_validate(
test, !strcmp(metric->name,
"test_counter"));
431 ast_test_validate(
test, !strcmp(metric->value,
""));
432 ast_test_validate(
test, metric->children.first ==
NULL);
433 ast_test_validate(
test, metric->children.last ==
NULL);
459 info->name = __func__;
461 info->summary =
"Test formatting of gauges";
463 "This test covers the formatting of printed gauges";
482 "# HELP test_gauge A test gauge\n"
483 "# TYPE test_gauge gauge\n"
485 "test_gauge{key_one=\"value_one\",key_two=\"value_one\"} 0\n"
486 "test_gauge{key_one=\"value_two\",key_two=\"value_two\"} 0\n") == 0);
497 info->name = __func__;
499 info->summary =
"Test creation (and destruction) of malloc'd gauges";
501 "This test covers creating a gauge metric and destroying\n"
502 "it. The metric should be malloc'd.";
509 ast_test_validate(
test, metric !=
NULL);
512 ast_test_validate(
test, !strcmp(metric->help,
"A test gauge"));
513 ast_test_validate(
test, !strcmp(metric->name,
"test_gauge"));
514 ast_test_validate(
test, !strcmp(metric->value,
""));
515 ast_test_validate(
test, metric->children.first ==
NULL);
516 ast_test_validate(
test, metric->children.last ==
NULL);
530 info->name = __func__;
532 info->summary =
"Test basic auth handling";
534 "This test covers authentication of requests";
557 res = curl_easy_perform(curl);
558 if (res != CURLE_OK) {
562 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
564 ast_test_validate(
test, response_code == 401);
568 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
569 curl_easy_setopt(curl, CURLOPT_USERPWD,
"matt:jordan");
570 res = curl_easy_perform(curl);
571 if (res != CURLE_OK) {
575 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
577 ast_test_validate(
test, response_code == 401);
581 curl_easy_setopt(curl, CURLOPT_USERPWD,
"foo:bar");
582 res = curl_easy_perform(curl);
583 if (res != CURLE_OK) {
587 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
589 ast_test_validate(
test, response_code == 200);
603 info->name = __func__;
605 info->summary =
"Test handling of enable/disable";
607 "When disabled, the module should return a 503.\n"
608 "This test verifies that it actually occurs.";
629 res = curl_easy_perform(curl);
630 if (res != CURLE_OK) {
634 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
636 ast_test_validate(
test, response_code == 503);
650 info->name = __func__;
652 info->summary =
"Test producing core metrics";
654 "This test covers the core metrics that are produced\n"
655 "by the basic Prometheus module.";
670 config->core_metrics_enabled = 1;
682 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
683 res = curl_easy_perform(curl);
684 if (res != CURLE_OK) {
717 while ((
str = strstr(
str, needle))) {
718 str += strlen(needle);
734 info->name = __func__;
736 info->summary =
"Test producing bridge metrics";
738 "This test covers checking the metrics produced by the\n"
739 "bridge support of the basic Promtheus module.";
746 ast_test_validate(
test, bridge1 !=
NULL);
750 "test_res_prometheus",
"test_bridge_invisible",
NULL);
753 ast_test_validate(
test, bridge3 !=
NULL);
763 ast_test_validate(
test,
match_count(
ast_str_buffer(response),
"# HELP asterisk_bridges_channels_count Number of channels in the bridge.") == 1);
773 const char *bindport;
819 if (!new_module_config) {
827 ao2_ref(new_module_config, -1);
896 .
requires =
"res_prometheus",
Asterisk main include file. File version handling, generic pbx functions.
#define AST_CURL_USER_AGENT
#define ast_malloc(len)
A wrapper for malloc()
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct ast_bridge * ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Create a new base class bridge.
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
@ AST_BRIDGE_CAPABILITY_HOLDING
Basic bridge subclass API.
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
@ AST_BRIDGE_FLAG_INVISIBLE
struct ast_sockaddr bindaddr
static const char config[]
static char prefix[MAX_PREFIX]
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
@ CONFIG_FLAG_FILEUNCHANGED
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
struct ast_str * prometheus_scrape_to_string(void)
Get the raw output of what a scrape would produce.
Asterisk Prometheus Metrics.
int prometheus_metric_unregister(struct prometheus_metric *metric)
Remove a registered metric.
#define PROMETHEUS_METRIC_SET_LABEL(metric, label, n, v)
Convenience macro for setting a label / value in a metric.
int prometheus_metric_register(struct prometheus_metric *metric)
int prometheus_metric_registered_count(void)
void prometheus_general_config_set(struct prometheus_general_config *config)
Set the configuration for the module.
#define PROMETHEUS_METRIC_STATIC_INITIALIZATION(mtype, n, h, cb)
Convenience macro for initializing a metric on the stack.
@ 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.
void * prometheus_general_config_alloc(void)
Allocate a new configuration object.
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.
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_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_string_field_set(x, field, data)
Set a field to a simple string value.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#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"....
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Structure that contains information about a bridge.
Structure used to handle boolean flags.
Support for dynamic strings.
Contains all the initialization information required to store a new test definition.
The configuration settings for this module.
Defines a callback that will be invoked when the HTTP route is called.
const char * name
The name of our callback (always useful for debugging)
Prometheus general configuration.
const ast_string_field uri
const ast_string_field auth_password
const ast_string_field auth_username
An actual, honest to god, metric.
struct prometheus_metric::@270 children
A list of children metrics.
char value[PROMETHEUS_MAX_VALUE_LENGTH]
The current value.
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
static void prometheus_metric_free_wrapper(void *ptr)
static int process_config(int reload)
static int match_count(const char *str, const char *needle)
static void metric_values_get_counter_value_cb(struct prometheus_metric *metric)
static void safe_bridge_destroy(struct ast_bridge *bridge)
AST_TEST_DEFINE(metric_values)
static CURL * get_curl_instance(void)
static int test_init_cb(struct ast_test_info *info, struct ast_test *test)
static int reload_module(void)
static size_t curl_write_string_callback(void *contents, size_t size, size_t nmemb, void *userdata)
static void curl_free_wrapper(void *ptr)
static struct prometheus_general_config * config_alloc(void)
static int load_module(void)
struct prometheus_general_config * module_config
static void prometheus_metric_callback(struct ast_str **output)
static int unload_module(void)
static int test_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
static char server_uri[512]
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.