| 1 | # Netdata Expression Evaluator |
| 2 | |
| 3 | This directory contains Netdata's Expression Evaluator, a component for evaluating mathematical and logical expressions in Netdata's health monitoring, alerts, and data processing pipelines. |
| 4 | |
| 5 | ## Overview |
| 6 | |
| 7 | The expression evaluator is a parser and interpreter for mathematical, logical, and comparison expressions. It supports: |
| 8 | |
| 9 | - Arithmetic operations (`+`, `-`, `*`, `/`, `%`) |
| 10 | - Logical operations (`AND`/`&&`, `OR`/`||`, `NOT`/`!`) |
| 11 | - Comparison operations (`==`, `!=`, `>`, `>=`, `<`, `<=`) |
| 12 | - Ternary conditional operator (`? :`) |
| 13 | - Function calls (e.g., `abs()`) |
| 14 | - Variables (e.g., `$var1`) |
| 15 | |
| 16 | Expressions are used in Netdata's alert definitions, and other areas that require dynamic computation. |
| 17 | |
| 18 | ## Implementation |
| 19 | |
| 20 | The expression evaluator has two parser implementations: |
| 21 | |
| 22 | 1. **Original Recursive Descent Parser** - A handwritten parser in `eval-parser-legacy.c` |
| 23 | 2. **re2c/Lemon Parser** - A more efficient parser using re2c for lexical analysis and Lemon for grammar parsing in the `re2c_lemon/` subdirectory |
| 24 | |
| 25 | The implementation can be switched between these two parsers using the `USE_RE2C_LEMON_PARSER` define in `eval-internal.h`. |
| 26 | |
| 27 | ## Key Components |
| 28 | |
| 29 | - **eval.h** - Public API for the expression evaluator |
| 30 | - **eval-internal.h** - Internal structures and parser selection switch |
| 31 | - **eval-parser.c** - Original recursive descent parser implementation |
| 32 | - **eval-execute.c** - Expression evaluation engine |
| 33 | - **eval-utils.c** - Helper functions for working with expression nodes |
| 34 | - **eval-unittest.c** - Comprehensive test suite for the evaluator |
| 35 | - **re2c_lemon/** - Subdirectory containing the re2c/Lemon-based parser implementation |
| 36 | |
| 37 | ## Expression Syntax |
| 38 | |
| 39 | The evaluator supports a C-like syntax: |
| 40 | |
| 41 | ``` |
| 42 | # Arithmetic |
| 43 | 42 + 24 |
| 44 | 5 * (3 + 2) |
| 45 | |
| 46 | # Comparisons |
| 47 | $temp > 80 |
| 48 | $load >= $threshold |
| 49 | |
| 50 | # Logical operations |
| 51 | $cpu_util > 90 && $mem_usage > 80 |
| 52 | $disk_full || $inode_usage > 95 |
| 53 | |
| 54 | # Ternary operator |
| 55 | $status == $WARNING ? 90 : 75 |
| 56 | |
| 57 | # Functions |
| 58 | abs($value) |
| 59 | ``` |
| 60 | |
| 61 | Variables are prefixed with `$` and can be either simple names (`$var`) or use braces for complex names (`${variable name with spaces}`). |
| 62 | |
| 63 | ## Special Features |
| 64 | |
| 65 | - Case-insensitive handling of logical operators: `AND`/`and`/`&&` are equivalent |
| 66 | - Support for special numeric literals: `nan` and `inf` (any capitalization) |
| 67 | - Short-circuit evaluation of logical operators |
| 68 | - NaN and Infinity handling in calculations |
| 69 | |
| 70 | ## Usage |
| 71 | |
| 72 | To use the expression evaluator in Netdata code: |
| 73 | |
| 74 | ```c |
| 75 | #include "libnetdata/eval/eval.h" |
| 76 | |
| 77 | // Parse an expression |
| 78 | const char *expr = "$value > 100 && $status != 0"; |
| 79 | const char *failed_at = NULL; |
| 80 | int error = 0; |
| 81 | EVAL_EXPRESSION *exp = expression_parse(expr, &failed_at, &error); |
| 82 | |
| 83 | if (!exp) { |
| 84 | // Handle parsing error |
| 85 | printf("Error parsing expression at: %s\n", failed_at); |
| 86 | printf("Error code: %d (%s)\n", error, expression_strerror(error)); |
| 87 | return; |
| 88 | } |
| 89 | |
| 90 | // Set up variable lookup callback |
| 91 | expression_set_variable_lookup_callback(exp, my_variable_lookup_function, my_data); |
| 92 | |
| 93 | // Evaluate the expression |
| 94 | if (expression_evaluate(exp)) { |
| 95 | // Get the result |
| 96 | NETDATA_DOUBLE result = expression_result(exp); |
| 97 | printf("Result: %f\n", result); |
| 98 | } else { |
| 99 | // Handle evaluation error |
| 100 | printf("Evaluation error: %s\n", expression_error_msg(exp)); |
| 101 | } |
| 102 | |
| 103 | // Free the expression |
| 104 | expression_free(exp); |
| 105 | ``` |
| 106 | |
| 107 | ## Testing |
| 108 | |
| 109 | The evaluator includes a comprehensive test suite in `eval-unittest.c`. Run it using: |
| 110 | |
| 111 | ``` |
| 112 | netdata -W evaltest |
| 113 | ``` |
| 114 | |
| 115 | All these tests run also at CI. |