Index: frontends/php/include/classes/validators/CFunctionValidator.php =================================================================== --- frontends/php/include/classes/validators/CFunctionValidator.php (revision 53760) +++ frontends/php/include/classes/validators/CFunctionValidator.php (working copy) @@ -189,6 +189,13 @@ 'args' => $argsIgnored, 'value_types' => $valueTypesAll ), + 'rate' => array( + 'args' => array( + array('type' => 'sec_num', 'mandat' => true), + array('type' => 'sec_zero', 'can_be_empty' => true) + ), + 'value_types' => $valueTypesNum + ), 'regexp' => array( 'args' => array( array('type' => 'str', 'mandat' => true), Index: frontends/php/include/triggers.inc.php =================================================================== --- frontends/php/include/triggers.inc.php (revision 53760) +++ frontends/php/include/triggers.inc.php (working copy) @@ -2098,6 +2098,7 @@ 'nodata' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'now' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), 'prev' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), + 'rate' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'regexp' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'str' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'strlen' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), Index: frontends/php/popup_trexpr.php =================================================================== --- frontends/php/popup_trexpr.php (revision 53760) +++ frontends/php/popup_trexpr.php (working copy) @@ -301,6 +301,26 @@ 'description' => _('Previous value is NOT N'), 'allowed_types' => $allowedTypesAny ), + 'rate[<]' => array( + 'description' => _('Rate for value over period T is < N'), + 'params' => $param1SecCount, + 'allowed_types' => $allowedTypesNumeric + ), + 'rate[>]' => array( + 'description' => _('Rate for value over period T is > N'), + 'params' => $param1SecCount, + 'allowed_types' => $allowedTypesNumeric + ), + 'rate[=]' => array( + 'description' => _('Rate for value over period T is = N'), + 'params' => $param1SecCount, + 'allowed_types' => $allowedTypesNumeric + ), + 'rate[<>]' => array( + 'description' => _('Rate for value over period T is NOT N'), + 'params' => $param1SecCount, + 'allowed_types' => $allowedTypesNumeric + ), 'str[=]' => array( 'description' => _('Find string V in last (most recent) value. N = 1 - if found, 0 - otherwise'), 'params' => $param2SecCount, Index: src/libs/zbxserver/evalfunc.c =================================================================== --- src/libs/zbxserver/evalfunc.c (revision 53760) +++ src/libs/zbxserver/evalfunc.c (working copy) @@ -757,6 +757,118 @@ /****************************************************************************** * * + * Function: evaluate_RATE * + * * + * Purpose: evaluate function 'rate' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + * Author: James Burns * + * * + ******************************************************************************/ +static int evaluate_RATE(char *value, DC_ITEM *item, const char *function, const char *parameters, time_t now) +{ + const char *__function_name = "evaluate_RATE"; + int nparams, arg1, flag, ret = FAIL, i, seconds = 0, nvalues = 0; + double meanx=0.0, meany=0.0; + double dx=0.0, dy=0.0; + double sumdydx=0.0, sumdxdx=0.0; + zbx_vector_history_record_t values; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + goto out; + + if (2 < (nparams = num_param(parameters))) + goto out; + + if (SUCCEED != get_function_parameter_uint31(item->host.hostid, parameters, 1, &arg1, &flag) || 0 == arg1) + goto out; + + if (2 == nparams) + { + int time_shift, time_shift_flag; + + if (SUCCEED != get_function_parameter_uint31_default(item->host.hostid, parameters, 2, &time_shift, + &time_shift_flag, 0, ZBX_FLAG_SEC) || ZBX_FLAG_SEC != time_shift_flag) + { + goto out; + } + + now -= time_shift; + } + + if (ZBX_FLAG_SEC == flag) + seconds = arg1; + else + nvalues = arg1; + + if (FAIL == zbx_vc_get_value_range(item->itemid, item->value_type, &values, seconds, nvalues, now)) + goto out; + + if (1 < values.values_num) + { + double sum = 0; + + if (ITEM_VALUE_TYPE_FLOAT == item->value_type) + { + for (i = 0; i < values.values_num; i++){ + meanx += values.values[i].timestamp.sec; + meany += values.values[i].value.dbl; + } + meanx /= values.values_num; + meany /= values.values_num; + + for (i = 1; i < values.values_num; i++){ + dx = (values.values[i].timestamp.sec - meanx); + dy = (values.values[i].value.dbl-meany); + sumdydx += (dy*dx); + sumdxdx += (dx*dx); + } + sumdydx /= sumdxdx;//produce the gradient and store in sumdydx + + } + else + { + for (i = 0; i < values.values_num; i++){ + meanx += values.values[i].timestamp.sec; + meany += values.values[i].value.ui64; + } + meanx /= values.values_num; + meany /= values.values_num; + + for (i = 1; i < values.values_num; i++){ + dx = (values.values[i].timestamp.sec - meanx); + dy = (values.values[i].value.ui64-meany); + sumdydx += (dy*dx); + sumdxdx += (dx*dx); + } + sumdydx /= sumdxdx;//produce the gradient and store in sumdydx + + } + zbx_snprintf(value, MAX_BUFFER_LEN, ZBX_FS_DBL, sumdydx); + + ret = SUCCEED; + } + else + zabbix_log(LOG_LEVEL_DEBUG, "result for RATE is empty"); +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * * Function: evaluate_LAST * * * * Purpose: evaluate functions 'last' and 'prev' for the item * @@ -1737,6 +1849,10 @@ { ret = evaluate_AVG(value, item, function, parameter, now); } + else if (0 == strcmp(function, "rate")) + { + ret = evaluate_RATE(value, item, function, parameter, now); + } else if (0 == strcmp(function, "sum")) { ret = evaluate_SUM(value, item, function, parameter, now); @@ -2224,7 +2340,7 @@ { zbx_format_value(value, MAX_BUFFER_LEN, item.valuemapid, item.units, item.value_type); } - else if (SUCCEED == str_in_list("abschange,avg,change,delta,max,min,sum", function, ',')) + else if (SUCCEED == str_in_list("abschange,avg,change,delta,max,min,rate,sum", function, ',')) { switch (item.value_type) { Index: src/zabbix_server/poller/checks_aggregate.c =================================================================== --- src/zabbix_server/poller/checks_aggregate.c (revision 53760) +++ src/zabbix_server/poller/checks_aggregate.c (working copy) @@ -29,6 +29,7 @@ #define ZBX_VALUE_FUNC_SUM 3 #define ZBX_VALUE_FUNC_COUNT 4 #define ZBX_VALUE_FUNC_LAST 5 +#define ZBX_VALUE_FUNC_RATE 6 /****************************************************************************** * * @@ -184,7 +185,63 @@ { *result = values->values[0].value; } +/****************************************************************************** + * * + * Function: evaluate_history_func_rate * + * * + * Purpose: calculate the rate of change for the history value ZBXNEXT-2374 * + * * + * Parameters: values - [IN] a vector containing history values * + * value_type - [IN] the type of values. Only float/uint64 * + * values are supported. * + * result - [OUT] the result value/second (from timestamp) * + * * + * Author: James Burns * + * * + ******************************************************************************/ +static void evaluate_history_func_rate(zbx_vector_history_record_t *values, int value_type, history_value_t *result) { + int i; + double meanx=0.0, meany=0.0; + double dx=0.0, dy=0.0; + double sumdydx=0.0, sumdxdx=0.0; + + if (ITEM_VALUE_TYPE_UINT64 == value_type) + { + for (i = 0; i < values->values_num; i++){ + meanx += values->values[i].timestamp.sec; + meany += values->values[i].value.ui64; + } + meanx /= values->values_num; + meany /= values->values_num; + + for (i = 1; i < values->values_num; i++){ + dx = (values->values[i].timestamp.sec - meanx); + dy = (values->values[i].value.ui64-meany); + sumdydx += (dy*dx); + sumdxdx += (dx*dx); + } + sumdydx /= sumdxdx;//produce the gradient and store in sumdydx + result->ui64 = sumdydx; + } + else { + for (i = 1; i < values->values_num; i++){ + meanx += values->values[i].timestamp.sec; + meany += values->values[i].value.dbl; + } + meanx /= values->values_num; + meany /= values->values_num; + for (i = 1; i < values->values_num; i++){ + dx = (values->values[i].timestamp.sec - meanx); + dy = (values->values[i].value.dbl-meany); + sumdydx += (dy*dx); + sumdxdx += (dx*dx); + } + sumdydx /= sumdxdx;//produce the gradient and store in sumdydx + result->dbl = sumdydx; + } +} + /****************************************************************************** * * * Function: evaluate_history_func * @@ -225,6 +282,9 @@ case ZBX_VALUE_FUNC_LAST: evaluate_history_func_last(values, value_type, result); break; + case ZBX_VALUE_FUNC_RATE: + evaluate_history_func_rate(values, value_type, result); + break; } } @@ -509,6 +569,8 @@ item_func = ZBX_VALUE_FUNC_COUNT; else if (0 == strcmp(tmp, "last")) item_func = ZBX_VALUE_FUNC_LAST; + else if (0 == strcmp(tmp, "rate")) + item_func = ZBX_VALUE_FUNC_RATE; else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));