mirror of
https://github.com/netdata/netdata.git
synced 2025-04-28 22:52:30 +00:00

* cleanup alerts * fix references * fix references * fix references * load alerts once and apply them to each node * simplify health_create_alarm_entry() * Compile without warnings with compiler flags: -Wall -Wextra -Wformat=2 -Wshadow -Wno-format-nonliteral -Winit-self * code re-organization and cleanup * generate patterns when applying prototypes; give unique dyncfg names to all alerts * eval expressions keep the source and the parsed_as as STRING pointers * renamed host to node in dyncfg ids * renamed host to node in dyncfg ids * add all cloud roles to the list of parsed X-Netdata-Role header and also default to member access level * working functionality * code re-organization: moved health event-loop to a new file, moved health globals to health.c * rrdcalctemplate is removed; alert_cfg is removed; foreach dimension is removed; RRDCALCs are now instanciated only when they are linked to RRDSETs * dyncfg alert prototypes initialization for alerts * health dyncfg split to separate file * cleanup not-needed code * normalize matches between parsing and json * also detect !* for disabled alerts * dyncfg capability disabled * Store alert config part1 * Add rrdlabels_common_count * wip health variables lookup without indexes * Improve rrdlabels_common_count by reusing rrdlabels_find_label_with_key_unsafe with an additional parameter * working variables with runtime lookup * working variables with runtime lookup * delete rrddimvar and rrdfamily index * remove rrdsetvar; now all variables are in RRDVARs inside hosts and charts * added /api/v1/variable that resolves a variable the same way alerts do * remove rrdcalc from eval * remove debug code * remove duplicate assignment * Fix memory leak * all alert variables are now handled by alert_variable_lookup() and EVAL is now independent of alerts * hide all internal structures of EVAL * Enable -Wformat flag Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud> * Adjust binding for calculation, warning, critical * Remove unused macro * Update config hash id * use the right info and summary in alerts log * use synchronous queries for alerts * Handle cases when config_hash_id is missing from health_log * remove deadlock from health worker * parsing to json payload for health alert prototypes * cleaner parsing and avoiding memory leaks in case of duplicate members in json * fix left-over rename of function * Keep original lookup field to send to the cloud Cleanup / rename function to store config Remove unused DEFINEs, functions * Use ac->lookup * link jobs to the host when the template is registered; do not accept running a function without a host * full dyncfg support for health alerts, except action TEST * working dyncfg additions, updates, removals * fixed missing source, wrong status updates * add alerts by type, component, classification, recipient and module at the /api/v2/alerts endpoint * fix dyncfg unittest * rename functions * generalize the json-c parser macros and move them to libnetdata * report progress when enabling and disabling dyncfg templates * moved rrdcalc and rrdvar to health * update alarms * added schema for alerts; separated alert_action_options from rrdr_options; restructured the json payload for alerts * enable parsed json alerts; allow sending back accepted but disabled * added format_version for alerts payload; enables/disables status now is also inheritted by the status of the rules; fixed variable names in json output * remove the RRDHOST pointer from DYNCFG * Fix command field submitted to the cloud * do not send updates to creation requests, for DYNCFG jobs --------- Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud> Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> Co-authored-by: Tasos Katsoulas <tasos@netdata.cloud> Co-authored-by: ilyam8 <ilya@netdata.cloud>
289 lines
7.8 KiB
C
289 lines
7.8 KiB
C
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
|
|
/*
|
|
* 1. build netdata (as normally)
|
|
* 2. cd profile/
|
|
* 3. compile with:
|
|
* gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o test-eval test-eval.c ../src/log.o ../src/eval.o ../src/common.o ../src/clocks.o ../src/web_buffer.o ../src/storage_number.o -pthread -lm
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "libnetdata/libnetdata.h"
|
|
#include "libnetdata/required_dummies.h"
|
|
#include "health/rrdcalc.h"
|
|
|
|
/*
|
|
void indent(int level, int show) {
|
|
int i = level;
|
|
while(i--) printf(" | ");
|
|
if(show) printf(" \\_ ");
|
|
else printf(" \\_ ");
|
|
}
|
|
|
|
void print_node(EVAL_NODE *op, int level);
|
|
|
|
void print_value(EVAL_VALUE *v, int level) {
|
|
indent(level, 0);
|
|
|
|
switch(v->type) {
|
|
case EVAL_VALUE_INVALID:
|
|
printf("value (NOP)\n");
|
|
break;
|
|
|
|
case EVAL_VALUE_NUMBER:
|
|
printf("value %Lf (NUMBER)\n", v->number);
|
|
break;
|
|
|
|
case EVAL_VALUE_EXPRESSION:
|
|
printf("value (SUB-EXPRESSION)\n");
|
|
print_node(v->expression, level+1);
|
|
break;
|
|
|
|
default:
|
|
printf("value (INVALID type %d)\n", v->type);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
void print_node(EVAL_NODE *op, int level) {
|
|
|
|
// if(op->operator != EVAL_OPERATOR_NOP) {
|
|
indent(level, 1);
|
|
if(op->operator) printf("%c (node %d, precedence: %d)\n", op->operator, op->id, op->precedence);
|
|
else printf("NOP (node %d, precedence: %d)\n", op->id, op->precedence);
|
|
// }
|
|
|
|
int i = op->count;
|
|
while(i--) print_value(&op->ops[i], level + 1);
|
|
}
|
|
|
|
NETDATA_DOUBLE evaluate(EVAL_NODE *op, int depth);
|
|
|
|
NETDATA_DOUBLE evaluate_value(EVAL_VALUE *v, int depth) {
|
|
switch(v->type) {
|
|
case EVAL_VALUE_NUMBER:
|
|
return v->number;
|
|
|
|
case EVAL_VALUE_EXPRESSION:
|
|
return evaluate(v->expression, depth);
|
|
|
|
default:
|
|
fatal("I don't know how to handle EVAL_VALUE type %d", v->type);
|
|
}
|
|
}
|
|
|
|
void print_depth(int depth) {
|
|
static int count = 0;
|
|
|
|
printf("%d. ", ++count);
|
|
while(depth--) printf(" ");
|
|
}
|
|
|
|
NETDATA_DOUBLE evaluate(EVAL_NODE *op, int depth) {
|
|
NETDATA_DOUBLE n1, n2, r;
|
|
|
|
switch(op->operator) {
|
|
case EVAL_OPERATOR_SIGN_PLUS:
|
|
r = evaluate_value(&op->ops[0], depth);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_SIGN_MINUS:
|
|
r = -evaluate_value(&op->ops[0], depth);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_PLUS:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 + n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf + %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_MINUS:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 - n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf - %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_MULTIPLY:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 * n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf * %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_DIVIDE:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 / n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf / %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_NOT:
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
r = !n1;
|
|
print_depth(depth);
|
|
printf("%Lf = NOT %Lf\n", r, n1);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_AND:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 && n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf AND %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_OR:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 || n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf OR %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_GREATER_THAN_OR_EQUAL:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 >= n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf >= %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_LESS_THAN_OR_EQUAL:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 <= n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf <= %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_GREATER:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 > n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf > %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_LESS:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 < n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf < %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_NOT_EQUAL:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 != n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf <> %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_EQUAL:
|
|
if(op->count != 2)
|
|
fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
|
|
n1 = evaluate_value(&op->ops[0], depth);
|
|
n2 = evaluate_value(&op->ops[1], depth);
|
|
r = n1 == n2;
|
|
print_depth(depth);
|
|
printf("%Lf = %Lf == %Lf\n", r, n1, n2);
|
|
break;
|
|
|
|
case EVAL_OPERATOR_EXPRESSION_OPEN:
|
|
printf("BEGIN SUB-EXPRESSION\n");
|
|
r = evaluate_value(&op->ops[0], depth + 1);
|
|
printf("END SUB-EXPRESSION\n");
|
|
break;
|
|
|
|
case EVAL_OPERATOR_NOP:
|
|
case EVAL_OPERATOR_VALUE:
|
|
r = evaluate_value(&op->ops[0], depth);
|
|
break;
|
|
|
|
default:
|
|
netdata_log_error("I don't know how to handle operator '%c'", op->operator);
|
|
r = 0;
|
|
break;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
void print_expression(EVAL_NODE *op, const char *failed_at, int error) {
|
|
if(op) {
|
|
printf("expression tree:\n");
|
|
print_node(op, 0);
|
|
|
|
printf("\nevaluation steps:\n");
|
|
evaluate(op, 0);
|
|
|
|
int error;
|
|
NETDATA_DOUBLE ret = expression_evaluate(op, &error);
|
|
printf("\ninternal evaluator:\nSTATUS: %d, RESULT = %Lf\n", error, ret);
|
|
|
|
expression_free(op);
|
|
}
|
|
else {
|
|
printf("error: %d, failed_at: '%s'\n", error, (failed_at)?failed_at:"<NONE>");
|
|
}
|
|
}
|
|
*/
|
|
|
|
int main(int argc, char **argv) {
|
|
if(argc != 2) {
|
|
fprintf(stderr, "I need an expression (enclose it in single-quotes (') as a single parameter)\n");
|
|
exit(1);
|
|
}
|
|
|
|
const char *failed_at = NULL;
|
|
int error;
|
|
|
|
EVAL_EXPRESSION *exp = expression_parse(argv[1], &failed_at, &error);
|
|
if(!exp)
|
|
printf("\nPARSING FAILED\nExpression: '%s'\nParsing stopped at: '%s'\nParsing error code: %d (%s)\n", argv[1], (failed_at)?((*failed_at)?failed_at:"<END OF EXPRESSION>"):"<NONE>", error, expression_strerror(error));
|
|
|
|
else {
|
|
printf("\nPARSING OK\nExpression: '%s'\nParsed as : '%s'\nParsing error code: %d (%s)\n", argv[1], exp->parsed_as, error, expression_strerror(error));
|
|
|
|
if(expression_evaluate(exp)) {
|
|
printf("\nEvaluates to: %Lf\n\n", exp->result);
|
|
}
|
|
else {
|
|
printf("\nEvaluation failed with code %d and message: %s\n\n", exp->error, buffer_tostring(exp->error_msg));
|
|
}
|
|
expression_free(exp);
|
|
}
|
|
|
|
return 0;
|
|
}
|