// SPDX-License-Identifier: GPL-3.0-or-later
#include "rrd.h"
// ----------------------------------------------------------------------------
// RRDCALC helpers
inline const char *rrdcalc_status2string(RRDCALC_STATUS status) {
switch(status) {
case RRDCALC_STATUS_REMOVED:
return "REMOVED";
case RRDCALC_STATUS_UNDEFINED:
return "UNDEFINED";
case RRDCALC_STATUS_UNINITIALIZED:
return "UNINITIALIZED";
case RRDCALC_STATUS_CLEAR:
return "CLEAR";
case RRDCALC_STATUS_RAISED:
return "RAISED";
case RRDCALC_STATUS_WARNING:
return "WARNING";
case RRDCALC_STATUS_CRITICAL:
return "CRITICAL";
default:
error("Unknown alarm status %d", status);
return "UNKNOWN";
}
}
uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id) {
netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
// re-use old IDs, by looking them up in the alarm log
ALARM_ENTRY *ae = NULL;
for(ae = host->health_log.alarms; ae ;ae = ae->next) {
if(unlikely(name == ae->name && chart == ae->chart)) {
if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
break;
}
}
uint32_t alarm_id;
if(ae)
alarm_id = ae->alarm_id;
else {
if (unlikely(!host->health_log.next_alarm_id))
host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
alarm_id = host->health_log.next_alarm_id++;
}
netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
return alarm_id;
}
// ----------------------------------------------------------------------------
// RRDCALC replacing info text variables with RRDSET labels
static STRING *rrdcalc_replace_variables_with_rrdset_labels(const char *line, RRDCALC *rc) {
if (!line || !*line)
return NULL;
size_t pos = 0;
char *temp = strdupz(line);
char var[RRDCALC_VAR_MAX];
char *m, *lbl_value = NULL;
while ((m = strchr(temp + pos, '$'))) {
int i = 0;
char *e = m;
while (*e) {
if (*e == ' ' || i == RRDCALC_VAR_MAX - 1)
break;
else
var[i] = *e;
e++;
i++;
}
var[i] = '\0';
pos = m - temp + 1;
if (!strcmp(var, RRDCALC_VAR_FAMILY)) {
char *buf = find_and_replace(temp, var, (rc->rrdset && rc->rrdset->family) ? rrdset_family(rc->rrdset) : "", m);
freez(temp);
temp = buf;
}
else if (!strncmp(var, RRDCALC_VAR_LABEL, RRDCALC_VAR_LABEL_LEN)) {
if(likely(rc->rrdset && rc->rrdset->rrdlabels)) {
rrdlabels_get_value_to_char_or_null(rc->rrdset->rrdlabels, &lbl_value, var+RRDCALC_VAR_LABEL_LEN);
if (lbl_value) {
char *buf = find_and_replace(temp, var, lbl_value, m);
freez(temp);
temp = buf;
freez(lbl_value);
}
}
}
}
STRING *ret = string_strdupz(temp);
freez(temp);
return ret;
}
void rrdcalc_update_info_using_rrdset_labels(RRDCALC *rc) {
if(!rc->rrdset || !rc->original_info || !rc->rrdset->rrdlabels) return;
size_t labels_version = dictionary_version(rc->rrdset->rrdlabels);
if(rc->labels_version != labels_version) {
STRING *old = rc->info;
rc->info = rrdcalc_replace_variables_with_rrdset_labels(rrdcalc_original_info(rc), rc);
string_freez(old);
rc->labels_version = labels_version;
}
}
// ----------------------------------------------------------------------------
// RRDCALC index management for RRDSET
// the dictionary requires a unique key for every item
// we use {chart id}.{alert name} for both the RRDHOST and RRDSET alert indexes.
#define RRDCALC_MAX_KEY_SIZE 1024
static size_t rrdcalc_key(char *dst, size_t dst_len, const char *chart, const char *alert) {
return snprintfz(dst, dst_len, "%s/%s", chart, alert);
}
const RRDCALC_ACQUIRED *rrdcalc_from_rrdset_get(RRDSET *st, const char *alert_name) {
char key[RRDCALC_MAX_KEY_SIZE + 1];
size_t key_len = rrdcalc_key(key, RRDCALC_MAX_KEY_SIZE, rrdset_id(st), alert_name);
const