coturn/src/apps/relay/prom_server.c
2024-01-15 18:26:54 -08:00

245 lines
9.6 KiB
C

#include "prom_server.h"
#include "mainrelay.h"
#include "ns_turn_utils.h"
#if !defined(WINDOWS)
#include <errno.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#if !defined(TURN_NO_PROMETHEUS)
prom_counter_t *stun_binding_request;
prom_counter_t *stun_binding_response;
prom_counter_t *stun_binding_error;
prom_counter_t *turn_traffic_rcvp;
prom_counter_t *turn_traffic_rcvb;
prom_counter_t *turn_traffic_sentp;
prom_counter_t *turn_traffic_sentb;
prom_counter_t *turn_traffic_peer_rcvp;
prom_counter_t *turn_traffic_peer_rcvb;
prom_counter_t *turn_traffic_peer_sentp;
prom_counter_t *turn_traffic_peer_sentb;
prom_counter_t *turn_total_traffic_rcvp;
prom_counter_t *turn_total_traffic_rcvb;
prom_counter_t *turn_total_traffic_sentp;
prom_counter_t *turn_total_traffic_sentb;
prom_counter_t *turn_total_traffic_peer_rcvp;
prom_counter_t *turn_total_traffic_peer_rcvb;
prom_counter_t *turn_total_traffic_peer_sentp;
prom_counter_t *turn_total_traffic_peer_sentb;
prom_gauge_t *turn_total_allocations;
void start_prometheus_server(void) {
if (turn_params.prometheus == 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "prometheus collector disabled, not started\n");
return;
}
prom_collector_registry_default_init();
const char *label[] = {"realm", NULL};
size_t nlabels = 1;
if (turn_params.prometheus_username_labels) {
label[1] = "user";
nlabels++;
}
// Create STUN counters
stun_binding_request = prom_collector_registry_must_register_metric(
prom_counter_new("stun_binding_request", "Incoming STUN Binding requests", 0, NULL));
stun_binding_response = prom_collector_registry_must_register_metric(
prom_counter_new("stun_binding_response", "Outgoing STUN Binding responses", 0, NULL));
stun_binding_error = prom_collector_registry_must_register_metric(
prom_counter_new("stun_binding_error", "STUN Binding errors", 0, NULL));
// Create TURN traffic counter metrics
turn_traffic_rcvp = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_rcvp", "Represents finished sessions received packets", nlabels, label));
turn_traffic_rcvb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_rcvb", "Represents finished sessions received bytes", nlabels, label));
turn_traffic_sentp = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_sentp", "Represents finished sessions sent packets", nlabels, label));
turn_traffic_sentb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_sentb", "Represents finished sessions sent bytes", nlabels, label));
// Create finished sessions traffic for peers counter metrics
turn_traffic_peer_rcvp = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_peer_rcvp", "Represents finished sessions peer received packets", nlabels, label));
turn_traffic_peer_rcvb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_peer_rcvb", "Represents finished sessions peer received bytes", nlabels, label));
turn_traffic_peer_sentp = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_peer_sentp", "Represents finished sessions peer sent packets", nlabels, label));
turn_traffic_peer_sentb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_traffic_peer_sentb", "Represents finished sessions peer sent bytes", nlabels, label));
// Create total finished traffic counter metrics
turn_total_traffic_rcvp = prom_collector_registry_must_register_metric(
prom_counter_new("turn_total_traffic_rcvp", "Represents total finished sessions received packets", 0, NULL));
turn_total_traffic_rcvb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_total_traffic_rcvb", "Represents total finished sessions received bytes", 0, NULL));
turn_total_traffic_sentp = prom_collector_registry_must_register_metric(
prom_counter_new("turn_total_traffic_sentp", "Represents total finished sessions sent packets", 0, NULL));
turn_total_traffic_sentb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_total_traffic_sentb", "Represents total finished sessions sent bytes", 0, NULL));
// Create total finished sessions traffic for peers counter metrics
turn_total_traffic_peer_rcvp = prom_collector_registry_must_register_metric(prom_counter_new(
"turn_total_traffic_peer_rcvp", "Represents total finished sessions peer received packets", 0, NULL));
turn_total_traffic_peer_rcvb = prom_collector_registry_must_register_metric(prom_counter_new(
"turn_total_traffic_peer_rcvb", "Represents total finished sessions peer received bytes", 0, NULL));
turn_total_traffic_peer_sentp = prom_collector_registry_must_register_metric(prom_counter_new(
"turn_total_traffic_peer_sentp", "Represents total finished sessions peer sent packets", 0, NULL));
turn_total_traffic_peer_sentb = prom_collector_registry_must_register_metric(
prom_counter_new("turn_total_traffic_peer_sentb", "Represents total finished sessions peer sent bytes", 0, NULL));
// Create total allocations number gauge metric
const char *typeLabel[] = {"type"};
turn_total_allocations = prom_collector_registry_must_register_metric(
prom_gauge_new("turn_total_allocations", "Represents current allocations number", 1, typeLabel));
promhttp_set_active_collector_registry(NULL);
// some flags appeared first in microhttpd v0.9.53
unsigned int flags = 0;
if (MHD_is_feature_supported(MHD_FEATURE_IPv6) && is_ipv6_enabled()) {
flags |= MHD_USE_DUAL_STACK;
}
#if MHD_VERSION >= 0x00095300
flags |= MHD_USE_ERROR_LOG;
#endif
if (MHD_is_feature_supported(MHD_FEATURE_EPOLL)) {
#if MHD_VERSION >= 0x00095300
flags |= MHD_USE_EPOLL_INTERNAL_THREAD;
#else
flags |= MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY; // old versions of microhttpd
#endif
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "prometheus exporter server will start using EPOLL\n");
} else {
flags |= MHD_USE_SELECT_INTERNALLY;
// Select() will not work if all 1024 first file-descriptors are used.
// In this case the prometheus server will be unreachable
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "prometheus exporter server will start using SELECT. "
"The exporter might be unreachable on highly used servers\n");
}
struct MHD_Daemon *daemon = promhttp_start_daemon(flags, turn_params.prometheus_port, NULL, NULL);
if (daemon == NULL) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "could not start prometheus collector\n");
return;
}
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "prometheus collector started successfully\n");
return;
}
void prom_set_finished_traffic(const char *realm, const char *user, unsigned long rsvp, unsigned long rsvb,
unsigned long sentp, unsigned long sentb, bool peer) {
if (turn_params.prometheus == 1) {
const char *label[] = {realm, NULL};
if (turn_params.prometheus_username_labels) {
label[1] = user;
}
if (peer) {
prom_counter_add(turn_traffic_peer_rcvp, rsvp, label);
prom_counter_add(turn_traffic_peer_rcvb, rsvb, label);
prom_counter_add(turn_traffic_peer_sentp, sentp, label);
prom_counter_add(turn_traffic_peer_sentb, sentb, label);
prom_counter_add(turn_total_traffic_peer_rcvp, rsvp, NULL);
prom_counter_add(turn_total_traffic_peer_rcvb, rsvb, NULL);
prom_counter_add(turn_total_traffic_peer_sentp, sentp, NULL);
prom_counter_add(turn_total_traffic_peer_sentb, sentb, NULL);
} else {
prom_counter_add(turn_traffic_rcvp, rsvp, label);
prom_counter_add(turn_traffic_rcvb, rsvb, label);
prom_counter_add(turn_traffic_sentp, sentp, label);
prom_counter_add(turn_traffic_sentb, sentb, label);
prom_counter_add(turn_total_traffic_rcvp, rsvp, NULL);
prom_counter_add(turn_total_traffic_rcvb, rsvb, NULL);
prom_counter_add(turn_total_traffic_sentp, sentp, NULL);
prom_counter_add(turn_total_traffic_sentb, sentb, NULL);
}
}
}
void prom_inc_allocation(SOCKET_TYPE type) {
if (turn_params.prometheus == 1) {
const char *label[] = {socket_type_name(type)};
prom_gauge_inc(turn_total_allocations, label);
}
}
void prom_dec_allocation(SOCKET_TYPE type) {
if (turn_params.prometheus == 1) {
const char *label[] = {socket_type_name(type)};
prom_gauge_dec(turn_total_allocations, label);
}
}
void prom_inc_stun_binding_request(void) {
if (turn_params.prometheus == 1) {
prom_counter_add(stun_binding_request, 1, NULL);
}
}
void prom_inc_stun_binding_response(void) {
if (turn_params.prometheus == 1) {
prom_counter_add(stun_binding_response, 1, NULL);
}
}
void prom_inc_stun_binding_error(void) {
if (turn_params.prometheus == 1) {
prom_counter_add(stun_binding_error, 1, NULL);
}
}
int is_ipv6_enabled(void) {
int ret = 0;
#ifdef AF_INET6
int fd = socket(AF_INET6, SOCK_STREAM, 0);
if (fd == -1) {
ret = errno != EAFNOSUPPORT;
} else {
ret = 1;
close(fd);
}
#endif /* AF_INET6 */
return ret;
}
#else
void start_prometheus_server(void) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "turnserver compiled without prometheus support\n");
return;
}
void prom_set_finished_traffic(const char *realm, const char *user, unsigned long rsvp, unsigned long rsvb,
unsigned long sentp, unsigned long sentb, bool peer) {
UNUSED_ARG(realm);
UNUSED_ARG(user);
UNUSED_ARG(rsvp);
UNUSED_ARG(rsvb);
UNUSED_ARG(sentp);
UNUSED_ARG(sentb);
UNUSED_ARG(peer);
}
void prom_inc_allocation(SOCKET_TYPE type) { UNUSED_ARG(type); }
void prom_dec_allocation(SOCKET_TYPE type) { UNUSED_ARG(type); }
#endif /* TURN_NO_PROMETHEUS */