1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 /*
21 * NOTE!!!!!
22 *
23 * This is the new expression syntax support for trigger functions and calculated/aggregated
24 * checks. The old syntax is still used in simple macros. When the new expression syntax
25 * support is added to simple macros the evalfunc.c:evaluate_function (and related code)
26 * must be removed, this code must be copied over the old implementation and unused code removed.
27 */
28
29 #include "common.h"
30 #include "db.h"
31 #include "log.h"
32 #include "zbxserver.h"
33 #include "valuecache.h"
34 #include "evalfunc.h"
35 #include "zbxregexp.h"
36 #include "zbxtrends.h"
37
38 typedef enum
39 {
40 ZBX_PARAM_OPTIONAL,
41 ZBX_PARAM_MANDATORY
42 }
43 zbx_param_type_t;
44
45 typedef enum
46 {
47 ZBX_VALUE_NONE,
48 ZBX_VALUE_SECONDS,
49 ZBX_VALUE_NVALUES
50 }
51 zbx_value_type_t;
52
zbx_type_string(zbx_value_type_t type)53 static const char *zbx_type_string(zbx_value_type_t type)
54 {
55 switch (type)
56 {
57 case ZBX_VALUE_NONE:
58 return "none";
59 case ZBX_VALUE_SECONDS:
60 return "sec";
61 case ZBX_VALUE_NVALUES:
62 return "num";
63 default:
64 THIS_SHOULD_NEVER_HAPPEN;
65 return "unknown";
66 }
67 }
68
69 /******************************************************************************
70 * *
71 * Function: get_function_parameter_int *
72 * *
73 * Purpose: get the value of sec|#num trigger function parameter *
74 * *
75 * Parameters: parameters - [IN] trigger function parameters *
76 * Nparam - [IN] specifies which parameter to extract *
77 * parameter_type - [IN] specifies whether parameter is mandatory *
78 * or optional *
79 * value - [OUT] parameter value (preserved as is if the *
80 * parameter is optional and empty) *
81 * type - [OUT] parameter value type (number of seconds *
82 * or number of values) *
83 * *
84 * Return value: SUCCEED - parameter is valid *
85 * FAIL - otherwise *
86 * *
87 ******************************************************************************/
get_function_parameter_int(const char * parameters,int Nparam,zbx_param_type_t parameter_type,int * value,zbx_value_type_t * type)88 static int get_function_parameter_int(const char *parameters, int Nparam, zbx_param_type_t parameter_type,
89 int *value, zbx_value_type_t *type)
90 {
91 char *parameter;
92 int ret = FAIL;
93
94 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
95
96 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
97 goto out;
98
99 if ('\0' == *parameter)
100 {
101 switch (parameter_type)
102 {
103 case ZBX_PARAM_OPTIONAL:
104 ret = SUCCEED;
105 break;
106 case ZBX_PARAM_MANDATORY:
107 break;
108 default:
109 THIS_SHOULD_NEVER_HAPPEN;
110 }
111 }
112 else if ('#' == *parameter)
113 {
114 *type = ZBX_VALUE_NVALUES;
115 if (SUCCEED == is_uint31(parameter + 1, value) && 0 < *value)
116 ret = SUCCEED;
117 }
118 else if ('-' == *parameter)
119 {
120 if (SUCCEED == is_time_suffix(parameter + 1, value, ZBX_LENGTH_UNLIMITED))
121 {
122 *value = -(*value);
123 *type = ZBX_VALUE_SECONDS;
124 ret = SUCCEED;
125 }
126 }
127 else if (SUCCEED == is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED))
128 {
129 *type = ZBX_VALUE_SECONDS;
130 ret = SUCCEED;
131 }
132
133 if (SUCCEED == ret)
134 zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d", __func__, zbx_type_string(*type), *value);
135
136 zbx_free(parameter);
137 out:
138 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
139
140 return ret;
141 }
142
get_function_parameter_uint64(const char * parameters,int Nparam,zbx_uint64_t * value)143 static int get_function_parameter_uint64(const char *parameters, int Nparam, zbx_uint64_t *value)
144 {
145 char *parameter;
146 int ret = FAIL;
147
148 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
149
150 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
151 goto out;
152
153 if (SUCCEED == (ret = is_uint64(parameter, value)))
154 zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_UI64, __func__, *value);
155
156 zbx_free(parameter);
157 out:
158 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
159
160 return ret;
161 }
162
get_function_parameter_float(const char * parameters,int Nparam,unsigned char flags,double * value)163 static int get_function_parameter_float(const char *parameters, int Nparam, unsigned char flags, double *value)
164 {
165 char *parameter;
166 int ret = FAIL;
167
168 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
169
170 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
171 goto out;
172
173 if (SUCCEED == (ret = is_double_suffix(parameter, flags)))
174 {
175 *value = str2double(parameter);
176 zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_DBL, __func__, *value);
177 }
178
179 zbx_free(parameter);
180 out:
181 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
182
183 return ret;
184 }
185
get_function_parameter_str(const char * parameters,int Nparam,char ** value)186 static int get_function_parameter_str(const char *parameters, int Nparam, char **value)
187 {
188 int ret = FAIL;
189
190 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
191
192 if (NULL == (*value = zbx_function_get_param_dyn(parameters, Nparam)))
193 goto out;
194
195 zabbix_log(LOG_LEVEL_DEBUG, "%s() value:'%s'", __func__, *value);
196 ret = SUCCEED;
197 out:
198 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
199
200 return ret;
201 }
202
203 /******************************************************************************
204 * *
205 * Function: get_function_parameter_hist_range *
206 * *
207 * Purpose: get the value of sec|num + timeshift trigger function parameter *
208 * *
209 * Parameters: from - [IN] the function calculation time *
210 * parameters - [IN] trigger function parameters *
211 * Nparam - [IN] specifies which parameter to extract *
212 * value - [OUT] parameter value (preserved as is if the *
213 * parameter is optional and empty) *
214 * type - [OUT] parameter value type (number of seconds *
215 * or number of values) *
216 * timeshift - [OUT] the timeshift value (0 if absent) *
217 * *
218 * Return value: SUCCEED - parameter is valid *
219 * FAIL - otherwise *
220 * *
221 ******************************************************************************/
get_function_parameter_hist_range(int from,const char * parameters,int Nparam,int * value,zbx_value_type_t * type,int * timeshift)222 static int get_function_parameter_hist_range(int from, const char *parameters, int Nparam, int *value,
223 zbx_value_type_t *type, int *timeshift)
224 {
225 char *parameter = NULL, *shift;
226 int ret = FAIL;
227
228 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
229
230 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
231 goto out;
232
233 if (NULL != (shift = strchr(parameter, ':')))
234 *shift++ = '\0';
235
236 if ('\0' == *parameter)
237 {
238 *value = 0;
239 *type = ZBX_VALUE_NONE;
240 }
241 else if ('#' != *parameter)
242 {
243 if (SUCCEED != is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED) || 0 > *value)
244 goto out;
245
246 *type = ZBX_VALUE_SECONDS;
247 }
248 else
249 {
250 if (SUCCEED != is_uint31(parameter + 1, value) || 0 >= *value)
251 goto out;
252 *type = ZBX_VALUE_NVALUES;
253 }
254
255 if (NULL != shift)
256 {
257 struct tm tm;
258 char *error = NULL;
259 int end;
260
261 if (SUCCEED != zbx_parse_timeshift(from, shift, &tm, &error))
262 {
263 zabbix_log(LOG_LEVEL_DEBUG, "%s() timeshift error:%s", __func__, error);
264 zbx_free(error);
265 goto out;
266 }
267
268 if (-1 == (end = mktime(&tm)))
269 {
270 zabbix_log(LOG_LEVEL_DEBUG, "%s() invalid timeshift value:%s", __func__, zbx_strerror(errno));
271 goto out;
272 }
273
274 *timeshift = from - end;
275 }
276 else
277 *timeshift = 0;
278
279 ret = SUCCEED;
280 zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d timeshift:%d", __func__, zbx_type_string(*type), *value,
281 *timeshift);
282 out:
283 zbx_free(parameter);
284
285 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
286
287 return ret;
288 }
289
290 /******************************************************************************
291 * *
292 * Function: get_last_n_value *
293 * *
294 * Purpose: get last Nth value defined by #num:now-timeshift first parameter *
295 * *
296 * Parameters: item - [IN] item (performance metric) *
297 * parameters - [IN] the parameter string with #sec|num/timeshift *
298 * in first parameter *
299 * ts - [IN] the starting timestamp *
300 * value - [OUT] the Nth value *
301 * error - [OUT] the error message *
302 * *
303 * Return value: SUCCEED - value was found successfully copied *
304 * FAIL - otherwise *
305 * *
306 ******************************************************************************/
get_last_n_value(const DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,zbx_history_record_t * value,char ** error)307 static int get_last_n_value(const DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
308 zbx_history_record_t *value, char **error)
309 {
310 int arg1 = 1, ret = FAIL, time_shift;
311 zbx_value_type_t arg1_type = ZBX_VALUE_NVALUES;
312 zbx_vector_history_record_t values;
313 zbx_timespec_t ts_end = *ts;
314
315 zbx_history_record_vector_create(&values);
316
317 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift))
318 {
319 *error = zbx_strdup(*error, "invalid second parameter");
320 goto out;
321 }
322
323 if (ZBX_VALUE_NVALUES != arg1_type)
324 arg1 = 1; /* time or non parameter is defaulted to "last(0)" */
325
326 ts_end.sec -= time_shift;
327
328 if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, arg1, &ts_end))
329 {
330 *error = zbx_strdup(*error, "cannot get values from value cache");
331 goto out;
332 }
333
334 if (arg1 <= values.values_num)
335 {
336 *value = values.values[arg1 - 1];
337 zbx_vector_history_record_remove(&values, arg1 - 1);
338 ret = SUCCEED;
339 }
340 else
341 *error = zbx_strdup(*error, "not enough data");
342 out:
343 zbx_history_record_vector_destroy(&values, item->value_type);
344
345 return ret;
346 }
347
348 /******************************************************************************
349 * *
350 * Function: evaluate_LOGEVENTID *
351 * *
352 * Purpose: evaluate function 'logeventid' for the item *
353 * *
354 * Parameters: item - item (performance metric) *
355 * parameter - regex string for event id matching *
356 * *
357 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
358 * FAIL - failed to evaluate function *
359 * *
360 ******************************************************************************/
evaluate_LOGEVENTID(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)361 static int evaluate_LOGEVENTID(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
362 const zbx_timespec_t *ts, char **error)
363 {
364 char *pattern = NULL;
365 int ret = FAIL, nparams;
366 zbx_vector_ptr_t regexps;
367 zbx_history_record_t vc_value;
368
369 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
370
371 zbx_vector_ptr_create(®exps);
372
373 if (ITEM_VALUE_TYPE_LOG != item->value_type)
374 {
375 *error = zbx_strdup(*error, "invalid value type");
376 goto out;
377 }
378
379 if (2 < (nparams = num_param(parameters)))
380 {
381 *error = zbx_strdup(*error, "invalid number of parameters");
382 goto out;
383 }
384
385 if (2 == nparams)
386 {
387 if (SUCCEED != get_function_parameter_str(parameters, 2, &pattern))
388 {
389 *error = zbx_strdup(*error, "invalid third parameter");
390 goto out;
391 }
392
393 if ('@' == *pattern)
394 {
395 DCget_expressions_by_name(®exps, pattern + 1);
396
397 if (0 == regexps.values_num)
398 {
399 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist",
400 pattern + 1);
401 goto out;
402 }
403 }
404 }
405 else
406 pattern = zbx_strdup(NULL, "");
407
408 if (SUCCEED == get_last_n_value(item, parameters, ts, &vc_value, error))
409 {
410 char logeventid[16];
411 int regexp_ret;
412
413 zbx_snprintf(logeventid, sizeof(logeventid), "%d", vc_value.value.log->logeventid);
414
415 if (FAIL == (regexp_ret = regexp_match_ex(®exps, logeventid, pattern, ZBX_CASE_SENSITIVE)))
416 {
417 *error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", pattern);
418 }
419 else
420 {
421 if (ZBX_REGEXP_MATCH == regexp_ret)
422 zbx_variant_set_dbl(value, 1);
423 else if (ZBX_REGEXP_NO_MATCH == regexp_ret)
424 zbx_variant_set_dbl(value, 0);
425
426 ret = SUCCEED;
427 }
428
429 zbx_history_record_clear(&vc_value, item->value_type);
430 }
431 else
432 zabbix_log(LOG_LEVEL_DEBUG, "result for LOGEVENTID is empty");
433 out:
434 zbx_free(pattern);
435
436 zbx_regexp_clean_expressions(®exps);
437 zbx_vector_ptr_destroy(®exps);
438
439 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
440
441 return ret;
442 }
443
444 /******************************************************************************
445 * *
446 * Function: evaluate_LOGSOURCE *
447 * *
448 * Purpose: evaluate function 'logsource' for the item *
449 * *
450 * Parameters: item - item (performance metric) *
451 * parameter - ignored *
452 * *
453 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
454 * FAIL - failed to evaluate function *
455 * *
456 ******************************************************************************/
evaluate_LOGSOURCE(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)457 static int evaluate_LOGSOURCE(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
458 char **error)
459 {
460 char *pattern = NULL;
461 int ret = FAIL, nparams;
462 zbx_vector_ptr_t regexps;
463 zbx_history_record_t vc_value;
464
465 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
466
467 zbx_vector_ptr_create(®exps);
468
469 if (ITEM_VALUE_TYPE_LOG != item->value_type)
470 {
471 *error = zbx_strdup(*error, "invalid value type");
472 goto out;
473 }
474
475 if (2 < (nparams = num_param(parameters)))
476 {
477 *error = zbx_strdup(*error, "invalid number of parameters");
478 goto out;
479 }
480
481 if (2 == nparams)
482 {
483 if (SUCCEED != get_function_parameter_str(parameters, 2, &pattern))
484 {
485 *error = zbx_strdup(*error, "invalid third parameter");
486 goto out;
487 }
488
489 if ('@' == *pattern)
490 {
491 DCget_expressions_by_name(®exps, pattern + 1);
492
493 if (0 == regexps.values_num)
494 {
495 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist",
496 pattern + 1);
497 goto out;
498 }
499 }
500 }
501 else
502 pattern = zbx_strdup(NULL, "");
503
504 if (SUCCEED == get_last_n_value(item, parameters, ts, &vc_value, error))
505 {
506 switch (regexp_match_ex(®exps, vc_value.value.log->source, pattern, ZBX_CASE_SENSITIVE))
507 {
508 case ZBX_REGEXP_MATCH:
509 zbx_variant_set_dbl(value, 1);
510 ret = SUCCEED;
511 break;
512 case ZBX_REGEXP_NO_MATCH:
513 zbx_variant_set_dbl(value, 0);
514 ret = SUCCEED;
515 break;
516 case FAIL:
517 *error = zbx_dsprintf(*error, "invalid regular expression");
518 }
519
520 zbx_history_record_clear(&vc_value, item->value_type);
521 }
522 else
523 zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSOURCE is empty");
524 out:
525 zbx_free(pattern);
526
527 zbx_regexp_clean_expressions(®exps);
528 zbx_vector_ptr_destroy(®exps);
529
530 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
531
532 return ret;
533 }
534
535 /******************************************************************************
536 * *
537 * Function: evaluate_LOGSEVERITY *
538 * *
539 * Purpose: evaluate function 'logseverity' for the item *
540 * *
541 * Parameters: item - item (performance metric) *
542 * *
543 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
544 * FAIL - failed to evaluate function *
545 * *
546 ******************************************************************************/
evaluate_LOGSEVERITY(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)547 static int evaluate_LOGSEVERITY(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
548 const zbx_timespec_t *ts, char **error)
549 {
550 int ret = FAIL;
551 zbx_history_record_t vc_value;
552
553 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
554
555 if (ITEM_VALUE_TYPE_LOG != item->value_type)
556 {
557 *error = zbx_strdup(*error, "invalid value type");
558 goto out;
559 }
560
561 if (1 < num_param(parameters))
562 {
563 *error = zbx_strdup(*error, "invalid number of parameters");
564 goto out;
565 }
566
567 if (SUCCEED == get_last_n_value(item, parameters, ts, &vc_value, error))
568 {
569 zbx_variant_set_dbl(value, vc_value.value.log->severity);
570 zbx_history_record_clear(&vc_value, item->value_type);
571
572 ret = SUCCEED;
573 }
574 else
575 zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSEVERITY is empty");
576 out:
577 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
578
579 return ret;
580 }
581
history_record_float_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)582 static int history_record_float_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
583 {
584 ZBX_RETURN_IF_NOT_EQUAL(d1->value.dbl, d2->value.dbl);
585
586 return 0;
587 }
588
history_record_uint64_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)589 static int history_record_uint64_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
590 {
591 ZBX_RETURN_IF_NOT_EQUAL(d1->value.ui64, d2->value.ui64);
592
593 return 0;
594 }
595
history_record_str_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)596 static int history_record_str_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
597 {
598 return strcmp(d1->value.str, d2->value.str);
599 }
600
history_record_log_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)601 static int history_record_log_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
602 {
603 int value_match;
604
605 if (0 != (value_match = strcmp(d1->value.log->value, d2->value.log->value)))
606 return value_match;
607
608 if (NULL != d1->value.log->source && NULL != d2->value.log->source)
609 return strcmp(d1->value.log->source, d2->value.log->source);
610
611 if (NULL != d2->value.log->source)
612 return -1;
613
614 if (NULL != d1->value.log->source)
615 return 1;
616
617 return 0;
618 }
619
620 /* specialized versions of zbx_vector_history_record_*_uniq() because */
621 /* standard versions do not release memory occupied by duplicate elements */
622
zbx_vector_history_record_str_uniq(zbx_vector_history_record_t * vector,zbx_compare_func_t compare_func)623 static void zbx_vector_history_record_str_uniq(zbx_vector_history_record_t *vector, zbx_compare_func_t compare_func)
624 {
625 if (2 <= vector->values_num)
626 {
627 int i = 0, j = 1;
628
629 while (j < vector->values_num)
630 {
631 if (0 != compare_func(&vector->values[i], &vector->values[j]))
632 {
633 i++;
634 j++;
635 }
636 else
637 {
638 zbx_free(vector->values[j].value.str);
639 zbx_vector_history_record_remove(vector, j);
640 }
641 }
642 }
643 }
644
zbx_vector_history_record_log_uniq(zbx_vector_history_record_t * vector,zbx_compare_func_t compare_func)645 static void zbx_vector_history_record_log_uniq(zbx_vector_history_record_t *vector, zbx_compare_func_t compare_func)
646 {
647 if (2 <= vector->values_num)
648 {
649 int i = 0, j = 1;
650
651 while (j < vector->values_num)
652 {
653 if (0 != compare_func(&vector->values[i], &vector->values[j]))
654 {
655 i++;
656 j++;
657 }
658 else
659 {
660 zbx_free(vector->values[j].value.log->source);
661 zbx_free(vector->values[j].value.log->value);
662 zbx_free(vector->values[j].value.log);
663 zbx_vector_history_record_remove(vector, j);
664 }
665 }
666 }
667 }
668
669 #define OP_UNKNOWN -1
670 #define OP_EQ 0
671 #define OP_NE 1
672 #define OP_GT 2
673 #define OP_GE 3
674 #define OP_LT 4
675 #define OP_LE 5
676 #define OP_LIKE 6
677 #define OP_REGEXP 7
678 #define OP_IREGEXP 8
679 #define OP_BITAND 9
680
count_one_ui64(int * count,int op,zbx_uint64_t value,zbx_uint64_t pattern,zbx_uint64_t mask)681 static void count_one_ui64(int *count, int op, zbx_uint64_t value, zbx_uint64_t pattern, zbx_uint64_t mask)
682 {
683 switch (op)
684 {
685 case OP_EQ:
686 if (value == pattern)
687 (*count)++;
688 break;
689 case OP_NE:
690 if (value != pattern)
691 (*count)++;
692 break;
693 case OP_GT:
694 if (value > pattern)
695 (*count)++;
696 break;
697 case OP_GE:
698 if (value >= pattern)
699 (*count)++;
700 break;
701 case OP_LT:
702 if (value < pattern)
703 (*count)++;
704 break;
705 case OP_LE:
706 if (value <= pattern)
707 (*count)++;
708 break;
709 case OP_BITAND:
710 if ((value & mask) == pattern)
711 (*count)++;
712 }
713 }
714
count_one_dbl(int * count,int op,double value,double pattern)715 static void count_one_dbl(int *count, int op, double value, double pattern)
716 {
717 switch (op)
718 {
719 case OP_EQ:
720 if (value > pattern - ZBX_DOUBLE_EPSILON && value < pattern + ZBX_DOUBLE_EPSILON)
721 (*count)++;
722 break;
723 case OP_NE:
724 if (!(value > pattern - ZBX_DOUBLE_EPSILON && value < pattern + ZBX_DOUBLE_EPSILON))
725 (*count)++;
726 break;
727 case OP_GT:
728 if (value >= pattern + ZBX_DOUBLE_EPSILON)
729 (*count)++;
730 break;
731 case OP_GE:
732 if (value > pattern - ZBX_DOUBLE_EPSILON)
733 (*count)++;
734 break;
735 case OP_LT:
736 if (value <= pattern - ZBX_DOUBLE_EPSILON)
737 (*count)++;
738 break;
739 case OP_LE:
740 if (value < pattern + ZBX_DOUBLE_EPSILON)
741 (*count)++;
742 }
743 }
744
count_one_str(int * count,int op,const char * value,const char * pattern,zbx_vector_ptr_t * regexps)745 static void count_one_str(int *count, int op, const char *value, const char *pattern, zbx_vector_ptr_t *regexps)
746 {
747 int res;
748
749 switch (op)
750 {
751 case OP_EQ:
752 if (0 == strcmp(value, pattern))
753 (*count)++;
754 break;
755 case OP_NE:
756 if (0 != strcmp(value, pattern))
757 (*count)++;
758 break;
759 case OP_LIKE:
760 if (NULL != strstr(value, pattern))
761 (*count)++;
762 break;
763 case OP_REGEXP:
764 if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_CASE_SENSITIVE)))
765 (*count)++;
766 else if (FAIL == res)
767 *count = FAIL;
768 break;
769 case OP_IREGEXP:
770 if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_IGNORE_CASE)))
771 (*count)++;
772 else if (FAIL == res)
773 *count = FAIL;
774 }
775 }
776
777 /* flags for evaluate_COUNT() */
778 #define COUNT_ALL 0
779 #define COUNT_UNIQUE 1
780
781 /******************************************************************************
782 * *
783 * Function: evaluate_COUNT *
784 * *
785 * Purpose: evaluate functions 'count' and 'find' for the item *
786 * *
787 * Parameters: item - [IN] item (performance metric) *
788 * parameters - [IN] up to three comma-separated fields: *
789 * (1) number of seconds/values + timeshift *
790 * (2) comparison operator (optional) *
791 * (3) value to compare with (optional) *
792 * Becomes mandatory for numeric items if 3rd *
793 * parameter is specified and is not "regexp" *
794 * or "iregexp". With "bitand" can take one of *
795 * 2 forms: *
796 * - value_to_compare_with/mask *
797 * - mask *
798 * ts - [IN] the function evaluation time *
799 * limit - [IN] the limit of counted values, will return *
800 * when the limit is reached *
801 * unique - [IN] COUNT_ALL - count all values, *
802 * COUNT_UNIQUE - count unique values *
803 * error - [OUT] the error message *
804 * *
805 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
806 * FAIL - failed to evaluate function *
807 * *
808 ******************************************************************************/
evaluate_COUNT(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,int limit,int unique,char ** error)809 static int evaluate_COUNT(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
810 int limit, int unique, char **error)
811 {
812 int arg1, op = OP_UNKNOWN, numeric_search, nparams, count = 0, i, ret = FAIL;
813 int seconds = 0, nvalues = 0, time_shift;
814 char *operator = NULL, *pattern2 = NULL, *pattern = NULL, buf[ZBX_MAX_UINT64_LEN];
815 double arg3_dbl;
816 zbx_uint64_t pattern_ui64, pattern2_ui64;
817 zbx_value_type_t arg1_type;
818 zbx_vector_ptr_t regexps;
819 zbx_vector_history_record_t values;
820 zbx_timespec_t ts_end = *ts;
821
822 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
823
824 zbx_vector_ptr_create(®exps);
825 zbx_history_record_vector_create(&values);
826
827 numeric_search = (ITEM_VALUE_TYPE_UINT64 == item->value_type || ITEM_VALUE_TYPE_FLOAT == item->value_type);
828
829 if (3 < (nparams = num_param(parameters)))
830 {
831 *error = zbx_strdup(*error, "invalid number of parameters");
832 goto out;
833 }
834
835 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift))
836 {
837 *error = zbx_strdup(*error, "invalid second parameter");
838 goto out;
839 }
840
841 if (2 <= nparams && SUCCEED != get_function_parameter_str(parameters, 2, &operator))
842 {
843 *error = zbx_strdup(*error, "invalid third parameter");
844 goto out;
845 }
846
847 if (3 <= nparams)
848 {
849 if (SUCCEED != get_function_parameter_str(parameters, 3, &pattern))
850 {
851 *error = zbx_strdup(*error, "invalid fourth parameter");
852 goto out;
853 }
854 }
855 else
856 pattern = zbx_strdup(NULL, "");
857
858 ts_end.sec -= time_shift;
859
860 if (NULL == operator || '\0' == *operator)
861 op = (0 != numeric_search ? OP_EQ : OP_LIKE);
862 else if (0 == strcmp(operator, "eq"))
863 op = OP_EQ;
864 else if (0 == strcmp(operator, "ne"))
865 op = OP_NE;
866 else if (0 == strcmp(operator, "gt"))
867 op = OP_GT;
868 else if (0 == strcmp(operator, "ge"))
869 op = OP_GE;
870 else if (0 == strcmp(operator, "lt"))
871 op = OP_LT;
872 else if (0 == strcmp(operator, "le"))
873 op = OP_LE;
874 else if (0 == strcmp(operator, "like"))
875 op = OP_LIKE;
876 else if (0 == strcmp(operator, "regexp"))
877 op = OP_REGEXP;
878 else if (0 == strcmp(operator, "iregexp"))
879 op = OP_IREGEXP;
880 else if (0 == strcmp(operator, "bitand"))
881 op = OP_BITAND;
882
883 if (OP_UNKNOWN == op)
884 {
885 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for function COUNT", operator);
886 goto out;
887 }
888
889 numeric_search = (0 != numeric_search && OP_REGEXP != op && OP_IREGEXP != op);
890
891 if (0 != numeric_search)
892 {
893 if (NULL != operator && '\0' != *operator && '\0' == *pattern)
894 {
895 *error = zbx_strdup(*error, "pattern must be provided along with operator for numeric values");
896 goto out;
897 }
898
899 if (OP_LIKE == op)
900 {
901 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting numeric values",
902 operator);
903 goto out;
904 }
905
906 if (OP_BITAND == op && ITEM_VALUE_TYPE_FLOAT == item->value_type)
907 {
908 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting float values",
909 operator);
910 goto out;
911 }
912
913 if (OP_BITAND == op && NULL != (pattern2 = strchr(pattern, '/')))
914 {
915 *pattern2 = '\0'; /* end of the 1st part of the 2nd parameter (number to compare with) */
916 pattern2++; /* start of the 2nd part of the 2nd parameter (mask) */
917 }
918
919 if (NULL != pattern && '\0' != *pattern)
920 {
921 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
922 {
923 if (OP_BITAND != op)
924 {
925 if (SUCCEED != str2uint64(pattern, ZBX_UNIT_SYMBOLS, &pattern_ui64))
926 {
927 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned"
928 " value", pattern);
929 goto out;
930 }
931 pattern2_ui64 = 0;
932 }
933 else
934 {
935 if (SUCCEED != is_uint64(pattern, &pattern_ui64))
936 {
937 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned"
938 " value", pattern);
939 goto out;
940 }
941
942 if (NULL != pattern2)
943 {
944 if (SUCCEED != is_uint64(pattern2, &pattern2_ui64))
945 {
946 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric"
947 " unsigned value", pattern2);
948 goto out;
949 }
950 }
951 else
952 pattern2_ui64 = pattern_ui64;
953 }
954 }
955 else
956 {
957 if (SUCCEED != is_double_suffix(pattern, ZBX_FLAG_DOUBLE_SUFFIX))
958 {
959 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric float value",
960 pattern);
961 goto out;
962 }
963
964 arg3_dbl = str2double(pattern);
965 }
966 }
967 }
968 else if (OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op && OP_EQ != op && OP_NE != op)
969 {
970 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting textual values", operator);
971 goto out;
972 }
973
974 if ((OP_REGEXP == op || OP_IREGEXP == op) && NULL != pattern && '@' == *pattern)
975 {
976 DCget_expressions_by_name(®exps, pattern + 1);
977
978 if (0 == regexps.values_num)
979 {
980 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", pattern + 1);
981 goto out;
982 }
983 }
984
985 switch (arg1_type)
986 {
987 case ZBX_VALUE_SECONDS:
988 seconds = arg1;
989 break;
990 case ZBX_VALUE_NVALUES:
991 nvalues = arg1;
992 break;
993 case ZBX_VALUE_NONE:
994 nvalues = 1;
995 break;
996 default:
997 THIS_SHOULD_NEVER_HAPPEN;
998 }
999
1000 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1001 {
1002 *error = zbx_strdup(*error, "cannot get values from value cache");
1003 goto out;
1004 }
1005
1006 if (COUNT_UNIQUE == unique)
1007 {
1008 switch (item->value_type)
1009 {
1010 case ITEM_VALUE_TYPE_UINT64:
1011 zbx_vector_history_record_sort(&values,
1012 (zbx_compare_func_t)history_record_uint64_compare);
1013 zbx_vector_history_record_uniq(&values,
1014 (zbx_compare_func_t)history_record_uint64_compare);
1015 break;
1016 case ITEM_VALUE_TYPE_FLOAT:
1017 zbx_vector_history_record_sort(&values,
1018 (zbx_compare_func_t)history_record_float_compare);
1019 zbx_vector_history_record_uniq(&values,
1020 (zbx_compare_func_t)history_record_float_compare);
1021 break;
1022 case ITEM_VALUE_TYPE_LOG:
1023 zbx_vector_history_record_sort(&values,
1024 (zbx_compare_func_t)history_record_log_compare);
1025 zbx_vector_history_record_log_uniq(&values,
1026 (zbx_compare_func_t)history_record_log_compare);
1027 break;
1028 default:
1029 zbx_vector_history_record_sort(&values,
1030 (zbx_compare_func_t)history_record_str_compare);
1031 zbx_vector_history_record_str_uniq(&values,
1032 (zbx_compare_func_t)history_record_str_compare);
1033 }
1034 }
1035
1036 /* skip counting values one by one if both pattern and operator are empty or "" is searched in text values */
1037 if ((NULL != pattern && '\0' != *pattern) || (NULL != operator && '\0' != *operator &&
1038 OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op))
1039 {
1040 switch (item->value_type)
1041 {
1042 case ITEM_VALUE_TYPE_UINT64:
1043 if (0 != numeric_search)
1044 {
1045 for (i = 0; i < values.values_num && count < limit; i++)
1046 {
1047 count_one_ui64(&count, op, values.values[i].value.ui64, pattern_ui64,
1048 pattern2_ui64);
1049 }
1050 }
1051 else
1052 {
1053 for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1054 {
1055 zbx_snprintf(buf, sizeof(buf), ZBX_FS_UI64,
1056 values.values[i].value.ui64);
1057 count_one_str(&count, op, buf, pattern, ®exps);
1058 }
1059 }
1060 break;
1061 case ITEM_VALUE_TYPE_FLOAT:
1062 if (0 != numeric_search)
1063 {
1064 for (i = 0; i < values.values_num && count < limit; i++)
1065 count_one_dbl(&count, op, values.values[i].value.dbl, arg3_dbl);
1066 }
1067 else
1068 {
1069 for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1070 {
1071 zbx_snprintf(buf, sizeof(buf), ZBX_FS_DBL_EXT(4),
1072 values.values[i].value.dbl);
1073 count_one_str(&count, op, buf, pattern, ®exps);
1074 }
1075 }
1076 break;
1077 case ITEM_VALUE_TYPE_LOG:
1078 for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1079 count_one_str(&count, op, values.values[i].value.log->value, pattern, ®exps);
1080 break;
1081 default:
1082 for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1083 count_one_str(&count, op, values.values[i].value.str, pattern, ®exps);
1084 }
1085
1086 if (FAIL == count)
1087 {
1088 *error = zbx_strdup(*error, "invalid regular expression");
1089 goto out;
1090 }
1091 }
1092 else
1093 {
1094 if ((count = values.values_num) > limit)
1095 count = limit;
1096 }
1097
1098 zbx_variant_set_dbl(value, count);
1099
1100 ret = SUCCEED;
1101 out:
1102 zbx_free(operator);
1103 zbx_free(pattern);
1104
1105 zbx_regexp_clean_expressions(®exps);
1106 zbx_vector_ptr_destroy(®exps);
1107
1108 zbx_history_record_vector_destroy(&values, item->value_type);
1109
1110 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1111
1112 return ret;
1113 }
1114
1115 #undef OP_UNKNOWN
1116 #undef OP_EQ
1117 #undef OP_NE
1118 #undef OP_GT
1119 #undef OP_GE
1120 #undef OP_LT
1121 #undef OP_LE
1122 #undef OP_LIKE
1123 #undef OP_REGEXP
1124 #undef OP_IREGEXP
1125 #undef OP_BITAND
1126
1127 /******************************************************************************
1128 * *
1129 * Function: evaluate_SUM *
1130 * *
1131 * Purpose: evaluate function 'sum' for the item *
1132 * *
1133 * Parameters: item - item (performance metric) *
1134 * parameters - number of seconds/values and time shift (optional)*
1135 * *
1136 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1137 * FAIL - failed to evaluate function *
1138 * *
1139 ******************************************************************************/
evaluate_SUM(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1140 static int evaluate_SUM(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1141 {
1142 int arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
1143 zbx_value_type_t arg1_type;
1144 zbx_vector_history_record_t values;
1145 history_value_t result;
1146 zbx_timespec_t ts_end = *ts;
1147
1148 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1149
1150 zbx_history_record_vector_create(&values);
1151
1152 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1153 {
1154 *error = zbx_strdup(*error, "invalid value type");
1155 goto out;
1156 }
1157
1158 if (1 != num_param(parameters))
1159 {
1160 *error = zbx_strdup(*error, "invalid number of parameters");
1161 goto out;
1162 }
1163
1164 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1165 ZBX_VALUE_NONE == arg1_type)
1166 {
1167 *error = zbx_strdup(*error, "invalid second parameter");
1168 goto out;
1169 }
1170
1171 ts_end.sec -= time_shift;
1172
1173 switch (arg1_type)
1174 {
1175 case ZBX_VALUE_SECONDS:
1176 seconds = arg1;
1177 break;
1178 case ZBX_VALUE_NVALUES:
1179 nvalues = arg1;
1180 break;
1181 default:
1182 THIS_SHOULD_NEVER_HAPPEN;
1183 }
1184
1185 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1186 {
1187 *error = zbx_strdup(*error, "cannot get values from value cache");
1188 goto out;
1189 }
1190
1191 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1192 {
1193 result.dbl = 0;
1194
1195 for (i = 0; i < values.values_num; i++)
1196 result.dbl += values.values[i].value.dbl;
1197 }
1198 else
1199 {
1200 result.ui64 = 0;
1201
1202 for (i = 0; i < values.values_num; i++)
1203 result.ui64 += values.values[i].value.ui64;
1204 }
1205
1206 zbx_history_value2variant(&result, item->value_type, value);
1207 ret = SUCCEED;
1208 out:
1209 zbx_history_record_vector_destroy(&values, item->value_type);
1210
1211 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1212
1213 return ret;
1214 }
1215
1216 /******************************************************************************
1217 * *
1218 * Function: evaluate_AVG *
1219 * *
1220 * Purpose: evaluate function 'avg' for the item *
1221 * *
1222 * Parameters: item - item (performance metric) *
1223 * parameters - number of seconds/values and time shift (optional)*
1224 * *
1225 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1226 * FAIL - failed to evaluate function *
1227 * *
1228 ******************************************************************************/
evaluate_AVG(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1229 static int evaluate_AVG(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1230 {
1231 int arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift;
1232 zbx_value_type_t arg1_type;
1233 zbx_vector_history_record_t values;
1234 zbx_timespec_t ts_end = *ts;
1235
1236 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1237
1238 zbx_history_record_vector_create(&values);
1239
1240 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1241 {
1242 *error = zbx_strdup(*error, "invalid value type");
1243 goto out;
1244 }
1245
1246 if (1 != num_param(parameters))
1247 {
1248 *error = zbx_strdup(*error, "invalid number of parameters");
1249 goto out;
1250 }
1251
1252 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1253 ZBX_VALUE_NONE == arg1_type)
1254 {
1255 *error = zbx_strdup(*error, "invalid second parameter");
1256 goto out;
1257 }
1258
1259 ts_end.sec -= time_shift;
1260
1261 switch (arg1_type)
1262 {
1263 case ZBX_VALUE_SECONDS:
1264 seconds = arg1;
1265 break;
1266 case ZBX_VALUE_NVALUES:
1267 nvalues = arg1;
1268 break;
1269 default:
1270 THIS_SHOULD_NEVER_HAPPEN;
1271 }
1272
1273 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1274 {
1275 *error = zbx_strdup(*error, "cannot get values from value cache");
1276 goto out;
1277 }
1278
1279 if (0 < values.values_num)
1280 {
1281 double avg = 0;
1282
1283 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1284 {
1285 for (i = 0; i < values.values_num; i++)
1286 avg += values.values[i].value.dbl / (i + 1) - avg / (i + 1);
1287 }
1288 else
1289 {
1290 for (i = 0; i < values.values_num; i++)
1291 avg += (double)values.values[i].value.ui64;
1292
1293 avg = avg / values.values_num;
1294 }
1295 zbx_variant_set_dbl(value, avg);
1296
1297 ret = SUCCEED;
1298 }
1299 else
1300 {
1301 zabbix_log(LOG_LEVEL_DEBUG, "result for AVG is empty");
1302 *error = zbx_strdup(*error, "not enough data");
1303 }
1304 out:
1305 zbx_history_record_vector_destroy(&values, item->value_type);
1306
1307 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1308
1309 return ret;
1310 }
1311
1312 /******************************************************************************
1313 * *
1314 * Function: evaluate_LAST *
1315 * *
1316 * Purpose: evaluate function 'last' for the item *
1317 * *
1318 * Parameters: value - dynamic buffer *
1319 * item - item (performance metric) *
1320 * parameters - Nth last value and time shift (optional) *
1321 * *
1322 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1323 * FAIL - failed to evaluate function *
1324 * *
1325 ******************************************************************************/
evaluate_LAST(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1326 static int evaluate_LAST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1327 char **error)
1328 {
1329 int ret;
1330 zbx_history_record_t vc_value;
1331
1332 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1333
1334 if (SUCCEED == (ret = get_last_n_value(item, parameters, ts, &vc_value, error)))
1335 {
1336 zbx_history_value2variant(&vc_value.value, item->value_type, value);
1337 zbx_history_record_clear(&vc_value, item->value_type);
1338 }
1339
1340 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1341
1342 return ret;
1343 }
1344
1345 /******************************************************************************
1346 * *
1347 * Function: evaluate_MIN *
1348 * *
1349 * Purpose: evaluate function 'min' for the item *
1350 * *
1351 * Parameters: item - item (performance metric) *
1352 * parameters - number of seconds/values and time shift (optional)*
1353 * *
1354 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1355 * FAIL - failed to evaluate function *
1356 * *
1357 ******************************************************************************/
evaluate_MIN(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1358 static int evaluate_MIN(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1359 {
1360 int arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
1361 zbx_value_type_t arg1_type;
1362 zbx_vector_history_record_t values;
1363 zbx_timespec_t ts_end = *ts;
1364
1365 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1366
1367 zbx_history_record_vector_create(&values);
1368
1369 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1370 {
1371 *error = zbx_strdup(*error, "invalid value type");
1372 goto out;
1373 }
1374
1375 if (1 != num_param(parameters))
1376 {
1377 *error = zbx_strdup(*error, "invalid number of parameters");
1378 goto out;
1379 }
1380
1381 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1382 ZBX_VALUE_NONE == arg1_type)
1383 {
1384 *error = zbx_strdup(*error, "invalid second parameter");
1385 goto out;
1386 }
1387
1388 ts_end.sec -= time_shift;
1389
1390 switch (arg1_type)
1391 {
1392 case ZBX_VALUE_SECONDS:
1393 seconds = arg1;
1394 break;
1395 case ZBX_VALUE_NVALUES:
1396 nvalues = arg1;
1397 break;
1398 default:
1399 THIS_SHOULD_NEVER_HAPPEN;
1400 }
1401
1402 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1403 {
1404 *error = zbx_strdup(*error, "cannot get values from value cache");
1405 goto out;
1406 }
1407
1408 if (0 < values.values_num)
1409 {
1410 int index = 0;
1411
1412 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1413 {
1414 for (i = 1; i < values.values_num; i++)
1415 {
1416 if (values.values[i].value.ui64 < values.values[index].value.ui64)
1417 index = i;
1418 }
1419 }
1420 else
1421 {
1422 for (i = 1; i < values.values_num; i++)
1423 {
1424 if (values.values[i].value.dbl < values.values[index].value.dbl)
1425 index = i;
1426 }
1427 }
1428
1429 zbx_history_value2variant(&values.values[index].value, item->value_type, value);
1430 ret = SUCCEED;
1431 }
1432 else
1433 {
1434 zabbix_log(LOG_LEVEL_DEBUG, "result for MIN is empty");
1435 *error = zbx_strdup(*error, "not enough data");
1436 }
1437 out:
1438 zbx_history_record_vector_destroy(&values, item->value_type);
1439
1440 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1441
1442 return ret;
1443 }
1444
1445 /******************************************************************************
1446 * *
1447 * Function: evaluate_MAX *
1448 * *
1449 * Purpose: evaluate function 'max' for the item *
1450 * *
1451 * Parameters: item - item (performance metric) *
1452 * parameters - number of seconds/values and time shift (optional)*
1453 * *
1454 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1455 * FAIL - failed to evaluate function *
1456 * *
1457 ******************************************************************************/
evaluate_MAX(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1458 static int evaluate_MAX(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1459 {
1460 int arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift;
1461 zbx_value_type_t arg1_type;
1462 zbx_vector_history_record_t values;
1463 zbx_timespec_t ts_end = *ts;
1464
1465 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1466
1467 zbx_history_record_vector_create(&values);
1468
1469 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1470 {
1471 *error = zbx_strdup(*error, "invalid value type");
1472 goto out;
1473 }
1474
1475 if (1 != num_param(parameters))
1476 {
1477 *error = zbx_strdup(*error, "invalid number of parameters");
1478 goto out;
1479 }
1480
1481 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1482 ZBX_VALUE_NONE == arg1_type)
1483 {
1484 *error = zbx_strdup(*error, "invalid second parameter");
1485 goto out;
1486 }
1487
1488 ts_end.sec -= time_shift;
1489
1490 switch (arg1_type)
1491 {
1492 case ZBX_VALUE_SECONDS:
1493 seconds = arg1;
1494 break;
1495 case ZBX_VALUE_NVALUES:
1496 nvalues = arg1;
1497 break;
1498 default:
1499 THIS_SHOULD_NEVER_HAPPEN;
1500 }
1501
1502 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1503 {
1504 *error = zbx_strdup(*error, "cannot get values from value cache");
1505 goto out;
1506 }
1507
1508 if (0 < values.values_num)
1509 {
1510 int index = 0;
1511
1512 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1513 {
1514 for (i = 1; i < values.values_num; i++)
1515 {
1516 if (values.values[i].value.ui64 > values.values[index].value.ui64)
1517 index = i;
1518 }
1519 }
1520 else
1521 {
1522 for (i = 1; i < values.values_num; i++)
1523 {
1524 if (values.values[i].value.dbl > values.values[index].value.dbl)
1525 index = i;
1526 }
1527 }
1528
1529 zbx_history_value2variant(&values.values[index].value, item->value_type, value);
1530
1531 ret = SUCCEED;
1532 }
1533 else
1534 {
1535 zabbix_log(LOG_LEVEL_DEBUG, "result for MAX is empty");
1536 *error = zbx_strdup(*error, "not enough data");
1537 }
1538 out:
1539 zbx_history_record_vector_destroy(&values, item->value_type);
1540
1541 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1542
1543 return ret;
1544 }
1545
1546 /******************************************************************************
1547 * *
1548 * Function: evaluate_PERCENTILE *
1549 * *
1550 * Purpose: evaluate function 'percentile' for the item *
1551 * *
1552 * Parameters: item - [IN] item (performance metric) *
1553 * parameters - [IN] seconds/values, time shift (optional), *
1554 * percentage *
1555 * *
1556 * Return value: SUCCEED - evaluated successfully, result is stored in *
1557 * 'value' *
1558 * FAIL - failed to evaluate function *
1559 * *
1560 ******************************************************************************/
evaluate_PERCENTILE(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1561 static int evaluate_PERCENTILE(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
1562 const zbx_timespec_t *ts, char **error)
1563 {
1564 int arg1, time_shift, ret = FAIL, seconds = 0, nvalues = 0;
1565 zbx_value_type_t arg1_type;
1566 double percentage;
1567 zbx_vector_history_record_t values;
1568 zbx_timespec_t ts_end = *ts;
1569
1570 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1571
1572 zbx_history_record_vector_create(&values);
1573
1574 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1575 {
1576 *error = zbx_strdup(*error, "invalid value type");
1577 goto out;
1578 }
1579
1580 if (2 != num_param(parameters))
1581 {
1582 *error = zbx_strdup(*error, "invalid number of parameters");
1583 goto out;
1584 }
1585
1586 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1587 ZBX_VALUE_NONE == arg1_type)
1588 {
1589 *error = zbx_strdup(*error, "invalid second parameter");
1590 goto out;
1591 }
1592
1593
1594 switch (arg1_type)
1595 {
1596 case ZBX_VALUE_SECONDS:
1597 seconds = arg1;
1598 break;
1599 case ZBX_VALUE_NVALUES:
1600 nvalues = arg1;
1601 break;
1602 default:
1603 THIS_SHOULD_NEVER_HAPPEN;
1604 }
1605
1606 ts_end.sec -= time_shift;
1607
1608 if (SUCCEED != get_function_parameter_float(parameters, 2, ZBX_FLAG_DOUBLE_PLAIN, &percentage) ||
1609 0.0 > percentage || 100.0 < percentage)
1610 {
1611 *error = zbx_strdup(*error, "invalid third parameter");
1612 goto out;
1613 }
1614
1615 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1616 {
1617 *error = zbx_strdup(*error, "cannot get values from value cache");
1618 goto out;
1619 }
1620
1621 if (0 < values.values_num)
1622 {
1623 int index;
1624
1625 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1626 zbx_vector_history_record_sort(&values, (zbx_compare_func_t)history_record_float_compare);
1627 else
1628 zbx_vector_history_record_sort(&values, (zbx_compare_func_t)history_record_uint64_compare);
1629
1630 if (0 == percentage)
1631 index = 1;
1632 else
1633 index = (int)ceil(values.values_num * (percentage / 100));
1634
1635 zbx_history_value2variant(&values.values[index - 1].value, item->value_type, value);
1636
1637 ret = SUCCEED;
1638 }
1639 else
1640 {
1641 zabbix_log(LOG_LEVEL_DEBUG, "result for PERCENTILE is empty");
1642 *error = zbx_strdup(*error, "not enough data");
1643 }
1644 out:
1645 zbx_history_record_vector_destroy(&values, item->value_type);
1646
1647 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1648
1649 return ret;
1650 }
1651
1652 /******************************************************************************
1653 * *
1654 * Function: evaluate_NODATA *
1655 * *
1656 * Purpose: evaluate function 'nodata' for the item *
1657 * *
1658 * Parameters: item - item (performance metric) *
1659 * parameter - number of seconds *
1660 * *
1661 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1662 * FAIL - failed to evaluate function *
1663 * *
1664 ******************************************************************************/
evaluate_NODATA(zbx_variant_t * value,DC_ITEM * item,const char * parameters,char ** error)1665 static int evaluate_NODATA(zbx_variant_t *value, DC_ITEM *item, const char *parameters, char **error)
1666 {
1667 int arg1, num, period, lazy = 1, ret = FAIL;
1668 zbx_value_type_t arg1_type;
1669 zbx_vector_history_record_t values;
1670 zbx_timespec_t ts;
1671 char *arg2 = NULL;
1672 zbx_proxy_suppress_t nodata_win;
1673
1674 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1675
1676 zbx_history_record_vector_create(&values);
1677
1678 if (2 < (num = num_param(parameters)))
1679 {
1680 *error = zbx_strdup(*error, "invalid number of parameters");
1681 goto out;
1682 }
1683
1684 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) ||
1685 ZBX_VALUE_SECONDS != arg1_type || 0 >= arg1)
1686 {
1687 *error = zbx_strdup(*error, "invalid second parameter");
1688 goto out;
1689 }
1690
1691 if (1 < num && (SUCCEED != get_function_parameter_str(parameters, 2, &arg2) ||
1692 ('\0' != *arg2 && 0 != (lazy = strcmp("strict", arg2)))))
1693 {
1694 *error = zbx_strdup(*error, "invalid third parameter");
1695 goto out;
1696 }
1697
1698 zbx_timespec(&ts);
1699 nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
1700
1701 if (0 != item->host.proxy_hostid && 0 != lazy)
1702 {
1703 int lastaccess;
1704
1705 if (SUCCEED != DCget_proxy_nodata_win(item->host.proxy_hostid, &nodata_win, &lastaccess))
1706 {
1707 *error = zbx_strdup(*error, "cannot retrieve proxy last access");
1708 goto out;
1709 }
1710
1711 period = arg1 + (ts.sec - lastaccess);
1712 }
1713 else
1714 period = arg1;
1715
1716 if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, period, 1, &ts) &&
1717 1 == values.values_num)
1718 {
1719 zbx_variant_set_dbl(value, 0);
1720 }
1721 else
1722 {
1723 int seconds;
1724
1725 if (SUCCEED != DCget_data_expected_from(item->itemid, &seconds))
1726 {
1727 *error = zbx_strdup(*error, "item does not exist, is disabled or belongs to a disabled host");
1728 goto out;
1729 }
1730
1731 if (seconds + arg1 > ts.sec)
1732 {
1733 *error = zbx_strdup(*error,
1734 "item does not have enough data after server start or item creation");
1735 goto out;
1736 }
1737
1738 if (0 != (nodata_win.flags & ZBX_PROXY_SUPPRESS_ACTIVE))
1739 {
1740 *error = zbx_strdup(*error, "historical data transfer from proxy is still in progress");
1741 goto out;
1742 }
1743
1744 zbx_variant_set_dbl(value, 1);
1745
1746 if (0 != item->host.proxy_hostid && 0 != lazy)
1747 {
1748 zabbix_log(LOG_LEVEL_TRACE, "Nodata in %s() flag:%d values_num:%d start_time:%d period:%d",
1749 __func__, nodata_win.flags, nodata_win.values_num, ts.sec - period, period);
1750 }
1751 }
1752
1753 ret = SUCCEED;
1754 out:
1755 zbx_history_record_vector_destroy(&values, item->value_type);
1756 zbx_free(arg2);
1757
1758 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1759
1760 return ret;
1761 }
1762
1763 /******************************************************************************
1764 * *
1765 * Function: evaluate_CHANGE *
1766 * *
1767 * Purpose: evaluate function 'change' for the item *
1768 * *
1769 * Parameters: item - item (performance metric) *
1770 * parameter - number of seconds *
1771 * *
1772 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1773 * FAIL - failed to evaluate function *
1774 * *
1775 ******************************************************************************/
evaluate_CHANGE(zbx_variant_t * value,DC_ITEM * item,const zbx_timespec_t * ts,char ** error)1776 static int evaluate_CHANGE(zbx_variant_t *value, DC_ITEM *item, const zbx_timespec_t *ts, char **error)
1777 {
1778 int ret = FAIL;
1779 zbx_vector_history_record_t values;
1780 double result;
1781
1782 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1783
1784 zbx_history_record_vector_create(&values);
1785
1786 if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, 2, ts) ||
1787 2 > values.values_num)
1788 {
1789 *error = zbx_strdup(*error, "cannot get values from value cache");
1790 goto out;
1791 }
1792
1793 switch (item->value_type)
1794 {
1795 case ITEM_VALUE_TYPE_FLOAT:
1796 result = values.values[0].value.dbl - values.values[1].value.dbl;
1797 break;
1798 case ITEM_VALUE_TYPE_UINT64:
1799 /* to avoid overflow */
1800 if (values.values[0].value.ui64 >= values.values[1].value.ui64)
1801 result = values.values[0].value.ui64 - values.values[1].value.ui64;
1802 else
1803 result = -(double)(values.values[1].value.ui64 - values.values[0].value.ui64);
1804 break;
1805 case ITEM_VALUE_TYPE_LOG:
1806 if (0 == strcmp(values.values[0].value.log->value, values.values[1].value.log->value))
1807 result = 0;
1808 else
1809 result = 1;
1810 break;
1811
1812 case ITEM_VALUE_TYPE_STR:
1813 case ITEM_VALUE_TYPE_TEXT:
1814 if (0 == strcmp(values.values[0].value.str, values.values[1].value.str))
1815 result = 0;
1816 else
1817 result = 1;
1818 break;
1819 default:
1820 *error = zbx_strdup(*error, "invalid value type");
1821 goto out;
1822 }
1823
1824 zbx_variant_set_dbl(value, result);
1825 ret = SUCCEED;
1826 out:
1827 zbx_history_record_vector_destroy(&values, item->value_type);
1828
1829 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1830
1831 return ret;
1832 }
1833
1834 /******************************************************************************
1835 * *
1836 * Function: evaluate_FUZZYTIME *
1837 * *
1838 * Purpose: evaluate function 'fuzzytime' for the item *
1839 * *
1840 * Parameters: item - item (performance metric) *
1841 * parameter - number of seconds *
1842 * *
1843 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1844 * FAIL - failed to evaluate function *
1845 * *
1846 ******************************************************************************/
evaluate_FUZZYTIME(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1847 static int evaluate_FUZZYTIME(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1848 char **error)
1849 {
1850 int arg1, ret = FAIL;
1851 zbx_value_type_t arg1_type;
1852 zbx_history_record_t vc_value;
1853 zbx_uint64_t fuzlow, fuzhig;
1854
1855 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1856
1857 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1858 {
1859 *error = zbx_strdup(*error, "invalid value type");
1860 goto out;
1861 }
1862
1863 if (1 < num_param(parameters))
1864 {
1865 *error = zbx_strdup(*error, "invalid number of parameters");
1866 goto out;
1867 }
1868
1869 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
1870 {
1871 *error = zbx_strdup(*error, "invalid second parameter");
1872 goto out;
1873 }
1874
1875 if (ZBX_VALUE_SECONDS != arg1_type || ts->sec <= arg1)
1876 {
1877 *error = zbx_strdup(*error, "invalid argument type or value");
1878 goto out;
1879 }
1880
1881 if (SUCCEED != zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value))
1882 {
1883 *error = zbx_strdup(*error, "cannot get value from value cache");
1884 goto out;
1885 }
1886
1887 fuzlow = (int)(ts->sec - arg1);
1888 fuzhig = (int)(ts->sec + arg1);
1889
1890 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1891 {
1892 if (vc_value.value.ui64 >= fuzlow && vc_value.value.ui64 <= fuzhig)
1893 zbx_variant_set_dbl(value, 1);
1894 else
1895 zbx_variant_set_dbl(value, 0);
1896 }
1897 else
1898 {
1899 if (vc_value.value.dbl >= fuzlow && vc_value.value.dbl <= fuzhig)
1900 zbx_variant_set_dbl(value, 1);
1901 else
1902 zbx_variant_set_dbl(value, 0);
1903 }
1904
1905 zbx_history_record_clear(&vc_value, item->value_type);
1906
1907 ret = SUCCEED;
1908 out:
1909 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1910
1911 return ret;
1912 }
1913
1914 /******************************************************************************
1915 * *
1916 * Function: evaluate_BITAND *
1917 * *
1918 * Purpose: evaluate logical bitwise function 'and' for the item *
1919 * *
1920 * Parameters: value - dynamic buffer *
1921 * item - item (performance metric) *
1922 * parameters - to 2 comma-separated fields: *
1923 * (1) same as the 1st parameter for function *
1924 * evaluate_LAST() (see documentation of *
1925 * trigger function last()), *
1926 * (2) mask to bitwise AND with (mandatory), *
1927 * *
1928 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1929 * FAIL - failed to evaluate function *
1930 * *
1931 ******************************************************************************/
evaluate_BITAND(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1932 static int evaluate_BITAND(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1933 char **error)
1934 {
1935 char *last_parameters = NULL;
1936 int ret = FAIL;
1937 zbx_uint64_t mask;
1938
1939 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1940
1941 if (ITEM_VALUE_TYPE_UINT64 != item->value_type)
1942 {
1943 *error = zbx_strdup(*error, "invalid value type");
1944 goto clean;
1945 }
1946
1947 if (2 < num_param(parameters))
1948 {
1949 *error = zbx_strdup(*error, "invalid number of parameters");
1950 goto clean;
1951 }
1952
1953 if (SUCCEED != get_function_parameter_uint64(parameters, 2, &mask))
1954 {
1955 *error = zbx_strdup(*error, "invalid third parameter");
1956 goto clean;
1957 }
1958
1959 /* prepare the 1st and the 3rd parameter for passing to evaluate_LAST() */
1960 last_parameters = zbx_function_get_param_dyn(parameters, 1);
1961
1962 if (SUCCEED == evaluate_LAST(value, item, last_parameters, ts, error))
1963 {
1964 /* the evaluate_LAST() should return uint64 value, but just to be sure try to convert it */
1965 if (SUCCEED != zbx_variant_convert(value, ZBX_VARIANT_UI64))
1966 {
1967 *error = zbx_strdup(*error, "invalid value type");
1968 goto clean;
1969 }
1970 zbx_variant_set_dbl(value, value->data.ui64 & (zbx_uint64_t)mask);
1971 ret = SUCCEED;
1972 }
1973
1974 zbx_free(last_parameters);
1975 clean:
1976 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1977
1978 return ret;
1979 }
1980
1981 /******************************************************************************
1982 * *
1983 * Function: evaluate_FORECAST *
1984 * *
1985 * Purpose: evaluate function 'forecast' for the item *
1986 * *
1987 * Parameters: item - item (performance metric) *
1988 * parameters - number of seconds/values and time shift (optional)*
1989 * *
1990 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1991 * FAIL - failed to evaluate function *
1992 * *
1993 ******************************************************************************/
evaluate_FORECAST(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1994 static int evaluate_FORECAST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1995 char **error)
1996 {
1997 char *fit_str = NULL, *mode_str = NULL;
1998 double *t = NULL, *x = NULL;
1999 int nparams, time, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
2000 zbx_value_type_t time_type, arg1_type;
2001 unsigned int k = 0;
2002 zbx_vector_history_record_t values;
2003 zbx_timespec_t zero_time;
2004 zbx_fit_t fit;
2005 zbx_mode_t mode;
2006 zbx_timespec_t ts_end = *ts;
2007
2008 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2009
2010 zbx_history_record_vector_create(&values);
2011
2012 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2013 {
2014 *error = zbx_strdup(*error, "invalid value type");
2015 goto out;
2016 }
2017
2018 if (2 > (nparams = num_param(parameters)) || nparams > 4)
2019 {
2020 *error = zbx_strdup(*error, "invalid number of parameters");
2021 goto out;
2022 }
2023
2024 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
2025 ZBX_VALUE_NONE == arg1_type)
2026 {
2027 *error = zbx_strdup(*error, "invalid second parameter");
2028 goto out;
2029 }
2030
2031 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_MANDATORY, &time, &time_type) ||
2032 ZBX_VALUE_SECONDS != time_type)
2033 {
2034 *error = zbx_strdup(*error, "invalid third parameter");
2035 goto out;
2036 }
2037
2038 if (3 <= nparams)
2039 {
2040 if (SUCCEED != get_function_parameter_str(parameters, 3, &fit_str) ||
2041 SUCCEED != zbx_fit_code(fit_str, &fit, &k, error))
2042 {
2043 *error = zbx_strdup(*error, "invalid fourth parameter");
2044 goto out;
2045 }
2046 }
2047 else
2048 {
2049 fit = FIT_LINEAR;
2050 }
2051
2052 if (4 == nparams)
2053 {
2054 if (SUCCEED != get_function_parameter_str(parameters, 4, &mode_str) ||
2055 SUCCEED != zbx_mode_code(mode_str, &mode, error))
2056 {
2057 *error = zbx_strdup(*error, "invalid fifth parameter");
2058 goto out;
2059 }
2060 }
2061 else
2062 {
2063 mode = MODE_VALUE;
2064 }
2065
2066 switch (arg1_type)
2067 {
2068 case ZBX_VALUE_SECONDS:
2069 seconds = arg1;
2070 break;
2071 case ZBX_VALUE_NVALUES:
2072 nvalues = arg1;
2073 break;
2074 default:
2075 THIS_SHOULD_NEVER_HAPPEN;
2076 }
2077
2078 ts_end.sec -= time_shift;
2079
2080 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
2081 {
2082 *error = zbx_strdup(*error, "cannot get values from value cache");
2083 goto out;
2084 }
2085
2086 if (0 < values.values_num)
2087 {
2088 t = (double *)zbx_malloc(t, values.values_num * sizeof(double));
2089 x = (double *)zbx_malloc(x, values.values_num * sizeof(double));
2090
2091 zero_time.sec = values.values[values.values_num - 1].timestamp.sec;
2092 zero_time.ns = values.values[values.values_num - 1].timestamp.ns;
2093
2094 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
2095 {
2096 for (i = 0; i < values.values_num; i++)
2097 {
2098 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2099 (values.values[i].timestamp.ns - zero_time.ns + 1);
2100 x[i] = values.values[i].value.dbl;
2101 }
2102 }
2103 else
2104 {
2105 for (i = 0; i < values.values_num; i++)
2106 {
2107 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2108 (values.values[i].timestamp.ns - zero_time.ns + 1);
2109 x[i] = values.values[i].value.ui64;
2110 }
2111 }
2112
2113 zbx_variant_set_dbl(value, zbx_forecast(t, x, values.values_num,
2114 ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), time, fit, k, mode));
2115 }
2116 else
2117 {
2118 zbx_variant_set_dbl(value, ZBX_MATH_ERROR);
2119 }
2120
2121 ret = SUCCEED;
2122 out:
2123 zbx_history_record_vector_destroy(&values, item->value_type);
2124
2125 zbx_free(fit_str);
2126 zbx_free(mode_str);
2127
2128 zbx_free(t);
2129 zbx_free(x);
2130
2131 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2132
2133 return ret;
2134 }
2135
2136 /******************************************************************************
2137 * *
2138 * Function: evaluate_TIMELEFT *
2139 * *
2140 * Purpose: evaluate function 'timeleft' for the item *
2141 * *
2142 * Parameters: item - item (performance metric) *
2143 * parameters - number of seconds/values and time shift (optional)*
2144 * *
2145 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2146 * FAIL - failed to evaluate function *
2147 * *
2148 ******************************************************************************/
evaluate_TIMELEFT(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2149 static int evaluate_TIMELEFT(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2150 char **error)
2151 {
2152 char *fit_str = NULL;
2153 double *t = NULL, *x = NULL, threshold;
2154 int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
2155 zbx_value_type_t arg1_type;
2156 unsigned k = 0;
2157 zbx_vector_history_record_t values;
2158 zbx_timespec_t zero_time;
2159 zbx_fit_t fit;
2160 zbx_timespec_t ts_end = *ts;
2161
2162 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2163
2164 zbx_history_record_vector_create(&values);
2165
2166 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2167 {
2168 *error = zbx_strdup(*error, "invalid value type");
2169 goto out;
2170 }
2171
2172 if (2 > (nparams = num_param(parameters)) || nparams > 3)
2173 {
2174 *error = zbx_strdup(*error, "invalid number of parameters");
2175 goto out;
2176 }
2177
2178 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
2179 ZBX_VALUE_NONE == arg1_type)
2180 {
2181 *error = zbx_strdup(*error, "invalid second parameter");
2182 goto out;
2183 }
2184
2185 if (SUCCEED != get_function_parameter_float(parameters, 2, ZBX_FLAG_DOUBLE_SUFFIX, &threshold))
2186 {
2187 *error = zbx_strdup(*error, "invalid third parameter");
2188 goto out;
2189 }
2190
2191 if (3 == nparams)
2192 {
2193 if (SUCCEED != get_function_parameter_str(parameters, 3, &fit_str) ||
2194 SUCCEED != zbx_fit_code(fit_str, &fit, &k, error))
2195 {
2196 *error = zbx_strdup(*error, "invalid fourth parameter");
2197 goto out;
2198 }
2199 }
2200 else
2201 {
2202 fit = FIT_LINEAR;
2203 }
2204
2205 if ((FIT_EXPONENTIAL == fit || FIT_POWER == fit) && 0.0 >= threshold)
2206 {
2207 *error = zbx_strdup(*error, "exponential and power functions are always positive");
2208 goto out;
2209 }
2210
2211 switch (arg1_type)
2212 {
2213 case ZBX_VALUE_SECONDS:
2214 seconds = arg1;
2215 break;
2216 case ZBX_VALUE_NVALUES:
2217 nvalues = arg1;
2218 break;
2219 default:
2220 THIS_SHOULD_NEVER_HAPPEN;
2221 }
2222
2223 ts_end.sec -= time_shift;
2224
2225 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
2226 {
2227 *error = zbx_strdup(*error, "cannot get values from value cache");
2228 goto out;
2229 }
2230
2231 if (0 < values.values_num)
2232 {
2233 t = (double *)zbx_malloc(t, values.values_num * sizeof(double));
2234 x = (double *)zbx_malloc(x, values.values_num * sizeof(double));
2235
2236 zero_time.sec = values.values[values.values_num - 1].timestamp.sec;
2237 zero_time.ns = values.values[values.values_num - 1].timestamp.ns;
2238
2239 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
2240 {
2241 for (i = 0; i < values.values_num; i++)
2242 {
2243 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2244 (values.values[i].timestamp.ns - zero_time.ns + 1);
2245 x[i] = values.values[i].value.dbl;
2246 }
2247 }
2248 else
2249 {
2250 for (i = 0; i < values.values_num; i++)
2251 {
2252 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2253 (values.values[i].timestamp.ns - zero_time.ns + 1);
2254 x[i] = values.values[i].value.ui64;
2255 }
2256 }
2257
2258 zbx_variant_set_dbl(value, zbx_timeleft(t, x, values.values_num,
2259 ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), threshold, fit, k));
2260 }
2261 else
2262 {
2263 zbx_variant_set_dbl(value, ZBX_MATH_ERROR);
2264 }
2265
2266 ret = SUCCEED;
2267 out:
2268 zbx_history_record_vector_destroy(&values, item->value_type);
2269
2270 zbx_free(fit_str);
2271
2272 zbx_free(t);
2273 zbx_free(x);
2274
2275 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2276
2277 return ret;
2278 }
2279
2280 /******************************************************************************
2281 * *
2282 * Function: evaluate_TREND *
2283 * *
2284 * Purpose: evaluate trend* functions for the item *
2285 * *
2286 * Parameters: value - [OUT] the function result *
2287 * item - [IN] item (performance metric) *
2288 * func - [IN] the trend function to evaluate *
2289 * (avg, sum, count, delta, max, min) *
2290 * parameters - [IN] function parameters *
2291 * ts - [IN] the historical time when function must be *
2292 * evaluated *
2293 * *
2294 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2295 * FAIL - failed to evaluate function *
2296 * *
2297 ******************************************************************************/
evaluate_TREND(zbx_variant_t * value,DC_ITEM * item,const char * func,const char * parameters,const zbx_timespec_t * ts,char ** error)2298 static int evaluate_TREND(zbx_variant_t *value, DC_ITEM *item, const char *func, const char *parameters,
2299 const zbx_timespec_t *ts, char **error)
2300 {
2301 int ret = FAIL, start, end;
2302 char *period = NULL;
2303 const char *table;
2304 double value_dbl;
2305
2306 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2307
2308 if (1 != num_param(parameters))
2309 {
2310 *error = zbx_strdup(*error, "invalid number of parameters");
2311 goto out;
2312 }
2313
2314 if (SUCCEED != get_function_parameter_str(parameters, 1, &period))
2315 {
2316 *error = zbx_strdup(*error, "invalid second parameter");
2317 goto out;
2318 }
2319
2320 if (SUCCEED != zbx_trends_parse_range(ts->sec, period, &start, &end, error))
2321 goto out;
2322
2323 switch (item->value_type)
2324 {
2325 case ITEM_VALUE_TYPE_FLOAT:
2326 table = "trends";
2327 break;
2328 case ITEM_VALUE_TYPE_UINT64:
2329 table = "trends_uint";
2330 break;
2331 default:
2332 *error = zbx_strdup(*error, "unsupported value type");
2333 goto out;
2334 }
2335
2336 if (0 == strcmp(func, "avg"))
2337 {
2338 ret = zbx_trends_eval_avg(table, item->itemid, start, end, &value_dbl, error);
2339 }
2340 else if (0 == strcmp(func, "count"))
2341 {
2342 ret = zbx_trends_eval_count(table, item->itemid, start, end, &value_dbl, error);
2343 }
2344 else if (0 == strcmp(func, "max"))
2345 {
2346 ret = zbx_trends_eval_max(table, item->itemid, start, end, &value_dbl, error);
2347 }
2348 else if (0 == strcmp(func, "min"))
2349 {
2350 ret = zbx_trends_eval_min(table, item->itemid, start, end, &value_dbl, error);
2351 }
2352 else if (0 == strcmp(func, "sum"))
2353 {
2354 ret = zbx_trends_eval_sum(table, item->itemid, start, end, &value_dbl, error);
2355 }
2356 else
2357 {
2358 *error = zbx_strdup(*error, "unknown trend function");
2359 goto out;
2360 }
2361
2362 if (SUCCEED == ret)
2363 zbx_variant_set_dbl(value, value_dbl);
2364 out:
2365 zbx_free(period);
2366
2367 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2368
2369 return ret;
2370 }
2371
validate_params_and_get_data(DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,zbx_vector_history_record_t * values,char ** error)2372 static int validate_params_and_get_data(DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2373 zbx_vector_history_record_t *values, char **error)
2374 {
2375 int arg1, seconds = 0, nvalues = 0, time_shift;
2376 zbx_value_type_t arg1_type;
2377 zbx_timespec_t ts_end = *ts;
2378
2379 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2380 {
2381 *error = zbx_strdup(*error, "invalid value type");
2382 return FAIL;
2383 }
2384
2385 if (1 != num_param(parameters))
2386 {
2387 *error = zbx_strdup(*error, "invalid number of parameters");
2388 return FAIL;
2389 }
2390
2391 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
2392 ZBX_VALUE_NONE == arg1_type)
2393 {
2394 *error = zbx_strdup(*error, "invalid parameter");
2395 return FAIL;
2396 }
2397
2398 ts_end.sec -= time_shift;
2399
2400 switch (arg1_type)
2401 {
2402 case ZBX_VALUE_SECONDS:
2403 seconds = arg1;
2404 break;
2405 case ZBX_VALUE_NVALUES:
2406 nvalues = arg1;
2407 break;
2408 default:
2409 *error = zbx_strdup(*error, "invalid type of first argument");
2410 THIS_SHOULD_NEVER_HAPPEN;
2411 return FAIL;
2412 }
2413
2414 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, values, seconds, nvalues, &ts_end))
2415 {
2416 *error = zbx_strdup(*error, "cannot get values from value cache");
2417 return FAIL;
2418 }
2419
2420 return SUCCEED;
2421 }
2422
2423 /******************************************************************************
2424 * *
2425 * Function: evaluate_FIRST *
2426 * *
2427 * Purpose: evaluate function 'first' for the item *
2428 * *
2429 * Parameters: value - dynamic buffer *
2430 * item - item (performance metric) *
2431 * parameters - Nth first value and time shift (optional) *
2432 * *
2433 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2434 * FAIL - failed to evaluate function *
2435 * *
2436 ******************************************************************************/
evaluate_FIRST(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2437 static int evaluate_FIRST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2438 char **error)
2439 {
2440 int arg1 = 1, ret = FAIL, seconds = 0, time_shift;
2441 zbx_value_type_t arg1_type = ZBX_VALUE_NVALUES;
2442 zbx_vector_history_record_t values;
2443 zbx_timespec_t ts_end = *ts;
2444
2445 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2446
2447 zbx_history_record_vector_create(&values);
2448
2449 if (1 != num_param(parameters))
2450 {
2451 *error = zbx_strdup(*error, "invalid number of parameters");
2452 goto out;
2453 }
2454
2455 if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift))
2456 {
2457 *error = zbx_strdup(*error, "invalid parameter");
2458 goto out;
2459 }
2460
2461 switch (arg1_type)
2462 {
2463 case ZBX_VALUE_SECONDS:
2464 seconds = arg1;
2465 break;
2466 case ZBX_VALUE_NONE:
2467 *error = zbx_strdup(*error, "the first argument is not specified");
2468 goto out;
2469 case ZBX_VALUE_NVALUES:
2470 *error = zbx_strdup(*error, "the first argument cannot be number of value");
2471 goto out;
2472 default:
2473 *error = zbx_strdup(*error, "invalid type of first argument");
2474 THIS_SHOULD_NEVER_HAPPEN;
2475 goto out;
2476 }
2477
2478 if (0 >= arg1)
2479 {
2480 *error = zbx_strdup(*error, "the first argument must be greater than 0");
2481 goto out;
2482 }
2483
2484 ts_end.sec -= time_shift;
2485
2486 if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, 0, &ts_end))
2487 {
2488 if (0 < values.values_num)
2489 {
2490 zbx_history_value2variant(&values.values[values.values_num - 1].value, item->value_type, value);
2491 ret = SUCCEED;
2492 }
2493 else
2494 {
2495 *error = zbx_strdup(*error, "not enough data");
2496 goto out;
2497 }
2498 }
2499 else
2500 *error = zbx_strdup(*error, "cannot get values from value cache");
2501 out:
2502 zbx_history_record_vector_destroy(&values, item->value_type);
2503
2504 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2505
2506 return ret;
2507 }
2508
history_to_dbl_vector(const zbx_history_record_t * v,int n,unsigned char value_type,zbx_vector_dbl_t * values)2509 static void history_to_dbl_vector(const zbx_history_record_t *v, int n, unsigned char value_type,
2510 zbx_vector_dbl_t *values)
2511 {
2512 int i;
2513
2514 zbx_vector_dbl_reserve(values, (size_t)n);
2515
2516 if (ITEM_VALUE_TYPE_FLOAT == value_type)
2517 {
2518 for (i = 0; i < n; i++)
2519 zbx_vector_dbl_append(values, v[i].value.dbl);
2520 }
2521 else
2522 {
2523 for (i = 0; i < n; i++)
2524 zbx_vector_dbl_append(values, (double)v[i].value.ui64);
2525 }
2526 }
2527
2528 /******************************************************************************
2529 * *
2530 * Function: evaluate_statistical_func *
2531 * *
2532 * Purpose: common operations for aggregate function calculation *
2533 * *
2534 * Parameters: value - [OUT] result *
2535 * item - [IN] item (performance metric) *
2536 * parameters - [IN] number of seconds/values and time shift *
2537 * (optional) *
2538 * ts - [IN] time shift *
2539 * stat_func - [IN] pointer to aggregate function to be called *
2540 * min_values - [IN] minimum data values required *
2541 * error - [OUT] the error message in the case of failure *
2542 * *
2543 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2544 * FAIL - failed to evaluate function *
2545 * *
2546 ******************************************************************************/
evaluate_statistical_func(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,zbx_statistical_func_t stat_func,int min_values,char ** error)2547 static int evaluate_statistical_func(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
2548 const zbx_timespec_t *ts, zbx_statistical_func_t stat_func, int min_values, char **error)
2549 {
2550 int ret = FAIL;
2551 zbx_vector_history_record_t values;
2552
2553 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2554
2555 zbx_history_record_vector_create(&values);
2556
2557 if (SUCCEED != validate_params_and_get_data(item, parameters, ts, &values, error))
2558 goto out;
2559
2560 if (min_values <= values.values_num)
2561 {
2562 zbx_vector_dbl_t values_dbl;
2563 double result;
2564
2565 zbx_vector_dbl_create(&values_dbl);
2566
2567 history_to_dbl_vector(values.values, values.values_num, item->value_type, &values_dbl);
2568
2569 if (SUCCEED == (ret = stat_func(&values_dbl, &result, error)))
2570 zbx_variant_set_dbl(value, result);
2571
2572 zbx_vector_dbl_destroy(&values_dbl);
2573 }
2574 else
2575 *error = zbx_strdup(*error, "not enough data");
2576 out:
2577 zbx_history_record_vector_destroy(&values, item->value_type);
2578
2579 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2580
2581 return ret;
2582 }
2583
2584 /******************************************************************************
2585 * *
2586 * Function: evaluate_function *
2587 * *
2588 * Purpose: evaluate function *
2589 * *
2590 * Parameters: item - item to calculate function for *
2591 * function - function (for example, 'max') *
2592 * parameter - parameter of the function *
2593 * *
2594 * Return value: SUCCEED - evaluated successfully, value contains its value *
2595 * FAIL - evaluation failed *
2596 * *
2597 ******************************************************************************/
evaluate_function2(zbx_variant_t * value,DC_ITEM * item,const char * function,const char * parameter,const zbx_timespec_t * ts,char ** error)2598 int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function, const char *parameter,
2599 const zbx_timespec_t *ts, char **error)
2600 {
2601 int ret;
2602
2603 zabbix_log(LOG_LEVEL_DEBUG, "In %s() function:'%s(/%s/%s,%s)' ts:'%s\'", __func__,
2604 function, item->host.host, item->key_orig, parameter, zbx_timespec_str(ts));
2605
2606 if (0 == strcmp(function, "last"))
2607 {
2608 ret = evaluate_LAST(value, item, parameter, ts, error);
2609 }
2610 else if (0 == strcmp(function, "min"))
2611 {
2612 ret = evaluate_MIN(value, item, parameter, ts, error);
2613 }
2614 else if (0 == strcmp(function, "max"))
2615 {
2616 ret = evaluate_MAX(value, item, parameter, ts, error);
2617 }
2618 else if (0 == strcmp(function, "avg"))
2619 {
2620 ret = evaluate_AVG(value, item, parameter, ts, error);
2621 }
2622 else if (0 == strcmp(function, "sum"))
2623 {
2624 ret = evaluate_SUM(value, item, parameter, ts, error);
2625 }
2626 else if (0 == strcmp(function, "percentile"))
2627 {
2628 ret = evaluate_PERCENTILE(value, item, parameter, ts, error);
2629 }
2630 else if (0 == strcmp(function, "count"))
2631 {
2632 ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, COUNT_ALL, error);
2633 }
2634 else if (0 == strcmp(function, "countunique"))
2635 {
2636 ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, COUNT_UNIQUE, error);
2637 }
2638 else if (0 == strcmp(function, "nodata"))
2639 {
2640 ret = evaluate_NODATA(value, item, parameter, error);
2641 }
2642 else if (0 == strcmp(function, "change"))
2643 {
2644 ret = evaluate_CHANGE(value, item, ts, error);
2645 }
2646 else if (0 == strcmp(function, "find"))
2647 {
2648 ret = evaluate_COUNT(value, item, parameter, ts, 1, COUNT_ALL, error);
2649 }
2650 else if (0 == strcmp(function, "fuzzytime"))
2651 {
2652 ret = evaluate_FUZZYTIME(value, item, parameter, ts, error);
2653 }
2654 else if (0 == strcmp(function, "logeventid"))
2655 {
2656 ret = evaluate_LOGEVENTID(value, item, parameter, ts, error);
2657 }
2658 else if (0 == strcmp(function, "logseverity"))
2659 {
2660 ret = evaluate_LOGSEVERITY(value, item, parameter, ts, error);
2661 }
2662 else if (0 == strcmp(function, "logsource"))
2663 {
2664 ret = evaluate_LOGSOURCE(value, item, parameter, ts, error);
2665 }
2666 else if (0 == strcmp(function, "bitand"))
2667 {
2668 ret = evaluate_BITAND(value, item, parameter, ts, error);
2669 }
2670 else if (0 == strcmp(function, "forecast"))
2671 {
2672 ret = evaluate_FORECAST(value, item, parameter, ts, error);
2673 }
2674 else if (0 == strcmp(function, "timeleft"))
2675 {
2676 ret = evaluate_TIMELEFT(value, item, parameter, ts, error);
2677 }
2678 else if (0 == strncmp(function, "trend", 5))
2679 {
2680 ret = evaluate_TREND(value, item, function + 5, parameter, ts, error);
2681 }
2682 else if (0 == strcmp(function, "first"))
2683 {
2684 ret = evaluate_FIRST(value, item, parameter, ts, error);
2685 }
2686 else if (0 == strcmp(function, "kurtosis"))
2687 {
2688 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_kurtosis, 1, error);
2689 }
2690 else if (0 == strcmp(function, "mad"))
2691 {
2692 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_mad, 1, error);
2693 }
2694 else if (0 == strcmp(function, "skewness"))
2695 {
2696 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_skewness, 1, error);
2697 }
2698 else if (0 == strcmp(function, "stddevpop"))
2699 {
2700 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_stddevpop, 1, error);
2701 }
2702 else if (0 == strcmp(function, "stddevsamp"))
2703 {
2704 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_stddevsamp, 2, error);
2705 }
2706 else if (0 == strcmp(function, "sumofsquares"))
2707 {
2708 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_sumofsquares, 1, error);
2709 }
2710 else if (0 == strcmp(function, "varpop"))
2711 {
2712 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_varpop, 1, error);
2713 }
2714 else if (0 == strcmp(function, "varsamp"))
2715 {
2716 ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_varsamp, 2, error);
2717 }
2718 else
2719 {
2720 *error = zbx_strdup(*error, "function is not supported");
2721 ret = FAIL;
2722 }
2723
2724 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:'%s' of type:'%s'", __func__, zbx_result_string(ret),
2725 zbx_variant_value_desc(value), zbx_variant_type_desc(value));
2726
2727 return ret;
2728 }
2729
2730 /******************************************************************************
2731 * *
2732 * Function: zbx_is_trigger_function *
2733 * *
2734 * Purpose: check if the specified function is a trigger function *
2735 * *
2736 * Parameters: name - [IN] the function name to check *
2737 * len - [IN] the length of function name *
2738 * *
2739 * Return value: SUCCEED - the function is a trigger function *
2740 * FAIL - otherwise *
2741 * *
2742 ******************************************************************************/
zbx_is_trigger_function(const char * name,size_t len)2743 int zbx_is_trigger_function(const char *name, size_t len)
2744 {
2745 char *functions[] = {"last", "min", "max", "avg", "sum", "percentile", "count", "countunique", "nodata",
2746 "change", "find", "fuzzytime", "logeventid", "logseverity", "logsource", "bitand", "forecast",
2747 "timeleft", "trendavg", "trendcount", "trendmax", "trendmin", "trendsum", "abs", "cbrt",
2748 "ceil", "exp", "floor", "log", "log10", "power", "round", "rand", "signum", "sqrt", "truncate",
2749 "acos", "asin", "atan", "cos", "cosh", "cot", "sin", "sinh", "tan", "degrees", "radians", "mod",
2750 "pi", "e", "expm1", "atan2", "first", "kurtosis", "mad", "skewness", "stddevpop", "stddevsamp",
2751 "sumofsquares", "varpop", "varsamp", "ascii", "bitlength", "char", "concat", "insert", "lcase",
2752 "left", "ltrim", "bytelength", "repeat", "replace", "right", "rtrim", "mid", "trim", "between",
2753 "in", "bitor", "bitxor", "bitnot", "bitlshift", "bitrshift", NULL};
2754 char **ptr;
2755
2756 for (ptr = functions; NULL != *ptr; ptr++)
2757 {
2758 size_t compare_len;
2759
2760 compare_len = strlen(*ptr);
2761 if (compare_len == len && 0 == memcmp(*ptr, name, len))
2762 return SUCCEED;
2763 }
2764
2765 return FAIL;
2766 }
2767