// SPDX-License-Identifier: GPL-3.0-or-later
#define EXPORTINGS_INTERNALS
#include "prometheus.h"
// ----------------------------------------------------------------------------
// PROMETHEUS
// /api/v1/allmetrics?format=prometheus and /api/v1/allmetrics?format=prometheus_all_hosts
static int is_matches_rrdset(struct instance *instance, RRDSET *st, SIMPLE_PATTERN *filter) {
if (instance->config.options & EXPORTING_OPTION_SEND_NAMES) {
return simple_pattern_matches(filter, rrdset_name(st));
}
return simple_pattern_matches(filter, rrdset_id(st));
}
/**
* Check if a chart can be sent to Prometheus
*
* @param instance an instance data structure.
* @param st a chart.
* @param filter a simple pattern to match against.
* @return Returns 1 if the chart can be sent, 0 otherwise.
*/
inline int can_send_rrdset(struct instance *instance, RRDSET *st, SIMPLE_PATTERN *filter)
{
#ifdef NETDATA_INTERNAL_CHECKS
RRDHOST *host = st->rrdhost;
#endif
// Do not send anomaly rates charts.
if (rrdset_is_ar_chart(st))
return 0;
if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_EXPORTING_IGNORE)))
return 0;
if (filter) {
if (!is_matches_rrdset(instance, st, filter)) {
return 0;
}
} else if (unlikely(!rrdset_flag_check(st, RRDSET_FLAG_EXPORTING_SEND))) {
// we have not checked this chart
if (is_matches_rrdset(instance, st, instance->config.charts_pattern)) {
rrdset_flag_set(st, RRDSET_FLAG_EXPORTING_SEND);
} else {
rrdset_flag_set(st, RRDSET_FLAG_EXPORTING_IGNORE);
debug(
D_EXPORTING,
"EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.",
rrdset_id(st),
rrdhost_hostname(host));
return 0;
}
}
if (unlikely(!rrdset_is_available_for_exporting_and_alarms(st))) {
debug(
D_EXPORTING,
"EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.",
rrdset_id(st),
rrdhost_hostname(host));
return 0;
}
if (unlikely(
st->rrd_memory_mode == RRD_MEMORY_MODE_NONE &&
!(EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED))) {
debug(
D_EXPORTING,
"EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting connector requires database access.",
rrdset_id(st),
rrdhost_hostname(host),
rrd_memory_mode_name(host->rrd_memory_mode));
return 0;
}
return 1;
}
static struct prometheus_server {
const char *server;
uint32_t hash;
RRDHOST *host;
time_t last_access;
struct prometheus_server *next;
} *prometheus_server_root = NULL;
static netdata_mutex_t prometheus_server_root_mutex = NETDATA_MUTEX_INITIALIZER;
/**
* Clean server root local structure
*/
void prometheus_clean_server_root()
{
if (prometheus_server_root) {
netdata_mutex_lock(&prometheus_server_root_mutex);
struct prometheus_server *ps;
for (ps = prometheus_server_root; ps; ) {
struct prometheus_server *current = ps;
ps = ps->next;
if(current->server)
freez((void *)current->server);
freez(current);
}
prometheus_server_root = NULL;
netdata_mutex_unlock(&prometheus_server_root_mutex);
}
}
/**
* Get the last time when a Prometheus server scraped the Netdata Prometheus exporter.
*
* @param server the name of the Prometheus server.
* @param host a data collecting host.
* @param now actual time.
* @return Returns the last time when the server accessed Netdata, or 0 if it is the first occurrence.
*/
static inline time_t prometheus_server_last_access(const char *server, RRDHOST *host, time_t now)
{
#ifdef UNIT_TESTING
return 0;
#endif
uint32_t hash = simple_hash(server);
netdata_mutex_lock(&prometheus_server_root_mutex);
struct prometheus_server *ps;
for (ps = prometheus_server_root; ps; ps = ps->next) {
if (host == ps->host && hash == ps->hash && !strcmp(server, ps->server)) {
time_t last = ps->last_access;
ps->last_access = now;
netdata_mutex_unlock(&prometheus_server_root_mutex);
return last;
}
}
ps = callocz(1, sizeof(struct prometheus_server));
ps->server = strdupz(server);
ps->hash = hash;
ps->host = host;
ps->last_access = now;
ps->next = prometheus_server_root;