diff options
author | Andris Zeila <andris.zeila@zabbix.com> | 2020-08-28 10:53:42 +0300 |
---|---|---|
committer | Andris Zeila <andris.zeila@zabbix.com> | 2020-08-28 11:11:02 +0300 |
commit | 3b6e07d1ec2ebb46ebe5294da2a71f362c6a5c1c (patch) | |
tree | 7f1b166d21c6a822b4b5c7e0deb6c15c37ee6636 | |
parent | 7fcb4908ac42281568e4e85f3adefe4a9b6ecd5e (diff) |
.......PS. [ZBXNEXT-6167] added diaginfo runtime command to log internal diagnostic information
* commit 'b9d85eedee7431f9204ac3a00eea559b81486ae7': (45 commits)
.D........ [ZBXNEXT-6167] updated server and proxy man pages
.D........ [ZBXNEXT-6167] added changelog entry
.......PS. [ZBXNEXT-6167] don't allow runtime command on Zabbix agentd
.......PS. [ZBXNEXT-6167] style fix
.......PS. [ZBXNEXT-6167] style fix
.......PS. [ZBXNEXT-6167] simplified main process waiting for dead children
.......PS. [ZBXNEXT-6167] added missing include file, more defines
.......PS. [ZBXNEXT-6167] added diaginfo remote command suppor to proxy
.......PS. [ZBXNEXT-6167] added comments, minor refactoring
........S. [ZBXNEXT-6167] added remote command support for diaginfo printing on server
.......PS. [ZBXNEXT-6167] small style fixes
........S. [ZBXNEXT-6167] fixed value cache diagnostics retrieval with disabled value cache
.......PS. [ZBXNEXT-6167] fixed vector not being destroyed on failure
.......PS. [ZBXNEXT-6167] fixed vector not being destroyed on failure
.......PS. [ZBXNEXT-6167] fixed warning
.......PS. [ZBXNEXT-6167] fixed memory leak
........S. [ZBXNEXT-6167] fixed memory leak
........S. [ZBXNEXT-6167] fixed wrong type used when serializing lld top result
........S. [ZBXNEXT-6167] small style fix
........S. [ZBXNEXT-6167] small style fixes
...
(cherry picked from commit dabac74c51a9d19db24c871f7f8ec247ac540eeb)
45 files changed, 3438 insertions, 153 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-6167 b/ChangeLog.d/feature/ZBXNEXT-6167 new file mode 100644 index 00000000000..4fb710a2d38 --- /dev/null +++ b/ChangeLog.d/feature/ZBXNEXT-6167 @@ -0,0 +1 @@ +.......PS. [ZBXNEXT-6167] added diaginfo runtime command to log internal diagnostic information (wiper) diff --git a/configure.ac b/configure.ac index afc1885c693..2d35fcd3e6d 100644 --- a/configure.ac +++ b/configure.ac @@ -1997,6 +1997,7 @@ AC_OUTPUT([ src/libs/zbxcompress/Makefile src/libs/zbxembed/Makefile src/libs/zbxprometheus/Makefile + src/libs/zbxdiag/Makefile src/zabbix_agent/Makefile src/zabbix_agent/logfiles/Makefile src/zabbix_get/Makefile diff --git a/include/common.h b/include/common.h index ae86cfb27b2..aa447981927 100644 --- a/include/common.h +++ b/include/common.h @@ -439,6 +439,7 @@ zbx_graph_yaxis_types_t; #define ZBX_LOG_LEVEL_INCREASE "log_level_increase" #define ZBX_LOG_LEVEL_DECREASE "log_level_decrease" #define ZBX_SNMP_CACHE_RELOAD "snmp_cache_reload" +#define ZBX_DIAGINFO "diaginfo" /* value for not supported items */ #define ZBX_NOTSUPPORTED "ZBX_NOTSUPPORTED" @@ -930,6 +931,7 @@ zbx_task_t; #define ZBX_RTC_HOUSEKEEPER_EXECUTE 3 #define ZBX_RTC_CONFIG_CACHE_RELOAD 8 #define ZBX_RTC_SNMP_CACHE_RELOAD 9 +#define ZBX_RTC_DIAGINFO 10 typedef enum { diff --git a/include/dbcache.h b/include/dbcache.h index 88c993b1abe..c26038661f1 100644 --- a/include/dbcache.h +++ b/include/dbcache.h @@ -25,6 +25,7 @@ #include "sysinfo.h" #include "zbxalgo.h" #include "zbxjson.h" +#include "memalloc.h" #define ZBX_SYNC_DONE 0 #define ZBX_SYNC_MORE 1 @@ -849,6 +850,7 @@ typedef struct { zbx_uint64_t itemid; unsigned char status; + int values_num; zbx_hc_data_t *tail; zbx_hc_data_t *head; @@ -985,4 +987,9 @@ const char *zbx_dc_get_instanceid(void); char *zbx_dc_expand_user_macros(const char *text, zbx_uint64_t hostid); char *zbx_dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid); +/* diagnostic data */ +void zbx_hc_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num); +void zbx_hc_get_mem_stats(zbx_mem_stats_t *data, zbx_mem_stats_t *index); +void zbx_hc_get_items(zbx_vector_uint64_pair_t *top); + #endif diff --git a/include/memalloc.h b/include/memalloc.h index c0f11e6238c..8f67d850977 100644 --- a/include/memalloc.h +++ b/include/memalloc.h @@ -23,6 +23,12 @@ #include "common.h" #include "mutexs.h" +#define MEM_MIN_ALLOC 24 /* should be a multiple of 8 and at least (2 * ZBX_PTR_SIZE) */ + +#define MEM_MIN_BUCKET_SIZE MEM_MIN_ALLOC +#define MEM_MAX_BUCKET_SIZE 256 /* starting from this size all free chunks are put into the same bucket */ +#define MEM_BUCKET_COUNT ((MEM_MAX_BUCKET_SIZE - MEM_MIN_BUCKET_SIZE) / 8 + 1) + typedef struct { void **buckets; @@ -44,6 +50,18 @@ typedef struct } zbx_mem_info_t; +typedef struct +{ + zbx_uint64_t free_size; + zbx_uint64_t used_size; + zbx_uint64_t min_chunk_size; + zbx_uint64_t max_chunk_size; + unsigned int chunks_num[MEM_BUCKET_COUNT]; + unsigned int free_chunks; + unsigned int used_chunks; +} +zbx_mem_stats_t; + int zbx_mem_create(zbx_mem_info_t **info, zbx_uint64_t size, const char *descr, const char *param, int allow_oom, char **error); @@ -64,6 +82,7 @@ void __zbx_mem_free(const char *file, int line, zbx_mem_info_t *info, void *ptr) void zbx_mem_clear(zbx_mem_info_t *info); +void zbx_mem_get_stats(const zbx_mem_info_t *info, zbx_mem_stats_t *stats); void zbx_mem_dump_stats(int level, zbx_mem_info_t *info); size_t zbx_mem_required_size(int chunks_num, const char *descr, const char *param); diff --git a/include/preproc.h b/include/preproc.h index 9a83845a811..36afc5cf6ba 100644 --- a/include/preproc.h +++ b/include/preproc.h @@ -33,6 +33,14 @@ typedef struct } zbx_preproc_result_t; +typedef struct +{ + zbx_uint64_t itemid; + int values_num; + int steps_num; +} +zbx_preproc_item_stats_t; + /* the following functions are implemented differently for server and proxy */ void zbx_preprocess_item_value(zbx_uint64_t itemid, unsigned char item_value_type, unsigned char item_flags, @@ -47,4 +55,8 @@ int zbx_preprocessor_test(unsigned char value_type, const char *value, const zbx const zbx_vector_ptr_t *steps, zbx_vector_ptr_t *results, zbx_vector_ptr_t *history, char **preproc_error, char **error); +int zbx_preprocessor_get_diag_stats(int *values_num, int *values_preproc_num, char **error); + + +int zbx_preprocessor_get_top_items(int limit, zbx_vector_ptr_t *items, char **error); #endif /* ZABBIX_PREPROC_H */ diff --git a/include/zbxalert.h b/include/zbxalert.h new file mode 100644 index 00000000000..67cfaa2ecc9 --- /dev/null +++ b/include/zbxalert.h @@ -0,0 +1,40 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#ifndef ZABBIX_ZBXALERT_H +#define ZABBIX_ZBXALERT_H + +#include "common.h" + +typedef struct +{ + int source; + int object; + zbx_uint64_t objectid; + int alerts_num; +} +zbx_am_source_stats_t; + +int zbx_alerter_get_diag_stats(zbx_uint64_t *alerts_num, char **error); + +int zbx_alerter_get_top_mediatypes(int limit, zbx_vector_uint64_pair_t *mediatypes, char **error); + +int zbx_alerter_get_top_sources(int limit, zbx_vector_ptr_t *sources, char **error); + +#endif diff --git a/include/zbxdiag.h b/include/zbxdiag.h new file mode 100644 index 00000000000..3a77db8a626 --- /dev/null +++ b/include/zbxdiag.h @@ -0,0 +1,48 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +#ifndef ZABBIX_ZBXDIAG_H +#define ZABBIX_ZBXDIAG_H + +#include "common.h" +#include "zbxjson.h" + +typedef enum +{ + ZBX_DIAGINFO_UNDEFINED = -1, + ZBX_DIAGINFO_ALL, + ZBX_DIAGINFO_HISTORYCACHE, + ZBX_DIAGINFO_VALUECACHE, + ZBX_DIAGINFO_PREPROCESSING, + ZBX_DIAGINFO_LLD, + ZBX_DIAGINFO_ALERTING +} +zbx_diaginfo_section_t; + +#define ZBX_DIAG_HISTORYCACHE "historycache" +#define ZBX_DIAG_VALUECACHE "valuecache" +#define ZBX_DIAG_PREPROCESSING "preprocessing" +#define ZBX_DIAG_LLD "lld" +#define ZBX_DIAG_ALERTING "alerting" + +int zbx_diag_get_info(const struct zbx_json_parse *jp, char **info); +void zbx_diag_log_info(unsigned int flags); + +#endif diff --git a/include/zbxjson.h b/include/zbxjson.h index 499ff77bf5e..1edc6c42d1b 100644 --- a/include/zbxjson.h +++ b/include/zbxjson.h @@ -280,6 +280,9 @@ int zbx_json_count(const struct zbx_json_parse *jp); const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_json_type_t *type); const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *string_alloc, zbx_json_type_t *type); void zbx_json_escape(char **string); +int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out); + +void zbx_json_log(const struct zbx_json_parse *jp, int loglevel); /* jsonpath support */ diff --git a/include/zbxlld.h b/include/zbxlld.h index d7016bfd730..639389ea92f 100644 --- a/include/zbxlld.h +++ b/include/zbxlld.h @@ -21,6 +21,7 @@ #define ZABBIX_LLD_H #include "common.h" +#include "zbxalgo.h" void zbx_lld_process_value(zbx_uint64_t itemid, const char *value, const zbx_timespec_t *ts, unsigned char meta, zbx_uint64_t lastlogsize, int mtime, const char *error); @@ -29,4 +30,8 @@ void zbx_lld_process_agent_result(zbx_uint64_t itemid, AGENT_RESULT *result, zbx int zbx_lld_get_queue_size(zbx_uint64_t *size, char **error); +int zbx_lld_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num, char **error); + +int zbx_lld_get_top_items(int limit, zbx_vector_uint64_pair_t *items, char **error); + #endif /* ZABBIX_LLD_H */ diff --git a/include/zbxserver.h b/include/zbxserver.h index ce167b490db..d6de7772675 100644 --- a/include/zbxserver.h +++ b/include/zbxserver.h @@ -54,8 +54,6 @@ #define STR_CONTAINS_MACROS(str) (NULL != strchr(str, '{')) -char *dc_expand_user_macros_in_expression(const char *text, zbx_uint64_t *hostids, int hostids_num); - int get_N_functionid(const char *expression, int N_functionid, zbx_uint64_t *functionid, const char **end); void get_functionids(zbx_vector_uint64_t *functionids, const char *expression); diff --git a/include/zbxtasks.h b/include/zbxtasks.h index d2b409d0752..565d0fd941e 100644 --- a/include/zbxtasks.h +++ b/include/zbxtasks.h @@ -47,6 +47,7 @@ /* task data type */ #define ZBX_TM_DATA_TYPE_TEST_ITEM 0 +#define ZBX_TM_DATA_TYPE_DIAGINFO 1 /* the time period after which finished (done/expired) tasks are removed */ #define ZBX_TM_CLEANUP_TASK_AGE SEC_PER_DAY @@ -149,4 +150,6 @@ void zbx_tm_json_deserialize_tasks(const struct zbx_json_parse *jp, zbx_vector_p /* separate implementation for proxy and server */ void zbx_tm_get_remote_tasks(zbx_vector_ptr_t *tasks, zbx_uint64_t proxy_hostid); +int zbx_tm_get_diaginfo(const struct zbx_json_parse *jp, char **info); + #endif diff --git a/man/zabbix_proxy.man b/man/zabbix_proxy.man index 8d0cbc40ffa..2d86d21277a 100644 --- a/man/zabbix_proxy.man +++ b/man/zabbix_proxy.man @@ -84,13 +84,19 @@ Ignored if housekeeper is being currently executed. .RE .RS 4 .TP 4 +\fBdiaginfo\fR[=\fIsection\fR] +Log internal diagnostic information of the specified section. Section can be \fIhistorycache\fR, \fIpreprocessing\fR. +By default diagnostic information of all sections is logged. +.RE +.RS 4 +.TP 4 \fBlog_level_increase\fR[=\fItarget\fR] -Increase log level, affects all processes if target is not specified +Increase log level, affects all processes if target is not specified. .RE .RS 4 .TP 4 \fBlog_level_decrease\fR[=\fItarget\fR] -Decrease log level, affects all processes if target is not specified +Decrease log level, affects all processes if target is not specified. .RE .RE .SS diff --git a/man/zabbix_server.man b/man/zabbix_server.man index 0acaef21dba..d33f2db2266 100644 --- a/man/zabbix_server.man +++ b/man/zabbix_server.man @@ -83,6 +83,13 @@ Ignored if housekeeper is being currently executed. .RE .RS 4 .TP 4 +\fBdiaginfo\fR[=\fIsection\fR] +Log internal diagnostic information of the specified section. Section can be \fIhistorycache\fR, \fIpreprocessing\fR, +\fIalerting\fR, \fIlld\fR, \fIvaluecache\fR. +By default diagnostic information of all sections is logged. +.RE +.RS 4 +.TP 4 \fBlog_level_increase\fR[=\fItarget\fR] Increase log level, affects all processes if target is not specified .RE diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am index ec981352e5b..a83ac5e16a9 100644 --- a/src/libs/Makefile.am +++ b/src/libs/Makefile.am @@ -30,7 +30,9 @@ DIST_SUBDIRS = \ zbxhistory \ zbxcompress \ zbxembed \ - zbxprometheus + zbxprometheus \ + zbxdiag + if SERVER SERVER_SUBDIRS = \ @@ -49,7 +51,8 @@ SERVER_SUBDIRS = \ zbxhistory \ zbxcompress \ zbxembed \ - zbxprometheus + zbxprometheus \ + zbxdiag else if PROXY PROXY_SUBDIRS = \ @@ -67,7 +70,8 @@ PROXY_SUBDIRS = \ zbxhistory \ zbxcompress \ zbxembed \ - zbxprometheus + zbxprometheus \ + zbxdiag endif endif diff --git a/src/libs/zbxdbcache/dbcache.c b/src/libs/zbxdbcache/dbcache.c index e2162058b1e..1b121e62275 100644 --- a/src/libs/zbxdbcache/dbcache.c +++ b/src/libs/zbxdbcache/dbcache.c @@ -3786,7 +3786,7 @@ static zbx_hc_item_t *hc_get_item(zbx_uint64_t itemid) ******************************************************************************/ static zbx_hc_item_t *hc_add_item(zbx_uint64_t itemid, zbx_hc_data_t *data) { - zbx_hc_item_t item_local = {itemid, ZBX_HC_ITEM_STATUS_NORMAL, data, data}; + zbx_hc_item_t item_local = {itemid, ZBX_HC_ITEM_STATUS_NORMAL, 0, data, data}; return (zbx_hc_item_t *)zbx_hashset_insert(&cache->history_items, &item_local, sizeof(item_local)); } @@ -4050,6 +4050,7 @@ static void hc_add_item_values(dc_item_value_t *values, int values_num) item->head->next = data; item->head = data; } + item->values_num++; } } @@ -4204,6 +4205,7 @@ void hc_push_items(zbx_vector_ptr_t *history_items) hc_queue_item(item); break; case ZBX_HC_ITEM_STATUS_NORMAL: + item->values_num--; data_free = item->tail; item->tail = item->tail->next; hc_free_data(data_free); @@ -4538,3 +4540,66 @@ out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } + +/****************************************************************************** + * * + * Function: zbx_hc_get_diag_stats * + * * + * Purpose: get history cache diagnostics statistics * + * * + ******************************************************************************/ +void zbx_hc_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num) +{ + LOCK_CACHE; + + *values_num = cache->history_num; + *items_num = cache->history_items.num_data; + + UNLOCK_CACHE; +} + +/****************************************************************************** + * * + * Function: zbx_hc_get_mem_stats * + * * + * Purpose: get shared memory allocator statistics * + * * + ******************************************************************************/ +void zbx_hc_get_mem_stats(zbx_mem_stats_t *data, zbx_mem_stats_t *index) +{ + LOCK_CACHE; + + if (NULL != data) + zbx_mem_get_stats(hc_mem, data); + + if (NULL != index) + zbx_mem_get_stats(hc_index_mem, index); + + UNLOCK_CACHE; +} + +/****************************************************************************** + * * + * Function: zbx_hc_get_items * + * * + * Purpose: get statistics of cached items * + * * + ******************************************************************************/ +void zbx_hc_get_items(zbx_vector_uint64_pair_t *items) +{ + zbx_hashset_iter_t iter; + zbx_hc_item_t *item; + + LOCK_CACHE; + + zbx_vector_uint64_pair_reserve(items, cache->history_items.num_data); + + zbx_hashset_iter_reset(&cache->history_items, &iter); + while (NULL != (item = (zbx_hc_item_t *)zbx_hashset_iter_next(&iter))) + { + zbx_uint64_pair_t pair = {item->itemid, item->values_num}; + zbx_vector_uint64_pair_append_ptr(items, &pair); + } + + UNLOCK_CACHE; +} diff --git a/src/libs/zbxdbcache/valuecache.c b/src/libs/zbxdbcache/valuecache.c index 6f035ac08fa..5a9c7895610 100644 --- a/src/libs/zbxdbcache/valuecache.c +++ b/src/libs/zbxdbcache/valuecache.c @@ -176,6 +176,17 @@ typedef struct /* interval should be cached. */ int db_cached_from; + /* The maximum number of values returned by one request */ + /* during last hourly interval. */ + int last_hourly_num; + + /* The maximum number of values returned by one request */ + /* during current hourly interval. */ + int hourly_num; + + /* The hour of hourly_num */ + int hour; + /* The number of cache hits for this item. */ /* Used to evaluate if the item must be dropped from cache */ /* in low memory situation. */ @@ -648,8 +659,21 @@ static void vc_update_statistics(zbx_vc_item_t *item, int hits, int misses) { if (NULL != item) { + int hour; + item->hits += hits; item->last_accessed = time(NULL); + + hour = item->last_accessed / SEC_PER_HOUR; + if (hour != item->hour) + { + item->last_hourly_num = item->hourly_num; + item->hourly_num = 0; + item->hour = hour; + } + + if (hits + misses > item->hourly_num) + item->hourly_num = hits + misses; } if (ZBX_VC_ENABLED == vc_state) @@ -2818,6 +2842,92 @@ void zbx_vc_disable(void) vc_state = ZBX_VC_DISABLED; } +/****************************************************************************** + * * + * Function: zbx_hc_get_diag_stats * + * * + * Purpose: get value cache diagnostic statistics * + * * + ******************************************************************************/ +void zbx_vc_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num, int *mode) +{ + zbx_hashset_iter_t iter; + zbx_vc_item_t *item; + + *values_num = 0; + + if (ZBX_VC_DISABLED == vc_state) + { + *items_num = 0; + *mode = -1; + return; + } + + vc_try_lock(); + + *items_num = vc_cache->items.num_data; + *mode = vc_cache->mode; + + zbx_hashset_iter_reset(&vc_cache->items, &iter); + while (NULL != (item = (zbx_vc_item_t *)zbx_hashset_iter_next(&iter))) + *values_num += item->values_total; + + vc_try_unlock(); +} + +/****************************************************************************** + * * + * Function: zbx_hc_get_mem_stats * + * * + * Purpose: get value cache shared memory statistics * + * * + ******************************************************************************/ +void zbx_vc_get_mem_stats(zbx_mem_stats_t *mem) +{ + if (ZBX_VC_DISABLED == vc_state) + { + memset(mem, 0, sizeof(zbx_mem_stats_t)); + return; + } + + vc_try_lock(); + zbx_mem_get_stats(vc_mem, mem); + vc_try_unlock(); +} + +/****************************************************************************** + * * + * Function: zbx_vc_get_item_stats * + * * + * Purpose: get statistics of cached items * + * * + ******************************************************************************/ +void zbx_vc_get_item_stats(zbx_vector_ptr_t *stats) +{ + zbx_hashset_iter_t iter; + zbx_vc_item_t *item; + zbx_vc_item_stats_t *item_stats; + + if (ZBX_VC_DISABLED == vc_state) + return; + + vc_try_lock(); + + zbx_vector_ptr_reserve(stats, vc_cache->items.num_data); + + zbx_hashset_iter_reset(&vc_cache->items, &iter); + while (NULL != (item = (zbx_vc_item_t *)zbx_hashset_iter_next(&iter))) + { + item_stats = (zbx_vc_item_stats_t *)zbx_malloc(NULL, sizeof(zbx_vc_item_stats_t)); + item_stats->itemid = item->itemid; + item_stats->values_num = item->values_total; + item_stats->hourly_num = item->last_hourly_num; + zbx_vector_ptr_append(stats, item_stats); + } + + vc_try_unlock(); +} + #ifdef HAVE_TESTS # include "../../../tests/libs/zbxdbcache/valuecache_test.c" #endif diff --git a/src/libs/zbxdbcache/valuecache.h b/src/libs/zbxdbcache/valuecache.h index 50ca34e229d..b697dedd55f 100644 --- a/src/libs/zbxdbcache/valuecache.h +++ b/src/libs/zbxdbcache/valuecache.h @@ -23,6 +23,7 @@ #include "zbxtypes.h" #include "zbxalgo.h" #include "zbxhistory.h" +#include "memalloc.h" /* * The Value Cache provides read caching of item historical data residing in history @@ -82,6 +83,15 @@ typedef struct } zbx_vc_stats_t; +/* item diagnostic statistics */ +typedef struct +{ + zbx_uint64_t itemid; + int values_num; + int hourly_num; +} +zbx_vc_item_stats_t; + int zbx_vc_init(char **error); void zbx_vc_destroy(void); @@ -107,4 +117,8 @@ int zbx_vc_get_statistics(zbx_vc_stats_t *stats); void zbx_vc_housekeeping_value_cache(void); +void zbx_vc_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num, int *mode); +void zbx_vc_get_mem_stats(zbx_mem_stats_t *mem); +void zbx_vc_get_item_stats(zbx_vector_ptr_t *stats); + #endif /* ZABBIX_VALUECACHE_H */ diff --git a/src/libs/zbxdiag/Makefile.am b/src/libs/zbxdiag/Makefile.am new file mode 100644 index 00000000000..d8ed63fc941 --- /dev/null +++ b/src/libs/zbxdiag/Makefile.am @@ -0,0 +1,11 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxdiag_server.a libzbxdiag_proxy.a + +libzbxdiag_server_a_SOURCES = \ + diag.c \ + diag_server.c + +libzbxdiag_proxy_a_SOURCES = \ + diag.c \ + diag_proxy.c diff --git a/src/libs/zbxdiag/diag.c b/src/libs/zbxdiag/diag.c new file mode 100644 index 00000000000..6219f08e4ab --- /dev/null +++ b/src/libs/zbxdiag/diag.c @@ -0,0 +1,867 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "common.h" +#include "zbxalgo.h" +#include "dbcache.h" +#include "preproc.h" +#include "zbxdiag.h" +#include "diag.h" +#include "log.h" + +void diag_map_free(zbx_diag_map_t *map) +{ + zbx_free(map->name); + zbx_free(map); +} + +/****************************************************************************** + * * + * Function: diag_parse_request * + * * + * Purpose: parse diagnostic section request having json format * + * {"stats":[<field1>,<field2>,...], "top":{<field1>:<limit1>,...}} * + * * + * Parameters: jp - [IN] the request * + * field_map - [IN] a map of supported statistic field names to * + * bitmasks * + * field_mask - [OUT] the bitmask of the requested fields * + * top_views - [OUT] the requested top views * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the request was parsed successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int diag_parse_request(const struct zbx_json_parse *jp, const zbx_diag_map_t *field_map, + zbx_uint64_t *field_mask, zbx_vector_ptr_t *top_views, char **error) +{ + struct zbx_json_parse jp_stats; + int ret = FAIL; + const char *pnext = NULL; + char name[ZBX_DIAG_FIELD_MAX + 1], value[MAX_ID_LEN + 1]; + zbx_uint64_t value_ui64; + + *field_mask = 0; + + /* parse requested statistics fields */ + if (SUCCEED == zbx_json_brackets_by_name(jp, "stats", &jp_stats)) + { + while (NULL != (pnext = zbx_json_next(&jp_stats, pnext))) + { + if (NULL != zbx_json_decodevalue(pnext, name, sizeof(name), NULL)) + { + const zbx_diag_map_t *stat; + + for (stat = field_map;; stat++) + { + if (NULL == stat->name) + { + *error = zbx_dsprintf(*error, "Unsupported statistics field: %s", name); + goto out; + } + + if (0 == strcmp(name, stat->name)) + break; + } + + *field_mask |= stat->value; + } + } + } + + /* parse requested top views */ + if (SUCCEED == zbx_json_brackets_by_name(jp, "top", &jp_stats)) + { + while (NULL != (pnext = zbx_json_pair_next(&jp_stats, pnext, name, sizeof(name)))) + { + zbx_diag_map_t *top; + + if (NULL == zbx_json_decodevalue(pnext, value, sizeof(value), NULL)) + { + *error = zbx_strdup(*error, zbx_json_strerror()); + goto out; + } + if (FAIL == is_uint64(value, &value_ui64)) + { + *error = zbx_dsprintf(*error, "Invalid top limit value: %s", value); + goto out; + } + + top = (zbx_diag_map_t *)zbx_malloc(NULL, sizeof(zbx_diag_map_t)); + top->name = zbx_strdup(NULL, name); + top->value = value_ui64; + zbx_vector_ptr_append(top_views, top); + } + } + ret = SUCCEED; +out: + if (FAIL == ret) + zbx_vector_ptr_clear_ext(top_views, (zbx_ptr_free_func_t)diag_map_free); + + return ret; +} + +/****************************************************************************** + * * + * Function: diag_add_mem_stats * + * * + * Purpose: add memory statistics to the json data * + * * + * Parameters: json - [IN/OUT] the json to update * + * name - [IN] the memory object name * + * stats - [IN] the memory statistics * + * * + ******************************************************************************/ +void diag_add_mem_stats(struct zbx_json *json, const char *name, const zbx_mem_stats_t *stats) +{ + int i; + + if (NULL == stats) + return; + + zbx_json_addobject(json, name); + + zbx_json_addobject(json, "size"); + zbx_json_adduint64(json, "free", stats->free_size); + zbx_json_adduint64(json, "used", stats->used_size); + zbx_json_close(json); + + zbx_json_addobject(json, "chunks"); + zbx_json_adduint64(json, "free", stats->free_chunks); + zbx_json_adduint64(json, "used", stats->used_chunks); + zbx_json_adduint64(json, "min", stats->min_chunk_size); + zbx_json_adduint64(json, "max", stats->max_chunk_size); + + zbx_json_addarray(json, "buckets"); + + for (i = 0; i < MEM_BUCKET_COUNT; i++) + { + if (0 != stats->chunks_num[i]) + { + char buf[MAX_ID_LEN + 2]; + + zbx_snprintf(buf, sizeof(buf), "%d%s", MEM_MIN_BUCKET_SIZE + 8 * i, + (MEM_BUCKET_COUNT - 1 == i ? "+" : "")); + zbx_json_addobject(json, NULL); + zbx_json_adduint64(json, buf, stats->chunks_num[i]); + zbx_json_close(json); + } + } + + zbx_json_close(json); + zbx_json_close(json); + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_compare_pair_second_desc * + * * + * Purpose: compare uint64 pairs by second value for descending sorting * + * * + ******************************************************************************/ +static int diag_compare_pair_second_desc(const void *d1, const void *d2) +{ + zbx_uint64_pair_t *p1 = (zbx_uint64_pair_t *)d1; + zbx_uint64_pair_t *p2 = (zbx_uint64_pair_t *)d2; + + if (p1->second < p2->second) + return 1; + if (p1->second > p2->second) + return -1; + return 0; +} + +/****************************************************************************** + * * + * Function: diag_historycahe_add_items * + * * + * Purpose: add history cache items diagnostic statistics to json * + * * + ******************************************************************************/ +static void diag_historycache_add_items(struct zbx_json *json, const char *field, const zbx_uint64_pair_t *pairs, + int pairs_num) +{ + int i; + + zbx_json_addarray(json, field); + + for (i = 0; i < pairs_num; i++) + { + zbx_json_addobject(json, NULL); + zbx_json_addint64(json, "itemid", pairs[i].first); + zbx_json_addint64(json, "values", pairs[i].second); + zbx_json_close(json); + } + + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_add_historycache_info * + * * + * Purpose: add requested history cache diagnostic information to json data * + * * + * Parameters: jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the information was added successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int diag_add_historycache_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error) +{ + zbx_vector_ptr_t tops; + int ret; + double time1, time2, time_total = 0; + zbx_uint64_t fields; + zbx_diag_map_t field_map[] = { + {"all", ZBX_DIAG_HISTORYCACHE_SIMPLE | ZBX_DIAG_HISTORYCACHE_MEMORY}, + {"items", ZBX_DIAG_HISTORYCACHE_ITEMS}, + {"values", ZBX_DIAG_HISTORYCACHE_VALUES}, + {"memory", ZBX_DIAG_HISTORYCACHE_MEMORY}, + {"memory.data", ZBX_DIAG_HISTORYCACHE_MEMORY_DATA}, + {"memory.index", ZBX_DIAG_HISTORYCACHE_MEMORY_INDEX}, + {NULL, 0} + }; + + zbx_vector_ptr_create(&tops); + + if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error))) + { + int i; + + zbx_json_addobject(json, ZBX_DIAG_HISTORYCACHE); + + if (0 != (fields & ZBX_DIAG_HISTORYCACHE_SIMPLE)) + { + zbx_uint64_t values_num, items_num; + + time1 = zbx_time(); + zbx_hc_get_diag_stats(&items_num, &values_num); + time2 = zbx_time(); + time_total += time2 - time1; + + if (0 != (fields & ZBX_DIAG_HISTORYCACHE_ITEMS)) + zbx_json_addint64(json, "items", items_num); + if (0 != (fields & ZBX_DIAG_HISTORYCACHE_VALUES)) + zbx_json_addint64(json, "values", values_num); + } + + if (0 != (fields & ZBX_DIAG_HISTORYCACHE_MEMORY)) + { + zbx_mem_stats_t data_mem, index_mem, *pdata_mem, *pindex_mem; + + pdata_mem = (0 != (fields & ZBX_DIAG_HISTORYCACHE_MEMORY_DATA) ? &data_mem : NULL); + pindex_mem = (0 != (fields & ZBX_DIAG_HISTORYCACHE_MEMORY_INDEX) ? &index_mem : NULL); + + time1 = zbx_time(); + zbx_hc_get_mem_stats(pdata_mem, pindex_mem); + time2 = zbx_time(); + time_total += time2 - time1; + + zbx_json_addobject(json, "memory"); + diag_add_mem_stats(json, "data", pdata_mem); + diag_add_mem_stats(json, "index", pindex_mem); + zbx_json_close(json); + } + + if (0 != tops.values_num) + { + zbx_json_addobject(json, "top"); + + for (i = 0; i < tops.values_num; i++) + { + zbx_diag_map_t *map = (zbx_diag_map_t *)tops.values[i]; + + if (0 == strcmp(map->name, "values")) + { + zbx_vector_uint64_pair_t items; + int limit; + + zbx_vector_uint64_pair_create(&items); + + time1 = zbx_time(); + zbx_hc_get_items(&items); + time2 = zbx_time(); + time_total += time2 - time1; + + zbx_vector_uint64_pair_sort(&items, diag_compare_pair_second_desc); + limit = MIN((int)map->value, items.values_num); + + diag_historycache_add_items(json, map->name, (zbx_uint64_pair_t *)items.values, + limit); + zbx_vector_uint64_pair_destroy(&items); + } + else + { + *error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name); + ret = FAIL; + break; + } + } + + zbx_json_close(json); + } + + zbx_json_addfloat(json, "time", time_total); + + zbx_json_close(json); + } + + zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free); + zbx_vector_ptr_destroy(&tops); + + return ret; +} + +/****************************************************************************** + * * + * Function: diag_add_preproc_items * + * * + * Purpose: add item top list to output json * + * * + * Parameters: json - [OUT] the output json * + * field - [IN] the field name * + * items - [IN] a top item list * + * * + ******************************************************************************/ +static void diag_add_preproc_items(struct zbx_json *json, const char *field, const zbx_vector_ptr_t *items) +{ + int i; + + zbx_json_addarray(json, field); + + for (i = 0; i < items->values_num; i++) + { + const zbx_preproc_item_stats_t *item = (const zbx_preproc_item_stats_t *)items->values[i]; + + zbx_json_addobject(json, NULL); + zbx_json_adduint64(json, "itemid", item->itemid); + zbx_json_adduint64(json, "values", item->values_num); + zbx_json_adduint64(json, "steps", item->steps_num); + zbx_json_close(json); + } + + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_add_preproc_info * + * * + * Purpose: add requested preprocessing diagnostic information to json data * + * * + * Parameters: jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the information was added successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int diag_add_preproc_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error) +{ + zbx_vector_ptr_t tops; + int ret = FAIL; + double time1, time2, time_total = 0; + zbx_uint64_t fields; + zbx_diag_map_t field_map[] = { + {"all", ZBX_DIAG_PREPROC_VALUES | ZBX_DIAG_PREPROC_VALUES_PREPROC}, + {"values", ZBX_DIAG_PREPROC_VALUES}, + {"preproc.values", ZBX_DIAG_PREPROC_VALUES_PREPROC}, + {NULL, 0} + }; + + zbx_vector_ptr_create(&tops); + + if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error))) + { + zbx_json_addobject(json, ZBX_DIAG_PREPROCESSING); + + if (0 != (fields & ZBX_DIAG_PREPROC_SIMPLE)) + { + int values_num, values_preproc_num; + + time1 = zbx_time(); + if (FAIL == (ret = zbx_preprocessor_get_diag_stats(&values_num, &values_preproc_num, error))) + goto out; + + time2 = zbx_time(); + time_total += time2 - time1; + + if (0 != (fields & ZBX_DIAG_PREPROC_VALUES)) + zbx_json_addint64(json, "values", values_num); + if (0 != (fields & ZBX_DIAG_PREPROC_VALUES_PREPROC)) + zbx_json_addint64(json, "preproc.values", values_preproc_num); + } + + if (0 != tops.values_num) + { + int i; + + zbx_json_addobject(json, "top"); + + for (i = 0; i < tops.values_num; i++) + { + zbx_diag_map_t *map = (zbx_diag_map_t *)tops.values[i]; + + if (0 == strcmp(map->name, "values")) + { + zbx_vector_ptr_t items; + + zbx_vector_ptr_create(&items); + time1 = zbx_time(); + if (FAIL == (ret = zbx_preprocessor_get_top_items(map->value, &items, error))) + { + zbx_vector_ptr_destroy(&items); + goto out; + } + time2 = zbx_time(); + time_total += time2 - time1; + + diag_add_preproc_items(json, map->name, &items); + zbx_vector_ptr_clear_ext(&items, zbx_ptr_free); + zbx_vector_ptr_destroy(&items); + } + else + { + *error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name); + ret = FAIL; + goto out; + } + } + + zbx_json_close(json); + } + + zbx_json_addfloat(json, "time", time_total); + zbx_json_close(json); + } +out: + zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free); + zbx_vector_ptr_destroy(&tops); + + return ret; +} + +/****************************************************************************** + * * + * Function: zbx_diag_get_info * + * * + * Purpose: get diagnostic information * + * * + * Parameters: jp - [IN] the request * + * info - [OUT] the requested information or error message * + * * + * Return value: SUCCEED - the information was retrieved successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_diag_get_info(const struct zbx_json_parse *jp, char **info) +{ + struct zbx_json_parse jp_section; + char section[ZBX_DIAG_SECTION_MAX + 1]; + const char *pnext = NULL; + struct zbx_json json; + int ret = SUCCEED; + + zbx_json_init(&json, 1024); + + while (NULL != (pnext = zbx_json_pair_next(jp, pnext, section, sizeof(section)))) + { + if (FAIL == (ret = zbx_json_brackets_open(pnext, &jp_section))) + { + *info = zbx_strdup(*info, zbx_json_strerror()); + goto out; + } + + if (FAIL == (ret = diag_add_section_info(section, &jp_section, &json, info))) + goto out; + } +out: + if (SUCCEED == ret) + *info = zbx_strdup(*info, json.buffer); + + zbx_json_free(&json); + + return ret; +} + +#define ZBX_DIAG_DEFAULT_TOP_LIMIT 25 + +/****************************************************************************** + * * + * Function: diag_add_section_request * + * * + * Purpose: add default diagnostic section request * + * * + * Parameters: j - [OUT] the request json * + * section - [IN] the section name * + * ... - [IN] null terminated list of top field names * + * * + ******************************************************************************/ +static void diag_add_section_request(struct zbx_json *j, const char *section, ...) +{ + va_list args; + const char *field; + + zbx_json_addobject(j, section); + zbx_json_addarray(j, "stats"); + zbx_json_addstring(j, NULL, "all", ZBX_JSON_TYPE_STRING); + zbx_json_close(j); + + zbx_json_addobject(j, "top"); + + va_start(args, section); + + while (NULL != (field = va_arg(args, const char *))) + zbx_json_adduint64(j, field, ZBX_DIAG_DEFAULT_TOP_LIMIT); + + va_end(args); + + zbx_json_close(j); + zbx_json_close(j); +} + +/****************************************************************************** + * * + * Function: diag_prepare_default_request * + * * + * Purpose: prepare default diagnostic request for all sections * + * * + ******************************************************************************/ +static void diag_prepare_default_request(struct zbx_json *j, unsigned int flags) +{ + if (0 != (flags & (1 << ZBX_DIAGINFO_HISTORYCACHE))) + diag_add_section_request(j, ZBX_DIAG_HISTORYCACHE, "values", NULL); + + if (0 != (flags & (1 << ZBX_DIAGINFO_VALUECACHE))) + diag_add_section_request(j, ZBX_DIAG_VALUECACHE, "values", "request.values", NULL); + + if (0 != (flags & (1 << ZBX_DIAGINFO_PREPROCESSING))) + diag_add_section_request(j, ZBX_DIAG_PREPROCESSING, "values", NULL); + + if (0 != (flags & (1 << ZBX_DIAGINFO_LLD))) + diag_add_section_request(j, ZBX_DIAG_LLD, "values", NULL); + + if (0 != (flags & (1 << ZBX_DIAGINFO_ALERTING))) + diag_add_section_request(j, ZBX_DIAG_ALERTING, "media.alerts", "source.alerts", NULL); +} + +/****************************************************************************** + * * + * Function: diag_get_simple_values * + * * + * Purpose: extract simple values in format <key1>:<value1> <key2>:<value2>...* + * from the specified json location * + * * + * Parameters: jp - [IN] the json location * + * msg - [OUT] the extracted values * + * * + ******************************************************************************/ +static void diag_get_simple_values(const struct zbx_json_parse *jp, char **msg) +{ + const char *pnext = NULL; + char key[MAX_STRING_LEN], *value = NULL; + struct zbx_json_parse jp_value; + size_t value_alloc = 0, msg_alloc = 0, msg_offset = 0; + zbx_json_type_t type; + + + while (NULL != (pnext = zbx_json_pair_next(jp, pnext, key, sizeof(key)))) + { + if (FAIL == zbx_json_brackets_open(pnext, &jp_value)) + { + zbx_json_decodevalue_dyn(pnext, &value, &value_alloc, &type); + + if (0 != msg_offset) + zbx_chrcpy_alloc(msg, &msg_alloc, &msg_offset, ' '); + + zbx_snprintf_alloc(msg, &msg_alloc, &msg_offset, "%s:%s", key, + (ZBX_JSON_TYPE_NULL != type ? value: "null")); + } + } + + zbx_free(value); +} + +/****************************************************************************** + * * + * Function: diag_log_memory_info * + * * + * Purpose: log shared memory information * + * * + * Parameters: jp - [IN] the section json * + * field - [OUT] the memory field name * + * path - [OUT] the json path to the memory data * + * * + ******************************************************************************/ +static void diag_log_memory_info(struct zbx_json_parse *jp, const char *field, const char *path) +{ + struct zbx_json_parse jp_memory, jp_size, jp_chunks; + char *msg = NULL; + + if (FAIL == zbx_json_open_path(jp, path, &jp_memory)) + return; + + zabbix_log(LOG_LEVEL_INFORMATION, "%s:", field); + if (SUCCEED == zbx_json_brackets_by_name(&jp_memory, "size", &jp_size)) + { + diag_get_simple_values(&jp_size, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, " size: %s", msg); + zbx_free(msg); + } + + if (SUCCEED == zbx_json_brackets_by_name(&jp_memory, "chunks", &jp_chunks)) + { + struct zbx_json_parse jp_buckets, jp_bucket; + + diag_get_simple_values(&jp_chunks, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, " chunks: %s", msg); + zbx_free(msg); + + if (SUCCEED == zbx_json_brackets_by_name(&jp_chunks, "buckets", &jp_buckets)) + { + const char *pnext; + + zabbix_log(LOG_LEVEL_INFORMATION, " buckets:"); + + for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp_buckets, pnext));) + { + if (SUCCEED == zbx_json_brackets_open(pnext, &jp_bucket)) + { + diag_get_simple_values(&jp_bucket, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, " %s", msg); + zbx_free(msg); + } + } + } + } +} + +/****************************************************************************** + * * + * Function: diag_log_top_view * + * * + * Purpose: log top view * + * * + * Parameters: jp - [IN] the section json * + * field - [OUT] the top field name * + * path - [OUT] the json path to the top view * + * * + ******************************************************************************/ +static void diag_log_top_view(struct zbx_json_parse *jp, const char *field, const char *path) +{ + struct zbx_json_parse jp_top, jp_row; + const char *pnext; + char *msg = NULL; + + if (FAIL == zbx_json_open_path(jp, path, &jp_top)) + return; + + zabbix_log(LOG_LEVEL_INFORMATION, "%s:", field); + + for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp_top, pnext));) + { + if (SUCCEED == zbx_json_brackets_open(pnext, &jp_row)) + { + diag_get_simple_values(&jp_row, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, " %s", msg); + zbx_free(msg); + } + } +} + +/****************************************************************************** + * * + * Function: diag_log_history_cache * + * * + * Purpose: log history cache diagnostic information * + * * + ******************************************************************************/ +static void diag_log_history_cache(struct zbx_json_parse *jp) +{ + char *msg = NULL; + + zabbix_log(LOG_LEVEL_INFORMATION, "== history cache diagnostic information =="); + + diag_get_simple_values(jp, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_free(msg); + + diag_log_memory_info(jp, "memory.data", "$.memory.data"); + diag_log_memory_info(jp, "memory.index", "$.memory.index"); + + diag_log_top_view(jp, "top.values", "$.top.values"); + + zabbix_log(LOG_LEVEL_INFORMATION, "=="); +} + +/****************************************************************************** + * * + * Function: diag_log_value_cache * + * * + * Purpose: log value cache diagnostic information * + * * + ******************************************************************************/ +static void diag_log_value_cache(struct zbx_json_parse *jp) +{ + char *msg = NULL; + + zabbix_log(LOG_LEVEL_INFORMATION, "== value cache diagnostic information =="); + + diag_get_simple_values(jp, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_free(msg); + + diag_log_memory_info(jp, "memory", "$.memory"); + + diag_log_top_view(jp, "top.values", "$.top.values"); + diag_log_top_view(jp, "top.request.values", "$.top['request.values']"); + + zabbix_log(LOG_LEVEL_INFORMATION, "=="); +} + +/****************************************************************************** + * * + * Function: diag_log_preprocessing * + * * + * Purpose: log preprocessing diagnostic information * + * * + ******************************************************************************/ +static void diag_log_preprocessing(struct zbx_json_parse *jp) +{ + char *msg = NULL; + + zabbix_log(LOG_LEVEL_INFORMATION, "== preprocessing diagnostic information =="); + + diag_get_simple_values(jp, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_free(msg); + + diag_log_top_view(jp, "top.values", "$.top.values"); + + zabbix_log(LOG_LEVEL_INFORMATION, "=="); +} + +/****************************************************************************** + * * + * Function: diag_log_lld * + * * + * Purpose: log LLD diagnostic information * + * * + ******************************************************************************/ + +static void diag_log_lld(struct zbx_json_parse *jp) +{ + char *msg = NULL; + + zabbix_log(LOG_LEVEL_INFORMATION, "== LLD diagnostic information =="); + + diag_get_simple_values(jp, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_free(msg); + + diag_log_top_view(jp, "top.values", "$.top.values"); + + zabbix_log(LOG_LEVEL_INFORMATION, "=="); +} + +/****************************************************************************** + * * + * Function: diag_log_alerting * + * * + * Purpose: log alerting diagnostic information * + * * + ******************************************************************************/ +static void diag_log_alerting(struct zbx_json_parse *jp) +{ + char *msg = NULL; + + zabbix_log(LOG_LEVEL_INFORMATION, "== alerting diagnostic information =="); + + diag_get_simple_values(jp, &msg); + zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_free(msg); + + diag_log_top_view(jp, "media.alerts", "$.top['media.alerts']"); + diag_log_top_view(jp, "source.alerts", "$.top['source.alerts']"); + + zabbix_log(LOG_LEVEL_INFORMATION, "=="); +} + +/****************************************************************************** + * * + * Function: zbx_diag_log_info * + * * + * Purpose: log diagnostic information * + * * + * Parameters: flags - [IN] flags describing section to log * + * * + ******************************************************************************/ +void zbx_diag_log_info(unsigned int flags) +{ + struct zbx_json j; + struct zbx_json_parse jp; + char *info = NULL; + + zbx_json_init(&j, 1024); + + diag_prepare_default_request(&j, flags); + zbx_json_open(j.buffer, &jp); + + if (SUCCEED == zbx_diag_get_info(&jp, &info)) + { + char section[ZBX_DIAG_SECTION_MAX + 1]; + struct zbx_json_parse jp_section; + const char *pnext = NULL; + + zbx_json_open(info, &jp); + + while (NULL != (pnext = zbx_json_pair_next(&jp, pnext, section, sizeof(section)))) + { + if (FAIL == zbx_json_brackets_open(pnext, &jp_section)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE)) + diag_log_history_cache(&jp_section); + else if (0 == strcmp(section, ZBX_DIAG_VALUECACHE)) + diag_log_value_cache(&jp_section); + else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING)) + diag_log_preprocessing(&jp_section); + else if (0 == strcmp(section, ZBX_DIAG_LLD)) + diag_log_lld(&jp_section); + else if (0 == strcmp(section, ZBX_DIAG_ALERTING)) + diag_log_alerting(&jp_section); + } + } + else + zabbix_log(LOG_LEVEL_INFORMATION, "cannot obtain diagnostic information: %s", info); + + zbx_free(info); + zbx_json_free(&j); +} + diff --git a/src/libs/zbxdiag/diag.h b/src/libs/zbxdiag/diag.h new file mode 100644 index 00000000000..f871205bcbc --- /dev/null +++ b/src/libs/zbxdiag/diag.h @@ -0,0 +1,88 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +#ifndef ZABBIX_DIAG_H +#define ZABBIX_DIAG_H + +#include "common.h" +#include "zbxjson.h" +#include "zbxalgo.h" +#include "memalloc.h" + +#define ZBX_DIAG_SECTION_MAX 64 +#define ZBX_DIAG_FIELD_MAX 64 + +#define ZBX_DIAG_HISTORYCACHE_ITEMS 0x00000001 +#define ZBX_DIAG_HISTORYCACHE_VALUES 0x00000002 +#define ZBX_DIAG_HISTORYCACHE_MEMORY_DATA 0x00000004 +#define ZBX_DIAG_HISTORYCACHE_MEMORY_INDEX 0x00000008 + +#define ZBX_DIAG_HISTORYCACHE_SIMPLE (ZBX_DIAG_HISTORYCACHE_ITEMS | \ + ZBX_DIAG_HISTORYCACHE_VALUES) + +#define ZBX_DIAG_HISTORYCACHE_MEMORY (ZBX_DIAG_HISTORYCACHE_MEMORY_DATA | \ + ZBX_DIAG_HISTORYCACHE_MEMORY_INDEX) + +#define ZBX_DIAG_VALUECACHE_ITEMS 0x00000001 +#define ZBX_DIAG_VALUECACHE_VALUES 0x00000002 +#define ZBX_DIAG_VALUECACHE_MODE 0x00000004 +#define ZBX_DIAG_VALUECACHE_MEMORY 0x00000008 + +#define ZBX_DIAG_VALUECACHE_SIMPLE (ZBX_DIAG_VALUECACHE_ITEMS | \ + ZBX_DIAG_VALUECACHE_VALUES | \ + ZBX_DIAG_VALUECACHE_MODE) + +#define ZBX_DIAG_PREPROC_VALUES 0x00000001 +#define ZBX_DIAG_PREPROC_VALUES_PREPROC 0x00000002 + +#define ZBX_DIAG_PREPROC_SIMPLE (ZBX_DIAG_PREPROC_VALUES | \ + ZBX_DIAG_PREPROC_VALUES_PREPROC) + +#define ZBX_DIAG_LLD_RULES 0x00000001 +#define ZBX_DIAG_LLD_VALUES 0x00000002 + +#define ZBX_DIAG_LLD_SIMPLE (ZBX_DIAG_LLD_RULES | \ + ZBX_DIAG_LLD_VALUES) + +#define ZBX_DIAG_ALERTING_ALERTS 0x00000001 + +#define ZBX_DIAG_ALERTING_SIMPLE (ZBX_DIAG_ALERTING_ALERTS) + +typedef struct +{ + char *name; + zbx_uint64_t value; +} +zbx_diag_map_t; + +void diag_map_free(zbx_diag_map_t *map); + +int diag_parse_request(const struct zbx_json_parse *jp, const zbx_diag_map_t *field_map, zbx_uint64_t *field_mask, + zbx_vector_ptr_t *top_views, char **error); + +void diag_add_mem_stats(struct zbx_json *j, const char *name, const zbx_mem_stats_t *stats); + +int diag_add_section_info(const char *section, const struct zbx_json_parse *jp, struct zbx_json *j, char **error); + +int diag_add_historycache_info(const struct zbx_json_parse *jp, struct zbx_json *j, char **error); + +int diag_add_preproc_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error); + +#endif diff --git a/src/libs/zbxdiag/diag_proxy.c b/src/libs/zbxdiag/diag_proxy.c new file mode 100644 index 00000000000..ddd2f887907 --- /dev/null +++ b/src/libs/zbxdiag/diag_proxy.c @@ -0,0 +1,53 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "common.h" +#include "zbxdiag.h" + +#include "diag.h" + +/****************************************************************************** + * * + * Function: diag_add_section_info * + * * + * Purpose: add requested section diagnostic information * + * * + * Parameters: section - [IN] the section name * + * jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - the information was retrieved successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int diag_add_section_info(const char *section, const struct zbx_json_parse *jp, struct zbx_json *json, + char **error) +{ + int ret = FAIL; + + if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE)) + ret = diag_add_historycache_info(jp, json, error); + else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING)) + ret = diag_add_preproc_info(jp, json, error); + else + *error = zbx_dsprintf(*error, "Unsupported diagnostics section: %s", section); + + return ret; +} diff --git a/src/libs/zbxdiag/diag_server.c b/src/libs/zbxdiag/diag_server.c new file mode 100644 index 00000000000..fb46f650ddc --- /dev/null +++ b/src/libs/zbxdiag/diag_server.c @@ -0,0 +1,540 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "common.h" +#include "zbxalgo.h" +#include "memalloc.h" +#include "../../libs/zbxdbcache/valuecache.h" +#include "zbxlld.h" +#include "zbxalert.h" +#include "zbxdiag.h" + +#include "diag.h" + +/****************************************************************************** + * * + * Function: diag_historycache_item_compare_values * + * * + * Purpose: sort itemid,values_num pair by values_num in descending order * + * * + ******************************************************************************/ +static int diag_valuecache_item_compare_values(const void *d1, const void *d2) +{ + zbx_vc_item_stats_t *i1 = *(zbx_vc_item_stats_t **)d1; + zbx_vc_item_stats_t *i2 = *(zbx_vc_item_stats_t **)d2; + + return i2->values_num - i1->values_num; +} + +/****************************************************************************** + * * + * Function: diag_valuecache_item_compare_hourly * + * * + * Purpose: sort itemid,values_num pair by hourly_num in descending order * + * * + ******************************************************************************/ +static int diag_valuecache_item_compare_hourly(const void *d1, const void *d2) +{ + zbx_vc_item_stats_t *i1 = *(zbx_vc_item_stats_t **)d1; + zbx_vc_item_stats_t *i2 = *(zbx_vc_item_stats_t **)d2; + + return i2->hourly_num - i1->hourly_num; +} + +/****************************************************************************** + * * + * Function: diag_valuecache_add_items * + * * + * Purpose: add valuecache items diagnostic statistics to json * + * * + ******************************************************************************/ +static void diag_valuecache_add_items(struct zbx_json *json, const char *field, zbx_vc_item_stats_t **items, + int items_num) +{ + int i; + + zbx_json_addarray(json, field); + + for (i = 0; i < items_num; i++) + { + zbx_json_addobject(json, NULL); + zbx_json_addint64(json, "itemid", items[i]->itemid); + zbx_json_addint64(json, "values", items[i]->values_num); + zbx_json_addint64(json, "request.values", items[i]->hourly_num); + zbx_json_close(json); + } + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_add_valuecache_info * + * * + * Purpose: add requested value cache diagnostic information to json data * + * * + * Parameters: jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the information was added successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int diag_add_valuecache_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error) +{ + zbx_vector_ptr_t tops; + int ret; + double time1, time2, time_total = 0; + zbx_uint64_t fields; + zbx_diag_map_t field_map[] = { + {"all", ZBX_DIAG_VALUECACHE_SIMPLE | ZBX_DIAG_VALUECACHE_MEMORY}, + {"items", ZBX_DIAG_VALUECACHE_ITEMS}, + {"values", ZBX_DIAG_VALUECACHE_VALUES}, + {"mode", ZBX_DIAG_VALUECACHE_MODE}, + {"memory", ZBX_DIAG_VALUECACHE_MEMORY}, + {NULL, 0} + }; + + zbx_vector_ptr_create(&tops); + + if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error))) + { + zbx_json_addobject(json, ZBX_DIAG_VALUECACHE); + + if (0 != (fields & ZBX_DIAG_VALUECACHE_SIMPLE)) + { + zbx_uint64_t values_num, items_num; + int mode; + + time1 = zbx_time(); + zbx_vc_get_diag_stats(&items_num, &values_num, &mode); + time2 = zbx_time(); + time_total += time2 - time1; + + if (0 != (fields & ZBX_DIAG_VALUECACHE_ITEMS)) + zbx_json_addint64(json, "items", items_num); + if (0 != (fields & ZBX_DIAG_VALUECACHE_VALUES)) + zbx_json_addint64(json, "values", values_num); + if (0 != (fields & ZBX_DIAG_VALUECACHE_MODE)) + zbx_json_addint64(json, "mode", mode); + } + + if (0 != (fields & ZBX_DIAG_VALUECACHE_MEMORY)) + { + zbx_mem_stats_t mem; + + time1 = zbx_time(); + zbx_vc_get_mem_stats(&mem); + time2 = zbx_time(); + time_total += time2 - time1; + + diag_add_mem_stats(json, "memory", &mem); + } + + if (0 != tops.values_num) + { + zbx_vector_ptr_t items; + int i; + + zbx_vector_ptr_create(&items); + + time1 = zbx_time(); + zbx_vc_get_item_stats(&items); + time2 = zbx_time(); + time_total += time2 - time1; + + zbx_json_addobject(json, "top"); + + for (i = 0; i < tops.values_num; i++) + { + zbx_diag_map_t *map = (zbx_diag_map_t *)tops.values[i]; + int limit; + + if (0 == strcmp(map->name, "values")) + { + zbx_vector_ptr_sort(&items, diag_valuecache_item_compare_values); + } + else if (0 == strcmp(map->name, "request.values")) + { + zbx_vector_ptr_sort(&items, diag_valuecache_item_compare_hourly); + } + else + { + *error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name); + ret = FAIL; + goto out; + } + + limit = MIN((int)map->value, items.values_num); + diag_valuecache_add_items(json, map->name, (zbx_vc_item_stats_t **)items.values, limit); + } + zbx_json_close(json); + + zbx_vector_ptr_clear_ext(&items, zbx_ptr_free); + zbx_vector_ptr_destroy(&items); + } + + zbx_json_addfloat(json, "time", time_total); + + zbx_json_close(json); + } +out: + zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free); + zbx_vector_ptr_destroy(&tops); + + return ret; +} + +/****************************************************************************** + * * + * Function: diag_add_lld_items * + * * + * Purpose: add lld item top list to output json * + * * + ******************************************************************************/ +static void diag_add_lld_items(struct zbx_json *json, const char *field, const zbx_vector_uint64_pair_t *items) +{ + int i; + + zbx_json_addarray(json, field); + + for (i = 0; i < items->values_num; i++) + { + zbx_json_addobject(json, NULL); + zbx_json_adduint64(json, "itemid", items->values[i].first); + zbx_json_adduint64(json, "values", items->values[i].second); + zbx_json_close(json); + } + + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_add_lld_info * + * * + * Purpose: add requested lld manager diagnostic information to json data * + * * + * Parameters: jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the information was added successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int diag_add_lld_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error) +{ + zbx_vector_ptr_t tops; + int ret; + double time1, time2, time_total = 0; + zbx_uint64_t fields; + zbx_diag_map_t field_map[] = { + {"all", ZBX_DIAG_LLD_SIMPLE}, + {"rules", ZBX_DIAG_LLD_RULES}, + {"values", ZBX_DIAG_LLD_VALUES}, + {NULL, 0} + }; + + zbx_vector_ptr_create(&tops); + + if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error))) + { + zbx_json_addobject(json, ZBX_DIAG_LLD); + + if (0 != (fields & ZBX_DIAG_LLD_SIMPLE)) + { + zbx_uint64_t values_num, items_num; + + time1 = zbx_time(); + if (FAIL == (ret = zbx_lld_get_diag_stats(&items_num, &values_num, error))) + goto out; + time2 = zbx_time(); + time_total += time2 - time1; + + if (0 != (fields & ZBX_DIAG_LLD_RULES)) + zbx_json_addint64(json, "rules", items_num); + if (0 != (fields & ZBX_DIAG_LLD_VALUES)) + zbx_json_addint64(json, "values", values_num); + } + + if (0 != tops.values_num) + { + int i; + + zbx_json_addobject(json, "top"); + + for (i = 0; i < tops.values_num; i++) + { + zbx_diag_map_t *map = (zbx_diag_map_t *)tops.values[i]; + + if (0 == strcmp(map->name, "values")) + { + zbx_vector_uint64_pair_t items; + + zbx_vector_uint64_pair_create(&items); + + time1 = zbx_time(); + if (FAIL == (ret = zbx_lld_get_top_items(map->value, &items, error))) + { + zbx_vector_uint64_pair_destroy(&items); + goto out; + } + time2 = zbx_time(); + time_total += time2 - time1; + + diag_add_lld_items(json, map->name, &items); + zbx_vector_uint64_pair_destroy(&items); + } + else + { + *error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name); + ret = FAIL; + goto out; + } + } + + zbx_json_close(json); + } + + zbx_json_addfloat(json, "time", time_total); + zbx_json_close(json); + } +out: + zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free); + zbx_vector_ptr_destroy(&tops); + + return ret; +} + +/****************************************************************************** + * * + * Function: diag_add_alerting_mediatypes * + * * + * Purpose: add mediatype top list to output json * + * * + * Parameters: json - [OUT] the output json * + * field - [IN] the field name * + * items - [IN] a top mediatype list consisting of * + * mediatype, alerts_num pairs * + * * + ******************************************************************************/ +static void diag_add_alerting_mediatypes(struct zbx_json *json, const char *field, + const zbx_vector_uint64_pair_t *mediatypes) +{ + int i; + + zbx_json_addarray(json, field); + + for (i = 0; i < mediatypes->values_num; i++) + { + zbx_json_addobject(json, NULL); + zbx_json_adduint64(json, "mediatypeid", mediatypes->values[i].first); + zbx_json_adduint64(json, "alerts", mediatypes->values[i].second); + zbx_json_close(json); + } + + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_add_alerting_sources * + * * + * Purpose: add alert source top list to output json * + * * + * Parameters: json - [OUT] the output json * + * field - [IN] the field name * + * items - [IN] a top alert source list consisting of * + * zbx_am_source_stats_t structures * + * * + ******************************************************************************/ +static void diag_add_alerting_sources(struct zbx_json *json, const char *field, const zbx_vector_ptr_t *sources) +{ + int i; + + zbx_json_addarray(json, field); + + for (i = 0; i < sources->values_num; i++) + { + const zbx_am_source_stats_t *source = (const zbx_am_source_stats_t *)sources->values[i]; + + zbx_json_addobject(json, NULL); + zbx_json_adduint64(json, "source", source->source); + zbx_json_adduint64(json, "object", source->object); + zbx_json_adduint64(json, "objectid", source->objectid); + zbx_json_adduint64(json, "alerts", source->alerts_num); + zbx_json_close(json); + } + + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: diag_add_alerting_info * + * * + * Purpose: add requested alert manager diagnostic information to json data * + * * + * Parameters: jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the information was added successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int diag_add_alerting_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error) +{ + zbx_vector_ptr_t tops; + int ret; + double time1, time2, time_total = 0; + zbx_uint64_t fields; + zbx_diag_map_t field_map[] = { + {"all", ZBX_DIAG_ALERTING_SIMPLE}, + {"alerts", ZBX_DIAG_ALERTING_ALERTS}, + {NULL, 0} + }; + + zbx_vector_ptr_create(&tops); + + if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error))) + { + zbx_json_addobject(json, ZBX_DIAG_ALERTING); + + if (0 != (fields & ZBX_DIAG_ALERTING_SIMPLE)) + { + zbx_uint64_t alerts_num; + + time1 = zbx_time(); + if (FAIL == (ret = zbx_alerter_get_diag_stats(&alerts_num, error))) + goto out; + time2 = zbx_time(); + time_total += time2 - time1; + + if (0 != (fields & ZBX_DIAG_ALERTING_ALERTS)) + zbx_json_addint64(json, "alerts", alerts_num); + } + + if (0 != tops.values_num) + { + int i; + + zbx_json_addobject(json, "top"); + + for (i = 0; i < tops.values_num; i++) + { + zbx_diag_map_t *map = (zbx_diag_map_t *)tops.values[i]; + + if (0 == strcmp(map->name, "media.alerts")) + { + zbx_vector_uint64_pair_t mediatypes; + + zbx_vector_uint64_pair_create(&mediatypes); + + time1 = zbx_time(); + if (FAIL == (ret = zbx_alerter_get_top_mediatypes(map->value, &mediatypes, + error))) + { + zbx_vector_uint64_pair_destroy(&mediatypes); + goto out; + } + time2 = zbx_time(); + time_total += time2 - time1; + + diag_add_alerting_mediatypes(json, map->name, &mediatypes); + zbx_vector_uint64_pair_destroy(&mediatypes); + } + else if (0 == strcmp(map->name, "source.alerts")) + { + zbx_vector_ptr_t sources; + + zbx_vector_ptr_create(&sources); + + time1 = zbx_time(); + if (FAIL == (ret = zbx_alerter_get_top_sources(map->value, &sources, error))) + { + zbx_vector_ptr_clear_ext(&sources, zbx_ptr_free); + zbx_vector_ptr_destroy(&sources); + goto out; + } + time2 = zbx_time(); + time_total += time2 - time1; + + diag_add_alerting_sources(json, map->name, &sources); + zbx_vector_ptr_clear_ext(&sources, zbx_ptr_free); + zbx_vector_ptr_destroy(&sources); + } + else + { + *error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name); + ret = FAIL; + goto out; + } + } + + zbx_json_close(json); + } + + zbx_json_addfloat(json, "time", time_total); + zbx_json_close(json); + } +out: + zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free); + zbx_vector_ptr_destroy(&tops); + + return ret; +} + +/****************************************************************************** + * * + * Function: diag_add_section_info * + * * + * Purpose: add requested section diagnostic information * + * * + * Parameters: section - [IN] the section name * + * jp - [IN] the request * + * json - [IN/OUT] the json to update * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - the information was retrieved successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int diag_add_section_info(const char *section, const struct zbx_json_parse *jp, struct zbx_json *json, + char **error) +{ + int ret = FAIL; + + if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE)) + ret = diag_add_historycache_info(jp, json, error); + else if (0 == strcmp(section, ZBX_DIAG_VALUECACHE)) + ret = diag_add_valuecache_info(jp, json, error); + else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING)) + ret = diag_add_preproc_info(jp, json, error); + else if (0 == strcmp(section, ZBX_DIAG_LLD)) + ret = diag_add_lld_info(jp, json, error); + else if (0 == strcmp(section, ZBX_DIAG_ALERTING)) + ret = diag_add_alerting_info(jp, json, error); + else + *error = zbx_dsprintf(*error, "Unsupported diagnostics section: %s", section); + + return ret; +} + diff --git a/src/libs/zbxjson/json.h b/src/libs/zbxjson/json.h index 1ddfc98fc25..55bcb55e6fa 100644 --- a/src/libs/zbxjson/json.h +++ b/src/libs/zbxjson/json.h @@ -29,6 +29,5 @@ SKIP_WHITESPACE(src) void zbx_set_json_strerror(const char *fmt, ...) __zbx_attr_format_printf(1, 2); -int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out); #endif diff --git a/src/libs/zbxmemory/memalloc.c b/src/libs/zbxmemory/memalloc.c index 698b64a1598..086c773065a 100644 --- a/src/libs/zbxmemory/memalloc.c +++ b/src/libs/zbxmemory/memalloc.c @@ -124,12 +124,6 @@ static void __mem_free(zbx_mem_info_t *info, void *ptr); #define MEM_MIN_SIZE __UINT64_C(128) #define MEM_MAX_SIZE __UINT64_C(0x1000000000) /* 64 GB */ -#define MEM_MIN_ALLOC 24 /* should be a multiple of 8 and at least (2 * ZBX_PTR_SIZE) */ - -#define MEM_MIN_BUCKET_SIZE MEM_MIN_ALLOC -#define MEM_MAX_BUCKET_SIZE 256 /* starting from this size all free chunks are put into the same bucket */ -#define MEM_BUCKET_COUNT ((MEM_MAX_BUCKET_SIZE - MEM_MIN_BUCKET_SIZE) / 8 + 1) - /* helper functions */ static void *ALIGN4(void *ptr) @@ -734,47 +728,67 @@ void zbx_mem_clear(zbx_mem_info_t *info) zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } -void zbx_mem_dump_stats(int level, zbx_mem_info_t *info) +void zbx_mem_get_stats(const zbx_mem_info_t *info, zbx_mem_stats_t *stats) { void *chunk; - int index; - zbx_uint64_t counter, total, total_free = 0; - zbx_uint64_t min_size = __UINT64_C(0xffffffffffffffff), max_size = __UINT64_C(0); + int i; + zbx_uint64_t counter; - zabbix_log(level, "=== memory statistics for %s ===", info->mem_descr); + stats->free_chunks = 0; + stats->max_chunk_size = __UINT64_C(0); + stats->min_chunk_size = __UINT64_C(0xffffffffffffffff); - for (index = 0; index < MEM_BUCKET_COUNT; index++) + for (i = 0; i < MEM_BUCKET_COUNT; i++) { counter = 0; - chunk = info->buckets[index]; + chunk = info->buckets[i]; while (NULL != chunk) { counter++; - min_size = MIN(min_size, CHUNK_SIZE(chunk)); - max_size = MAX(max_size, CHUNK_SIZE(chunk)); + stats->min_chunk_size = MIN(stats->min_chunk_size, CHUNK_SIZE(chunk)); + stats->max_chunk_size = MAX(stats->max_chunk_size, CHUNK_SIZE(chunk)); chunk = mem_get_next_chunk(chunk); } - if (counter > 0) - { - total_free += counter; - zabbix_log(level, "free chunks of size %2s %3d bytes: %8llu", - index == MEM_BUCKET_COUNT - 1 ? ">=" : "", - MEM_MIN_BUCKET_SIZE + 8 * index, (unsigned long long)counter); - } + stats->free_chunks += counter; + stats->chunks_num[i] = counter; + } + + stats->used_chunks = (info->total_size - info->used_size - info->free_size) / (2 * MEM_SIZE_FIELD) + 1 - + stats->free_chunks; + stats->free_size = info->free_size; + stats->used_size = info->used_size; +} + +void zbx_mem_dump_stats(int level, zbx_mem_info_t *info) +{ + zbx_mem_stats_t stats; + int i; + + zbx_mem_get_stats(info, &stats); + + zabbix_log(level, "=== memory statistics for %s ===", info->mem_descr); + + for (i = 0; i < MEM_BUCKET_COUNT; i++) + { + if (0 == stats.chunks_num[i]) + continue; + + zabbix_log(level, "free chunks of size %2s %3d bytes: %8u", i == MEM_BUCKET_COUNT - 1 ? ">=" : "", + MEM_MIN_BUCKET_SIZE + 8 * i, stats.chunks_num[i]); } - zabbix_log(level, "min chunk size: %10llu bytes", (unsigned long long)min_size); - zabbix_log(level, "max chunk size: %10llu bytes", (unsigned long long)max_size); + zabbix_log(level, "min chunk size: %10llu bytes", (unsigned long long)stats.min_chunk_size); + zabbix_log(level, "max chunk size: %10llu bytes", (unsigned long long)stats.max_chunk_size); - total = (info->total_size - info->used_size - info->free_size) / (2 * MEM_SIZE_FIELD) + 1; zabbix_log(level, "memory of total size %llu bytes fragmented into %llu chunks", - (unsigned long long)info->total_size, (unsigned long long)total); + (unsigned long long)stats.free_size + stats.used_size, + (unsigned long long)stats.free_chunks + stats.used_chunks); zabbix_log(level, "of those, %10llu bytes are in %8llu free chunks", - (unsigned long long)info->free_size, (unsigned long long)total_free); + (unsigned long long)stats.free_size, (unsigned long long)stats.free_chunks); zabbix_log(level, "of those, %10llu bytes are in %8llu used chunks", - (unsigned long long)info->used_size, (unsigned long long)(total - total_free)); + (unsigned long long)stats.used_size, (unsigned long long)stats.used_chunks); zabbix_log(level, "================================"); } diff --git a/src/libs/zbxnix/control.c b/src/libs/zbxnix/control.c index cfcba5e5189..8515edf074b 100644 --- a/src/libs/zbxnix/control.c +++ b/src/libs/zbxnix/control.c @@ -18,6 +18,7 @@ **/ #include "control.h" +#include "zbxdiag.h" static int parse_log_level_options(const char *opt, size_t len, unsigned int *scope, unsigned int *data) { @@ -167,6 +168,47 @@ int parse_rtc_options(const char *opt, unsigned char program_type, int *message) return FAIL; #endif } + else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER | ZBX_PROGRAM_TYPE_PROXY)) && + 0 == strncmp(opt, ZBX_DIAGINFO, ZBX_CONST_STRLEN(ZBX_DIAGINFO))) + { + command = ZBX_RTC_DIAGINFO; + data = 0; + scope = ZBX_DIAGINFO_ALL; + + if ('=' == opt[ZBX_CONST_STRLEN(ZBX_DIAGINFO)]) + { + const char *section = opt + ZBX_CONST_STRLEN(ZBX_DIAGINFO) + 1; + + if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE)) + { + scope = ZBX_DIAGINFO_HISTORYCACHE; + } + else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING)) + { + scope = ZBX_DIAGINFO_PREPROCESSING; + } + else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER))) + { + if (0 == strcmp(section, ZBX_DIAG_VALUECACHE)) + scope = ZBX_DIAGINFO_VALUECACHE; + else if (0 == strcmp(section, ZBX_DIAG_LLD)) + scope = ZBX_DIAGINFO_LLD; + else if (0 == strcmp(section, ZBX_DIAG_ALERTING)) + scope = ZBX_DIAGINFO_ALERTING; + } + + if (0 == scope) + { + zbx_error("invalid diaginfo section: %s", section); + return FAIL; + } + } + else if ('\0' != opt[ZBX_CONST_STRLEN(ZBX_DIAGINFO)]) + { + zbx_error("invalid runtime control option: %s", opt); + return FAIL; + } + } else { zbx_error("invalid runtime control option: %s", opt); diff --git a/src/libs/zbxnix/daemon.c b/src/libs/zbxnix/daemon.c index 1899b96d960..3b59c35204d 100644 --- a/src/libs/zbxnix/daemon.c +++ b/src/libs/zbxnix/daemon.c @@ -241,6 +241,9 @@ static void user1_signal_handler(int sig, siginfo_t *siginfo, void *context) zbx_signal_process_by_type(ZBX_PROCESS_TYPE_DISCOVERER, ZBX_RTC_GET_DATA(flags), flags); zbx_signal_process_by_type(ZBX_PROCESS_TYPE_TASKMANAGER, ZBX_RTC_GET_DATA(flags), flags); break; + default: + if (NULL != zbx_sigusr_handler) + zbx_sigusr_handler(flags); } #endif } diff --git a/src/libs/zbxtasks/task.c b/src/libs/zbxtasks/task.c index 67699d6cdf9..7bccb94520b 100644 --- a/src/libs/zbxtasks/task.c +++ b/src/libs/zbxtasks/task.c @@ -1313,4 +1313,3 @@ int zbx_tm_execute_task_data(const char *data, int len, zbx_uint64_t proxy_hosti return zbx_tm_task_result_wait(taskid, info); } - diff --git a/src/zabbix_proxy/Makefile.am b/src/zabbix_proxy/Makefile.am index adb892d825e..ba37775bf7c 100644 --- a/src/zabbix_proxy/Makefile.am +++ b/src/zabbix_proxy/Makefile.am @@ -71,6 +71,7 @@ zabbix_proxy_LDADD = \ $(top_builddir)/src/libs/zbxdb/libzbxdb.a \ $(top_builddir)/src/libs/zbxmodules/libzbxmodules.a \ $(top_builddir)/src/libs/zbxtasks/libzbxtasks.a \ + $(top_builddir)/src/libs/zbxdiag/libzbxdiag_proxy.a \ $(top_builddir)/src/libs/zbxcompress/libzbxcompress.a \ $(top_builddir)/src/libs/zbxembed/libzbxembed.a \ $(top_builddir)/src/libs/zbxprometheus/libzbxprometheus.a \ diff --git a/src/zabbix_proxy/proxy.c b/src/zabbix_proxy/proxy.c index 0dc22497c14..892c31d846b 100644 --- a/src/zabbix_proxy/proxy.c +++ b/src/zabbix_proxy/proxy.c @@ -58,6 +58,7 @@ #include "zbxipcservice.h" #include "../zabbix_server/preprocessor/preproc_manager.h" #include "../zabbix_server/preprocessor/preproc_worker.h" +#include "zbxdiag.h" #ifdef HAVE_OPENIPMI @@ -296,6 +297,8 @@ char *CONFIG_STATS_ALLOWED_IP = NULL; int CONFIG_DOUBLE_PRECISION = ZBX_DB_DBL_PRECISION_DISABLED; +volatile sig_atomic_t zbx_diaginfo_scope = ZBX_DIAGINFO_UNDEFINED; + int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num); int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num) @@ -960,6 +963,19 @@ int main(int argc, char **argv) return daemon_start(CONFIG_ALLOW_ROOT, CONFIG_USER, t.flags); } +static void zbx_main_sigusr_handler(int flags) +{ + if (ZBX_RTC_DIAGINFO == ZBX_RTC_GET_MSG(flags)) + { + int scope = ZBX_RTC_GET_SCOPE(flags); + + if (ZBX_DIAGINFO_ALL == scope) + zbx_diaginfo_scope = (1 << ZBX_DIAGINFO_HISTORYCACHE) | (1 << ZBX_DIAGINFO_PREPROCESSING); + else + zbx_diaginfo_scope = 1 << scope; + } +} + int MAIN_ZABBIX_ENTRY(int flags) { zbx_socket_t listen_sock; @@ -1238,6 +1254,8 @@ int MAIN_ZABBIX_ENTRY(int flags) } } + zbx_set_sigusr_handler(zbx_main_sigusr_handler); + while (-1 == wait(&i)) /* wait for any child to exit */ { if (EINTR != errno) @@ -1245,6 +1263,13 @@ int MAIN_ZABBIX_ENTRY(int flags) zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno)); break; } + + /* check if the wait was interrupted because of diaginfo remote command */ + if (ZBX_DIAGINFO_UNDEFINED != zbx_diaginfo_scope) + { + zbx_diag_log_info(zbx_diaginfo_scope); + zbx_diaginfo_scope = ZBX_DIAGINFO_UNDEFINED; + } } /* all exiting child processes should be caught by signal handlers */ diff --git a/src/zabbix_proxy/taskmanager/taskmanager.c b/src/zabbix_proxy/taskmanager/taskmanager.c index 4c9644b499b..63bd09ef080 100644 --- a/src/zabbix_proxy/taskmanager/taskmanager.c +++ b/src/zabbix_proxy/taskmanager/taskmanager.c @@ -25,6 +25,7 @@ #include "db.h" #include "dbcache.h" #include "zbxcrypto.h" +#include "zbxdiag.h" #include "../../zabbix_server/scripts/scripts.h" #include "taskmanager.h" @@ -214,6 +215,40 @@ static int tm_process_check_now(zbx_vector_uint64_t *taskids) /****************************************************************************** * * + * Function: tm_execute_data_json * + * * + * Purpose: process data task with json contents * + * * + * Return value: SUCCEED - the data task was executed * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int tm_execute_data_json(int type, const char *data, char **info) +{ + struct zbx_json_parse jp_data; + + if (SUCCEED != zbx_json_brackets_open(data, &jp_data)) + { + *info = zbx_strdup(*info, zbx_json_strerror()); + return FAIL; + } + + switch (type) + { + case ZBX_TM_DATA_TYPE_TEST_ITEM: + return zbx_trapper_item_test_run(&jp_data, 0, info); + case ZBX_TM_DATA_TYPE_DIAGINFO: + return zbx_diag_get_info(&jp_data, info); + } + + THIS_SHOULD_NEVER_HAPPEN; + + *info = zbx_strdup(*info, "Unknown task data type"); + return FAIL; +} + +/****************************************************************************** + * * * Function: tm_execute_data * * * * Purpose: process data task * @@ -227,10 +262,9 @@ static int tm_execute_data(zbx_uint64_t taskid, int clock, int ttl, int now) DB_ROW row; DB_RESULT result; zbx_tm_task_t *task = NULL; - int ret = FAIL; + int ret = FAIL, data_type; char *info = NULL; zbx_uint64_t parent_taskid; - struct zbx_json_parse jp_data; result = DBselect("select parent_taskid,data,type" " from task_data" @@ -249,17 +283,18 @@ static int tm_execute_data(zbx_uint64_t taskid, int clock, int ttl, int now) goto finish; } - if (ZBX_TM_DATA_TYPE_TEST_ITEM != atoi(row[2])) + switch (data_type = atoi(row[2])) { - task->data = zbx_tm_data_result_create(parent_taskid, FAIL, "Unknown task."); - goto finish; + case ZBX_TM_DATA_TYPE_TEST_ITEM: + ZBX_FALLTHROUGH; + case ZBX_TM_DATA_TYPE_DIAGINFO: + ret = tm_execute_data_json(data_type, row[1], &info); + break; + default: + task->data = zbx_tm_data_result_create(parent_taskid, FAIL, "Unknown task."); + goto finish; } - if (SUCCEED != (ret = zbx_json_brackets_open(row[1], &jp_data))) - info = zbx_strdup(NULL, zbx_json_strerror()); - else - ret = zbx_trapper_item_test_run(&jp_data, 0, &info); - task->data = zbx_tm_data_result_create(parent_taskid, ret, info); zbx_free(info); diff --git a/src/zabbix_server/Makefile.am b/src/zabbix_server/Makefile.am index 3d0018e9c46..5fcdfdd7cc6 100644 --- a/src/zabbix_server/Makefile.am +++ b/src/zabbix_server/Makefile.am @@ -97,6 +97,7 @@ zabbix_server_LDADD = \ $(top_builddir)/src/libs/zbxdb/libzbxdb.a \ $(top_builddir)/src/libs/zbxmodules/libzbxmodules.a \ $(top_builddir)/src/libs/zbxtasks/libzbxtasks.a \ + $(top_builddir)/src/libs/zbxdiag/libzbxdiag_server.a \ $(top_builddir)/src/libs/zbxcompress/libzbxcompress.a \ $(top_builddir)/src/libs/zbxserver/libzbxserver_server.a diff --git a/src/zabbix_server/alerter/alert_manager.c b/src/zabbix_server/alerter/alert_manager.c index 6947efff6d8..5cbe4d93cd7 100644 --- a/src/zabbix_server/alerter/alert_manager.c +++ b/src/zabbix_server/alerter/alert_manager.c @@ -30,6 +30,7 @@ #include "zbxmedia.h" #include "zbxembed.h" #include "zbxserialize.h" +#include "zbxalert.h" #define ZBX_AM_LOCATION_NOWHERE 0 #define ZBX_AM_LOCATION_QUEUE 1 @@ -45,6 +46,7 @@ #define ALERT_SOURCE_EXTERNAL 0xffff #define ZBX_ALERTPOOL_SOURCE(id) (id >> 48) +#define ZBX_ALERTPOOL_OBJECT(id) ((id >> 32) & 0xffff) #define ZBX_AM_MEDIATYPE_FLAG_NONE 0x00 #define ZBX_AM_MEDIATYPE_FLAG_REMOVE 0x01 @@ -113,6 +115,8 @@ typedef struct char *params; int status; int retries; + + int objectid; } zbx_am_alert_t; @@ -129,6 +133,8 @@ typedef struct zbx_binary_heap_t queue; int location; + + /* the number of currently processing alerts */ int alerts_num; /* the number of alert objects for this alert pool */ @@ -136,49 +142,6 @@ typedef struct } zbx_am_alertpool_t; -/* media type data */ -typedef struct -{ - zbx_uint64_t mediatypeid; - - int location; - int alerts_num; - - /* the number of alert objects for this media type */ - int refcount; - - /* alert pool queue */ - zbx_binary_heap_t queue; - - /* media type data */ - int type; - char *smtp_server; - char *smtp_helo; - char *smtp_email; - char *exec_path; - char *gsm_modem; - char *username; - char *passwd; - char *exec_params; - char *script; - char *script_bin; - char *error; - unsigned short smtp_port; - unsigned char smtp_security; - unsigned char smtp_verify_peer; - unsigned char smtp_verify_host; - unsigned char smtp_authentication; - - int maxsessions; - int maxattempts; - int attempt_interval; - int timeout; - int script_bin_sz; - unsigned char content_type; - unsigned char flags; -} -zbx_am_mediatype_t; - /* alerter data */ typedef struct { @@ -192,6 +155,9 @@ zbx_am_alerter_t; /* alert manager data */ typedef struct { + /* number of queued alerts */ + zbx_uint64_t alerts_num; + /* alerter vector, created during manager initialization */ zbx_vector_ptr_t alerters; zbx_queue_ptr_t free_alerters; @@ -723,6 +689,7 @@ static zbx_am_alert_t *am_create_alert(zbx_uint64_t alertid, zbx_uint64_t mediat alert->alertid = alertid; alert->mediatypeid = mediatypeid; alert->alertpoolid = am_calc_alertpoolid(source, object, objectid); + alert->objectid = objectid; if (NULL != sendto) alert->sendto = zbx_strdup(NULL, sendto); @@ -773,6 +740,7 @@ static zbx_am_alert_t *am_copy_db_alert(zbx_am_db_alert_t *db_alert) alert->alertid = db_alert->alertid; alert->mediatypeid = db_alert->mediatypeid; alert->alertpoolid = am_calc_alertpoolid(db_alert->source, db_alert->object, db_alert->objectid); + alert->objectid = db_alert->objectid; alert->eventid = db_alert->eventid; alert->p_eventid = db_alert->p_eventid; @@ -790,7 +758,6 @@ static zbx_am_alert_t *am_copy_db_alert(zbx_am_db_alert_t *db_alert) return alert; } - /****************************************************************************** * * * Function: am_alert_free * @@ -893,6 +860,8 @@ static void am_remove_alert(zbx_am_t *manager, zbx_am_alert_t *alert) } am_alert_free(alert); + + manager->alerts_num--; } /****************************************************************************** @@ -1156,6 +1125,7 @@ static int am_init(zbx_am_t *manager, char **error) if (FAIL == (ret = zbx_ipc_service_start(&manager->ipc, ZBX_IPC_SERVICE_ALERTER, error))) goto out; + manager->alerts_num = 0; zbx_vector_ptr_create(&manager->alerters); zbx_queue_ptr_create(&manager->free_alerters); zbx_hashset_create(&manager->alerters_client, 0, alerter_hash_func, alerter_compare_func); @@ -1733,6 +1703,8 @@ static int am_queue_alert(zbx_am_t *manager, zbx_am_alert_t *alert, int now) am_push_alertpool(mediatype, alertpool); am_push_mediatype(manager, mediatype); + manager->alerts_num++; + return SUCCEED; } @@ -1951,6 +1923,180 @@ static void am_remove_unused_mediatypes(zbx_am_t *manager) } } +/****************************************************************************** + * * + * Function: am_process_diag_stats * + * * + * Purpose: process diagnostic statistics request * + * * + ******************************************************************************/ +static void am_process_diag_stats(zbx_am_t *manager, zbx_ipc_client_t *client) +{ + unsigned char *data; + zbx_uint32_t data_len; + + data_len = zbx_alerter_serialize_diag_stats(&data, manager->alerts_num); + zbx_ipc_client_send(client, ZBX_IPC_ALERTER_DIAG_STATS_RESULT, data, data_len); + zbx_free(data); +} + +/****************************************************************************** + * * + * Function: am_compare_mediatype_by_alerts_desc * + * * + * Purpose: compare mediatypes by total queued alerts * + * * + ******************************************************************************/ +static int am_compare_mediatype_by_alerts_desc(const void *d1, const void *d2) +{ + zbx_am_mediatype_t *m1 = *(zbx_am_mediatype_t **)d1; + zbx_am_mediatype_t *m2 = *(zbx_am_mediatype_t **)d2; + + return m2->refcount - m1->refcount; +} + +/****************************************************************************** + * * + * Function: am_process_diag_top_mediatypes * + * * + * Purpose: processes top mediatypes by queued alerts * + * * + * Parameters: manager - [IN] the manager * + * client - [IN] the connected worker IPC client data * + * message - [IN] the received message * + * * + ******************************************************************************/ +static void am_process_diag_top_mediatypes(zbx_am_t *manager, zbx_ipc_client_t *client, + const zbx_ipc_message_t *message) +{ + int limit; + unsigned char *data; + zbx_uint32_t data_len; + + zbx_vector_ptr_t view; + zbx_hashset_iter_t iter; + zbx_am_mediatype_t *mediatype; + int mediatypes_num; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_alerter_deserialize_top_request(message->data, &limit); + + zbx_vector_ptr_create(&view); + + zbx_hashset_iter_reset(&manager->mediatypes, &iter); + while (NULL != (mediatype = (zbx_am_mediatype_t *)zbx_hashset_iter_next(&iter))) + { + if (0 != mediatype->refcount) + zbx_vector_ptr_append(&view, mediatype); + } + + zbx_vector_ptr_sort(&view, am_compare_mediatype_by_alerts_desc); + mediatypes_num = MIN(limit, view.values_num); + + data_len = zbx_alerter_serialize_top_mediatypes_result(&data, (zbx_am_mediatype_t **)view.values, mediatypes_num); + zbx_ipc_client_send(client, ZBX_IPC_ALERTER_DIAG_TOP_MEDIATYPES_RESULT, data, data_len); + zbx_free(data); + + zbx_vector_ptr_destroy(&view); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/* alert source hashset support */ + +static zbx_hash_t am_source_hash_func(const void *data) +{ + const zbx_am_source_stats_t *source = (const zbx_am_source_stats_t *)data; + + zbx_hash_t hash; + zbx_uint64_t source_object; + + source_object = (zbx_uint64_t)source->source << 32 | source->object; + hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&source_object); + hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&source->objectid, sizeof(source->objectid), hash); + + return hash; +} + +static int am_source_compare_func(const void *d1, const void *d2) +{ + const zbx_am_source_stats_t *s1 = (const zbx_am_source_stats_t *)d1; + const zbx_am_source_stats_t *s2 = (const zbx_am_source_stats_t *)d2; + + ZBX_RETURN_IF_NOT_EQUAL(s1->source, s2->source); + ZBX_RETURN_IF_NOT_EQUAL(s1->object, s2->object); + ZBX_RETURN_IF_NOT_EQUAL(s1->objectid, s2->objectid); + + return 0; +} +/****************************************************************************** + * * + * Function: am_process_diag_top_sources * + * * + * Purpose: processes top alert sources by queued alerts * + * * + * Parameters: manager - [IN] the manager * + * client - [IN] the connected worker IPC client data * + * message - [IN] the received message * + * * + ******************************************************************************/ +static void am_process_diag_top_sources(zbx_am_t *manager, zbx_ipc_client_t *client, + const zbx_ipc_message_t *message) +{ + int limit; + unsigned char *data; + zbx_uint32_t data_len; + + zbx_vector_ptr_t view; + zbx_am_alertpool_t *alertpool; + zbx_am_alert_t *alert; + int i, sources_num; + zbx_hashset_t sources; + zbx_hashset_iter_t iter; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_alerter_deserialize_top_request(message->data, &limit); + + zbx_hashset_create(&sources, 1024, am_source_hash_func, am_source_compare_func); + zbx_vector_ptr_create(&view); + + zbx_hashset_iter_reset(&manager->alertpools, &iter); + while (NULL != (alertpool = (zbx_am_alertpool_t *)zbx_hashset_iter_next(&iter))) + { + for (i = 0; i < alertpool->queue.elems_num; i++) + { + zbx_am_source_stats_t *source, source_local; + + alert = (zbx_am_alert_t *)alertpool->queue.elems[i].data; + source_local.source = ZBX_ALERTPOOL_SOURCE(alert->alertpoolid); + source_local.object = ZBX_ALERTPOOL_OBJECT(alert->alertpoolid); + source_local.objectid = alert->objectid; + + if (NULL == (source = zbx_hashset_search(&sources, &source_local))) + { + source = zbx_hashset_insert(&sources, &source_local, sizeof(source_local)); + source->alerts_num = 0; + zbx_vector_ptr_append(&view, source); + } + source->alerts_num++; + } + } + + zbx_vector_ptr_sort(&view, am_compare_mediatype_by_alerts_desc); + sources_num = MIN(limit, view.values_num); + + data_len = zbx_alerter_serialize_top_sources_result(&data, (zbx_am_source_stats_t **)view.values, sources_num); + zbx_ipc_client_send(client, ZBX_IPC_ALERTER_DIAG_TOP_SOURCES_RESULT, data, data_len); + zbx_free(data); + + zbx_vector_ptr_destroy(&view); + zbx_hashset_destroy(&sources); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + ZBX_THREAD_ENTRY(alert_manager_thread, args) { #define STAT_INTERVAL 5 /* if a process is busy and does not sleep then update status not faster than */ @@ -2089,6 +2235,15 @@ ZBX_THREAD_ENTRY(alert_manager_thread, args) case ZBX_IPC_ALERTER_DROP_MEDIATYPES: am_drop_mediatypes(&manager, message); break; + case ZBX_IPC_ALERTER_DIAG_STATS: + am_process_diag_stats(&manager, client); + break; + case ZBX_IPC_ALERTER_DIAG_TOP_MEDIATYPES: + am_process_diag_top_mediatypes(&manager, client, message); + break; + case ZBX_IPC_ALERTER_DIAG_TOP_SOURCES: + am_process_diag_top_sources(&manager, client, message); + break; } zbx_ipc_message_free(message); diff --git a/src/zabbix_server/alerter/alerter_protocol.c b/src/zabbix_server/alerter/alerter_protocol.c index c80ed560834..8783613024e 100644 --- a/src/zabbix_server/alerter/alerter_protocol.c +++ b/src/zabbix_server/alerter/alerter_protocol.c @@ -18,9 +18,11 @@ **/ #include "common.h" - #include "log.h" #include "zbxserialize.h" +#include "zbxalgo.h" +#include "zbxipcservice.h" +#include "zbxalert.h" #include "alerter_protocol.h" @@ -730,3 +732,280 @@ void zbx_alerter_deserialize_ids(const unsigned char *data, zbx_uint64_t **ids, for (i = 0; i < *ids_num; i++) data += zbx_deserialize_value(data, &(*ids)[i]); } + +/****************************************************************************** + * * + * Function: zbx_alerter_serialize_diag_stats * + * * + ******************************************************************************/ +zbx_uint32_t zbx_alerter_serialize_diag_stats(unsigned char **data, zbx_uint64_t alerts_num) +{ + zbx_uint32_t data_len = 0; + + zbx_serialize_prepare_value(data_len, alerts_num); + *data = (unsigned char *)zbx_malloc(NULL, data_len); + (void)zbx_serialize_value(*data, alerts_num); + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_alerter_deserialize_diag_stats * + * * + ******************************************************************************/ +static void zbx_alerter_deserialize_diag_stats(const unsigned char *data, zbx_uint64_t *alerts_num) +{ + (void)zbx_deserialize_value(data, alerts_num); +} + +/****************************************************************************** + * * + * Function: zbx_alerter_serialize_top_request * + * * + ******************************************************************************/ +static zbx_uint32_t zbx_alerter_serialize_top_request(unsigned char **data, int limit) +{ + zbx_uint32_t len; + + *data = (unsigned char *)zbx_malloc(NULL, sizeof(limit)); + len = zbx_serialize_value(*data, limit); + + return len; +} + +/****************************************************************************** + * * + * Function: zbx_alerter_deserialize_top_request * + * * + ******************************************************************************/ +void zbx_alerter_deserialize_top_request(const unsigned char *data, int *limit) +{ + (void)zbx_deserialize_value(data, limit); +} + +/****************************************************************************** + * * + * Function: zbx_alerter_serialize_top_mediatypes_result * + * * + ******************************************************************************/ +zbx_uint32_t zbx_alerter_serialize_top_mediatypes_result(unsigned char **data, zbx_am_mediatype_t **mediatypes, + int mediatypes_num) +{ + unsigned char *ptr; + zbx_uint32_t data_len = 0, mediatype_len = 0; + int i; + + if (0 != mediatypes_num) + { + zbx_serialize_prepare_value(mediatype_len, mediatypes[0]->mediatypeid); + zbx_serialize_prepare_value(mediatype_len, mediatypes[0]->refcount); + } + + zbx_serialize_prepare_value(data_len, mediatypes_num); + data_len += mediatype_len * mediatypes_num; + *data = (unsigned char *)zbx_malloc(NULL, data_len); + + ptr = *data; + ptr += zbx_serialize_value(ptr, mediatypes_num); + + for (i = 0; i < mediatypes_num; i++) + { + ptr += zbx_serialize_value(ptr, mediatypes[0]->mediatypeid); + ptr += zbx_serialize_value(ptr, mediatypes[0]->refcount); + } + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_alerter_deserialize_top_mediatypes_result * + * * + ******************************************************************************/ +static void zbx_alerter_deserialize_top_mediatypes_result(const unsigned char *data, + zbx_vector_uint64_pair_t *mediatypes) +{ + int i, mediatypes_num; + + data += zbx_deserialize_value(data, &mediatypes_num); + + if (0 != mediatypes_num) + { + zbx_vector_uint64_pair_reserve(mediatypes, mediatypes_num); + + for (i = 0; i < mediatypes_num; i++) + { + zbx_uint64_pair_t pair; + int value; + + data += zbx_deserialize_value(data, &pair.first); + data += zbx_deserialize_value(data, &value); + pair.second = value; + zbx_vector_uint64_pair_append_ptr(mediatypes, &pair); + } + } +} + +/****************************************************************************** + * * + * Function: zbx_alerter_serialize_top_sources_result * + * * + ******************************************************************************/ +zbx_uint32_t zbx_alerter_serialize_top_sources_result(unsigned char **data, zbx_am_source_stats_t **sources, + int sources_num) +{ + unsigned char *ptr; + zbx_uint32_t data_len = 0, source_len = 0; + int i; + + if (0 != sources_num) + { + zbx_serialize_prepare_value(source_len, sources[0]->source); + zbx_serialize_prepare_value(source_len, sources[0]->object); + zbx_serialize_prepare_value(source_len, sources[0]->objectid); + zbx_serialize_prepare_value(source_len, sources[0]->alerts_num); + } + + zbx_serialize_prepare_value(data_len, sources_num); + data_len += source_len * sources_num; + *data = (unsigned char *)zbx_malloc(NULL, data_len); + + ptr = *data; + ptr += zbx_serialize_value(ptr, sources_num); + + for (i = 0; i < sources_num; i++) + { + ptr += zbx_serialize_value(ptr, sources[i]->source); + ptr += zbx_serialize_value(ptr, sources[i]->object); + ptr += zbx_serialize_value(ptr, sources[i]->objectid); + ptr += zbx_serialize_value(ptr, sources[i]->alerts_num); + } + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_alerter_deserialize_top_sources_result * + * * + ******************************************************************************/ +static void zbx_alerter_deserialize_top_sources_result(const unsigned char *data, zbx_vector_ptr_t *sources) +{ + int i, sources_num; + + data += zbx_deserialize_value(data, &sources_num); + + if (0 != sources_num) + { + zbx_vector_ptr_reserve(sources, sources_num); + + for (i = 0; i < sources_num; i++) + { + zbx_am_source_stats_t *source;; + + source = (zbx_am_source_stats_t *)zbx_malloc(NULL, sizeof(zbx_am_source_stats_t)); + data += zbx_deserialize_value(data, &source->source); + data += zbx_deserialize_value(data, &source->object); + data += zbx_deserialize_value(data, &source->objectid); + data += zbx_deserialize_value(data, &source->alerts_num); + zbx_vector_ptr_append(sources, source); + } + } +} + +/****************************************************************************** + * * + * Function: zbx_alerter_get_diag_stats * + * * + * Purpose: get alerter manager diagnostic statistics * + * * + ******************************************************************************/ +int zbx_alerter_get_diag_stats(zbx_uint64_t *alerts_num, char **error) +{ + unsigned char *result; + + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_ALERTER, ZBX_IPC_ALERTER_DIAG_STATS, SEC_PER_MIN, NULL, 0, + &result, error)) + { + return FAIL; + } + + zbx_alerter_deserialize_diag_stats(result, alerts_num); + zbx_free(result); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_alerter_get_top_mediatypes * + * * + * Purpose: get the top N mediatypes by the number of queued alerts * + * * + * Parameters limit - [IN] the number of top records to retrieve * + * mediatypes - [OUT] a vector of top mediatypeid,alerts_num pairs * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - the top n mediatypes were returned successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_alerter_get_top_mediatypes(int limit, zbx_vector_uint64_pair_t *mediatypes, char **error) +{ + int ret; + unsigned char *data, *result; + zbx_uint32_t data_len; + + data_len = zbx_alerter_serialize_top_request(&data, limit); + + if (SUCCEED != (ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_ALERTER, ZBX_IPC_ALERTER_DIAG_TOP_MEDIATYPES, + SEC_PER_MIN, data, data_len, &result, error))) + { + goto out; + } + + zbx_alerter_deserialize_top_mediatypes_result(result, mediatypes); + zbx_free(result); +out: + zbx_free(data); + + return ret; +} + +/****************************************************************************** + * * + * Function: zbx_alerter_get_top_sources * + * * + * Purpose: get the top N sources by the number of queued alerts * + * * + * Parameters limit - [IN] the number of top records to retrieve * + * sources - [OUT] a vector of top zbx_alerter_source_stats_t * + * structure * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - the top n sources were returned successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_alerter_get_top_sources(int limit, zbx_vector_ptr_t *sources, char **error) +{ + int ret; + unsigned char *data, *result; + zbx_uint32_t data_len; + + data_len = zbx_alerter_serialize_top_request(&data, limit); + + if (SUCCEED != (ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_ALERTER, ZBX_IPC_ALERTER_DIAG_TOP_SOURCES, + SEC_PER_MIN, data, data_len, &result, error))) + { + goto out; + } + + zbx_alerter_deserialize_top_sources_result(result, sources); + zbx_free(result); +out: + zbx_free(data); + + return ret; +} diff --git a/src/zabbix_server/alerter/alerter_protocol.h b/src/zabbix_server/alerter/alerter_protocol.h index 1dc369fd908..04d722ec7ba 100644 --- a/src/zabbix_server/alerter/alerter_protocol.h +++ b/src/zabbix_server/alerter/alerter_protocol.h @@ -21,6 +21,8 @@ #define ZABBIX_ALERTER_PROTOCOL_H #include "common.h" +#include "zbxalgo.h" +#include "zbxalert.h" #define ZBX_IPC_SERVICE_ALERTER "alerter" @@ -40,10 +42,65 @@ #define ZBX_IPC_ALERTER_EXEC 1104 #define ZBX_IPC_ALERTER_WEBHOOK 1105 +/* process -> manager */ +#define ZBX_IPC_ALERTER_DIAG_STATS 1200 +#define ZBX_IPC_ALERTER_DIAG_TOP_MEDIATYPES 1201 +#define ZBX_IPC_ALERTER_DIAG_TOP_SOURCES 1202 + +/* manager -> process */ +#define ZBX_IPC_ALERTER_DIAG_STATS_RESULT 1300 +#define ZBX_IPC_ALERTER_DIAG_TOP_MEDIATYPES_RESULT 1301 +#define ZBX_IPC_ALERTER_DIAG_TOP_SOURCES_RESULT 1302 + #define ZBX_WATCHDOG_ALERT_FREQUENCY (15 * SEC_PER_MIN) #define ZBX_ALERT_NO_DEBUG 0 #define ZBX_ALERT_DEBUG 1 +/* media type data */ +typedef struct +{ + zbx_uint64_t mediatypeid; + + int location; + + /* the number of currently processing alerts */ + int alerts_num; + + /* the number of alert objects for this media type */ + int refcount; + + /* alert pool queue */ + zbx_binary_heap_t queue; + + /* media type data */ + int type; + char *smtp_server; + char *smtp_helo; + char *smtp_email; + char *exec_path; + char *gsm_modem; + char *username; + char *passwd; + char *exec_params; + char *script; + char *script_bin; + char *error; + unsigned short smtp_port; + unsigned char smtp_security; + unsigned char smtp_verify_peer; + unsigned char smtp_verify_host; + unsigned char smtp_authentication; + + int maxsessions; + int maxattempts; + int attempt_interval; + int timeout; + int script_bin_sz; + unsigned char content_type; + unsigned char flags; +} +zbx_am_mediatype_t; + typedef struct { zbx_uint64_t mediaid; @@ -195,4 +252,14 @@ zbx_uint32_t zbx_alerter_serialize_ids(unsigned char **data, zbx_uint64_t *ids, void zbx_alerter_deserialize_ids(const unsigned char *data, zbx_uint64_t **ids, int *ids_num); +void zbx_alerter_deserialize_top_request(const unsigned char *data, int *limit); + +zbx_uint32_t zbx_alerter_serialize_diag_stats(unsigned char **data, zbx_uint64_t alerts_num); + +zbx_uint32_t zbx_alerter_serialize_top_mediatypes_result(unsigned char **data, zbx_am_mediatype_t **mediatypes, + int mediatypes_num); + +zbx_uint32_t zbx_alerter_serialize_top_sources_result(unsigned char **data, zbx_am_source_stats_t **sources, + int sources_num); + #endif diff --git a/src/zabbix_server/lld/lld_manager.c b/src/zabbix_server/lld/lld_manager.c index 1388f8d9a57..5dd8bc2c0d1 100644 --- a/src/zabbix_server/lld/lld_manager.c +++ b/src/zabbix_server/lld/lld_manager.c @@ -46,34 +46,6 @@ extern int CONFIG_LLDWORKER_FORKS; * */ -typedef struct zbx_lld_value -{ - char *value; - char *error; - zbx_timespec_t ts; - - zbx_uint64_t lastlogsize; - int mtime; - unsigned char meta; - - struct zbx_lld_value *next; -} -zbx_lld_data_t; - -/* queue of values for one LLD rule */ -typedef struct -{ - /* the LLD rule id */ - zbx_uint64_t itemid; - - /* the oldest value in queue */ - zbx_lld_data_t *tail; - - /* the newest value in queue */ - zbx_lld_data_t *head; -} -zbx_lld_rule_t; - typedef struct { /* workers vector, created during manager initialization */ @@ -361,7 +333,7 @@ static void lld_queue_request(zbx_lld_manager_t *manager, const zbx_ipc_message_ if (NULL == (rule = zbx_hashset_search(&manager->rule_index, &itemid))) { - zbx_lld_rule_t rule_local = {itemid, data, data}; + zbx_lld_rule_t rule_local = {itemid, 0, data, data}; rule = zbx_hashset_insert(&manager->rule_index, &rule_local, sizeof(rule_local)); lld_queue_rule(manager, rule); @@ -372,6 +344,7 @@ static void lld_queue_request(zbx_lld_manager_t *manager, const zbx_ipc_message_ rule->tail = data; } + rule->values_num++; manager->queued_num++; zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); @@ -456,9 +429,14 @@ static void lld_process_result(zbx_lld_manager_t *manager, zbx_ipc_client_t *cli rule->head = rule->head->next; if (NULL == rule->head) + { zbx_hashset_remove_direct(&manager->rule_index, rule); + } else + { + rule->values_num--; lld_queue_rule(manager, rule); + } lld_data_free(data); @@ -472,6 +450,86 @@ static void lld_process_result(zbx_lld_manager_t *manager, zbx_ipc_client_t *cli /****************************************************************************** * * + * Function: lld_process_diag_stats * + * * + * Purpose: processes external diagnostic statistics request * + * * + * Parameters: manager - [IN] the LLD manager * + * Parameters: client - [IN] the external IPC connection * + * * + ******************************************************************************/ +static void lld_process_diag_stats(zbx_lld_manager_t *manager, zbx_ipc_client_t *client) +{ + unsigned char *data; + zbx_uint32_t data_len; + + data_len = zbx_lld_serialize_diag_stats(&data, manager->rule_index.num_data, manager->queued_num); + zbx_ipc_client_send(client, ZBX_IPC_LLD_DIAG_STATS_RESULT, data, data_len); + zbx_free(data); +} + +/****************************************************************************** + * * + * Function: lld_diag_item_compare_values_desc * + * * + * Purpose: sort lld manager cache item view by second value * + * (number of values) in descending order * + * * + ******************************************************************************/ +static int lld_diag_item_compare_values_desc(const void *d1, const void *d2) +{ + zbx_lld_rule_t *r1 = *(zbx_lld_rule_t **)d1; + zbx_lld_rule_t *r2 = *(zbx_lld_rule_t **)d2; + + return r2->values_num - r1->values_num; +} + +/****************************************************************************** + * * + * Function: lld_process_diag_top * + * * + * Purpose: processes external top items request * + * * + * Parameters: manager - [IN] the manager * + * client - [IN] the connected worker IPC client data * + * message - [IN] the received message * + * * + ******************************************************************************/ +static void lld_process_top_items(zbx_lld_manager_t *manager, zbx_ipc_client_t *client, + const zbx_ipc_message_t *message) +{ + int limit; + unsigned char *data; + zbx_uint32_t data_len; + zbx_vector_ptr_t view; + zbx_hashset_iter_t iter; + zbx_lld_rule_t *item; + int items_num; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_lld_deserialize_top_items_request(message->data, &limit); + + zbx_vector_ptr_create(&view); + + zbx_hashset_iter_reset(&manager->rule_index, &iter); + while (NULL != (item = (zbx_lld_rule_t *)zbx_hashset_iter_next(&iter))) + zbx_vector_ptr_append(&view, item); + + zbx_vector_ptr_sort(&view, lld_diag_item_compare_values_desc); + items_num = MIN(limit, view.values_num); + + data_len = zbx_lld_serialize_top_items_result(&data, (zbx_lld_rule_t **)view.values, items_num); + zbx_ipc_client_send(client, ZBX_IPC_LLD_TOP_ITEMS_RESULT, data, data_len); + + zbx_free(data); + zbx_vector_ptr_destroy(&view); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * * Function: lld_manager_thread * * * * Purpose: main processing loop * @@ -556,6 +614,12 @@ ZBX_THREAD_ENTRY(lld_manager_thread, args) zbx_ipc_client_send(client, message->code, (unsigned char *)&manager.queued_num, sizeof(zbx_uint64_t)); break; + case ZBX_IPC_LLD_DIAG_STATS: + lld_process_diag_stats(&manager, client); + break; + case ZBX_IPC_LLD_TOP_ITEMS: + lld_process_top_items(&manager, client, message); + break; } zbx_ipc_message_free(message); diff --git a/src/zabbix_server/lld/lld_manager.h b/src/zabbix_server/lld/lld_manager.h index 6acdee61af4..f6aa9383e60 100644 --- a/src/zabbix_server/lld/lld_manager.h +++ b/src/zabbix_server/lld/lld_manager.h @@ -22,6 +22,37 @@ #include "threads.h" +typedef struct zbx_lld_value +{ + char *value; + char *error; + zbx_timespec_t ts; + + zbx_uint64_t lastlogsize; + int mtime; + unsigned char meta; + + struct zbx_lld_value *next; +} +zbx_lld_data_t; + +/* queue of values for one LLD rule */ +typedef struct +{ + /* the LLD rule id */ + zbx_uint64_t itemid; + + /* the number of queued values */ + int values_num; + + /* the oldest value in queue */ + zbx_lld_data_t *tail; + + /* the newest value in queue */ + zbx_lld_data_t *head; +} +zbx_lld_rule_t; + ZBX_THREAD_ENTRY(lld_manager_thread, args); #endif diff --git a/src/zabbix_server/lld/lld_protocol.c b/src/zabbix_server/lld/lld_protocol.c index 4eba5f2603e..20b2b6098c2 100644 --- a/src/zabbix_server/lld/lld_protocol.c +++ b/src/zabbix_server/lld/lld_protocol.c @@ -24,6 +24,7 @@ #include "lld_protocol.h" #include "sysinfo.h" #include "zbxlld.h" +#include "lld_manager.h" /****************************************************************************** * * @@ -89,6 +90,127 @@ void zbx_lld_deserialize_item_value(const unsigned char *data, zbx_uint64_t *ite /****************************************************************************** * * + * Function: zbx_lld_serialize_diag_stats * + * * + ******************************************************************************/ +zbx_uint32_t zbx_lld_serialize_diag_stats(unsigned char **data, zbx_uint64_t items_num, zbx_uint64_t values_num) +{ + unsigned char *ptr; + zbx_uint32_t data_len = 0; + + zbx_serialize_prepare_value(data_len, items_num); + zbx_serialize_prepare_value(data_len, values_num); + + *data = (unsigned char *)zbx_malloc(NULL, data_len); + + ptr = *data; + ptr += zbx_serialize_value(ptr, items_num); + (void)zbx_serialize_value(ptr, values_num); + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_lld_deserialize_diag_stats * + * * + ******************************************************************************/ +static void zbx_lld_deserialize_diag_stats(const unsigned char *data, zbx_uint64_t *items_num, zbx_uint64_t *values_num) +{ + data += zbx_deserialize_value(data, items_num); + (void)zbx_deserialize_value(data, values_num); +} + + +/****************************************************************************** + * * + * Function: zbx_lld_serialize_top_request * + * * + ******************************************************************************/ +static zbx_uint32_t zbx_lld_serialize_top_items_request(unsigned char **data, int limit) +{ + zbx_uint32_t data_len = 0; + + zbx_serialize_prepare_value(data_len, limit); + *data = (unsigned char *)zbx_malloc(NULL, data_len); + (void)zbx_serialize_value(*data, limit); + + return data_len; +} + +/****************************************************************************** + * * + * Function: lld_deserialize_top_request * + * * + ******************************************************************************/ +void zbx_lld_deserialize_top_items_request(const unsigned char *data, int *limit) +{ + (void)zbx_deserialize_value(data, limit); +} + +/****************************************************************************** + * * + * Function: zbx_lld_serialize_top_items_result * + * * + ******************************************************************************/ +zbx_uint32_t zbx_lld_serialize_top_items_result(unsigned char **data, zbx_lld_rule_t **items, int items_num) +{ + unsigned char *ptr; + zbx_uint32_t data_len = 0, item_len = 0; + int i; + + if (0 != items_num) + { + zbx_serialize_prepare_value(item_len, items[0]->itemid); + zbx_serialize_prepare_value(item_len, items[0]->values_num); + } + + zbx_serialize_prepare_value(data_len, items_num); + data_len += item_len * items_num; + *data = (unsigned char *)zbx_malloc(NULL, data_len); + + ptr = *data; + ptr += zbx_serialize_value(ptr, items_num); + + for (i = 0; i < items_num; i++) + { + ptr += zbx_serialize_value(ptr, items[i]->itemid); + ptr += zbx_serialize_value(ptr, items[i]->values_num); + } + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_lld_deserialize_top_result * + * * + ******************************************************************************/ +static void zbx_lld_deserialize_top_items_result(const unsigned char *data, zbx_vector_uint64_pair_t *items) +{ + int i, items_num; + + data += zbx_deserialize_value(data, &items_num); + + if (0 != items_num) + { + zbx_vector_uint64_pair_reserve(items, items_num); + + for (i = 0; i < items_num; i++) + { + zbx_uint64_pair_t pair; + int value; + + data += zbx_deserialize_value(data, &pair.first); + data += zbx_deserialize_value(data, &value); + pair.second = value; + zbx_vector_uint64_pair_append_ptr(items, &pair); + } + } +} + +/****************************************************************************** + * * * Function: zbx_lld_process_value * * * * Purpose: process low level discovery value/error * @@ -205,3 +327,63 @@ out: return ret; } + +/****************************************************************************** + * * + * Function: zbx_lld_get_diag_stats * + * * + * Purpose: get lld manager diagnostic statistics * + * * + ******************************************************************************/ +int zbx_lld_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num, char **error) +{ + unsigned char *result; + + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_LLD, ZBX_IPC_LLD_DIAG_STATS, SEC_PER_MIN, NULL, 0, + &result, error)) + { + return FAIL; + } + + zbx_lld_deserialize_diag_stats(result, items_num, values_num); + zbx_free(result); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_lld_get_top_items * + * * + * Purpose: get the top N items by the number of queued values * + * * + * Parameters field - [IN] the sort field * + * limit - [IN] the number of top records to retrieve * + * items - [OUT] a vector of top itemid, values_num pairs * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - the top n items were returned successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_lld_get_top_items(int limit, zbx_vector_uint64_pair_t *items, char **error) +{ + int ret; + unsigned char *data, *result; + zbx_uint32_t data_len; + + data_len = zbx_lld_serialize_top_items_request(&data, limit); + + if (SUCCEED != (ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_LLD, ZBX_IPC_LLD_TOP_ITEMS, SEC_PER_MIN, data, + data_len, &result, error))) + { + goto out; + } + + zbx_lld_deserialize_top_items_result(result, items); + zbx_free(result); +out: + zbx_free(data); + + return ret; +} diff --git a/src/zabbix_server/lld/lld_protocol.h b/src/zabbix_server/lld/lld_protocol.h index 93f54db4e85..0fa3a8aebe2 100644 --- a/src/zabbix_server/lld/lld_protocol.h +++ b/src/zabbix_server/lld/lld_protocol.h @@ -21,26 +21,46 @@ #define ZABBIX_LLD_PROTOCOL_H #include "common.h" +#include "lld_manager.h" #define ZBX_IPC_SERVICE_LLD "lld" -/* LLD -> manager */ +/* poller -> manager */ #define ZBX_IPC_LLD_REGISTER 1000 #define ZBX_IPC_LLD_DONE 1001 -/* manager -> LLD */ +/* manager -> poller */ #define ZBX_IPC_LLD_TASK 1100 -/* manager -> LLD */ +/* manager -> poller */ #define ZBX_IPC_LLD_REQUEST 1200 -/* poller -> LLD */ +/* poller -> poller */ #define ZBX_IPC_LLD_QUEUE 1300 +/* process -> manager */ +#define ZBX_IPC_LLD_DIAG_STATS 1400 + +/* manager -> process */ +#define ZBX_IPC_LLD_DIAG_STATS_RESULT 1401 + +/* process -> manager */ +#define ZBX_IPC_LLD_TOP_ITEMS 1402 + +/* manager -> process */ +#define ZBX_IPC_LLD_TOP_ITEMS_RESULT 1403 + + zbx_uint32_t zbx_lld_serialize_item_value(unsigned char **data, zbx_uint64_t itemid, const char *value, const zbx_timespec_t *ts, unsigned char meta, zbx_uint64_t lastlogsize, int mtime, const char *error); void zbx_lld_deserialize_item_value(const unsigned char *data, zbx_uint64_t *itemid, char **value, zbx_timespec_t *ts, unsigned char *meta, zbx_uint64_t *lastlogsize, int *mtime, char **error); +zbx_uint32_t zbx_lld_serialize_diag_stats(unsigned char **data, zbx_uint64_t items_num, zbx_uint64_t values_num); + +void zbx_lld_deserialize_top_items_request(const unsigned char *data, int *limit); + +zbx_uint32_t zbx_lld_serialize_top_items_result(unsigned char **data, zbx_lld_rule_t **items, int items_num); + #endif diff --git a/src/zabbix_server/preprocessor/preproc_manager.c b/src/zabbix_server/preprocessor/preproc_manager.c index 8eb31b25dc2..198e651fdf6 100644 --- a/src/zabbix_server/preprocessor/preproc_manager.c +++ b/src/zabbix_server/preprocessor/preproc_manager.c @@ -131,8 +131,9 @@ static void preproc_item_clear(zbx_preproc_item_t *item) static void request_free_steps(zbx_preprocessing_request_t *request) { - while (0 < request->steps_num--) + while (0 < request->steps_num) { + request->steps_num--; zbx_free(request->steps[request->steps_num].params); zbx_free(request->steps[request->steps_num].error_handler_params); } @@ -1080,6 +1081,108 @@ static void preprocessor_flush_test_result(zbx_preprocessing_manager_t *manager, /****************************************************************************** * * + * Function: preprocessor_get_diag_stats * + * * + * Purpose: return diagnostic statistics * + * * + * Parameters: manager - [IN] preprocessing manager * + * client - [IN] IPC client * + * * + ******************************************************************************/ +static void preprocessor_get_diag_stats(zbx_preprocessing_manager_t *manager, zbx_ipc_client_t *client) +{ + unsigned char *data; + zbx_uint32_t data_len; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + data_len = zbx_preprocessor_pack_diag_stats(&data, manager->queued_num, manager->preproc_num); + zbx_ipc_client_send(client, ZBX_IPC_PREPROCESSOR_DIAG_STATS_RESULT, data, data_len); + zbx_free(data); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Function: preproc_sort_item_by_values_desc * + * * + * Purpose: compare item statistics by value * + * * + ******************************************************************************/ +static int preproc_sort_item_by_values_desc(const void *d1, const void *d2) +{ + zbx_preproc_item_stats_t *i1 = *(zbx_preproc_item_stats_t **)d1; + zbx_preproc_item_stats_t *i2 = *(zbx_preproc_item_stats_t **)d2; + + return i2->values_num - i1->values_num; +} + +/****************************************************************************** + * * + * Function: preprocessor_get_top_items * + * * + * Purpose: return diagnostic top view * + * * + * Parameters: manager - [IN] preprocessing manager * + * client - [IN] IPC client * + * message - [IN] the message with request * + * * + ******************************************************************************/ +static void preprocessor_get_top_items(zbx_preprocessing_manager_t *manager, zbx_ipc_client_t *client, + zbx_ipc_message_t *message) +{ + int limit; + unsigned char *data; + zbx_uint32_t data_len; + zbx_hashset_t items; + zbx_vector_ptr_t view; + zbx_list_iterator_t iterator; + zbx_preprocessing_request_t *request; + zbx_preproc_item_stats_t *item; + int items_num; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_preprocessor_unpack_top_request(&limit, message->data); + + zbx_hashset_create(&items, 1024, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_ptr_create(&view); + + zbx_list_iterator_init(&manager->queue, &iterator); + while (SUCCEED == zbx_list_iterator_next(&iterator)) + { + zbx_list_iterator_peek(&iterator, (void **)&request); + + if (NULL == (item = zbx_hashset_search(&items, &request->value.itemid))) + { + zbx_preproc_item_stats_t item_local = {.itemid = request->value.itemid}; + + item = zbx_hashset_insert(&items, &item_local, sizeof(item_local)); + zbx_vector_ptr_append(&view, item); + } + /* There might be processed, but not yet flushed items at the start of queue with */ + /* freed preprocessing steps and steps_num being zero. Because of that keep updating */ + /* items steps_num to have preprocessing steps of last queued item. */ + item->steps_num = request->steps_num; + item->values_num++; + } + + zbx_vector_ptr_sort(&view, preproc_sort_item_by_values_desc); + items_num = MIN(limit, view.values_num); + + data_len = zbx_preprocessor_pack_top_items_result(&data, (zbx_preproc_item_stats_t **)view.values, items_num); + zbx_ipc_client_send(client, ZBX_IPC_PREPROCESSOR_TOP_ITEMS_RESULT, data, data_len); + zbx_free(data); + + zbx_vector_ptr_destroy(&view); + zbx_hashset_destroy(&items); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * * Function: preprocessor_init_manager * * * * Purpose: initializes preprocessing manager * @@ -1269,6 +1372,12 @@ ZBX_THREAD_ENTRY(preprocessing_manager_thread, args) case ZBX_IPC_PREPROCESSOR_TEST_RESULT: preprocessor_flush_test_result(&manager, client, message); break; + case ZBX_IPC_PREPROCESSOR_DIAG_STATS: + preprocessor_get_diag_stats(&manager, client); + break; + case ZBX_IPC_PREPROCESSOR_TOP_ITEMS: + preprocessor_get_top_items(&manager, client, message); + break; } zbx_ipc_message_free(message); diff --git a/src/zabbix_server/preprocessor/preproc_worker.c b/src/zabbix_server/preprocessor/preproc_worker.c index 114d428456f..9447b8cec16 100644 --- a/src/zabbix_server/preprocessor/preproc_worker.c +++ b/src/zabbix_server/preprocessor/preproc_worker.c @@ -326,7 +326,7 @@ static void worker_preprocess_value(zbx_ipc_socket_t *socket, zbx_ipc_message_t result = (SUCCEED == ret ? zbx_variant_value_desc(&value) : error); zabbix_log(LOG_LEVEL_DEBUG, "%s(): %s", __func__, zbx_variant_value_desc(&value_start)); - zabbix_log(LOG_LEVEL_DEBUG, "%s: %s %s",__func__, zbx_result_string(ret), result); + zabbix_log(LOG_LEVEL_DEBUG, "%s: %s %s",__func__, zbx_result_string(ret), result); } size = zbx_preprocessor_pack_result(&data, &value, &history_out, error); diff --git a/src/zabbix_server/preprocessor/preprocessing.c b/src/zabbix_server/preprocessor/preprocessing.c index 6e4241aa6fe..5679d43c180 100644 --- a/src/zabbix_server/preprocessor/preprocessing.c +++ b/src/zabbix_server/preprocessor/preprocessing.c @@ -599,6 +599,100 @@ zbx_uint32_t zbx_preprocessor_pack_test_result(unsigned char **data, const zbx_p /****************************************************************************** * * + * Function: zbx_preprocessor_pack_diag_stats * + * * + * Purpose: pack diagnostic statistics data into a single buffer that can be * + * used in IPC * + * Parameters: data - [OUT] memory buffer for packed data * + * values_num - [IN] the number of queued values * + * values_preproc_num - [IN] the number of queued values with * + * preprocessing steps * + * data - [IN] IPC data buffer * + * * + ******************************************************************************/ +zbx_uint32_t zbx_preprocessor_pack_diag_stats(unsigned char **data, int values_num, int values_preproc_num) +{ + unsigned char *ptr; + zbx_uint32_t data_len = 0; + + zbx_serialize_prepare_value(data_len, values_num); + zbx_serialize_prepare_value(data_len, values_preproc_num); + + *data = (unsigned char *)zbx_malloc(NULL, data_len); + + ptr = *data; + ptr += zbx_serialize_value(ptr, values_num); + (void)zbx_serialize_value(ptr, values_preproc_num); + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_preprocessor_pack_top_request * + * * + * Purpose: pack top request data into a single buffer that can be used in IPC* + * * + * Parameters: data - [OUT] memory buffer for packed data * + * field - [IN] the sort field * + * limit - [IN] the number of top values to return * + * * + ******************************************************************************/ +zbx_uint32_t zbx_preprocessor_pack_top_items_request(unsigned char **data, int limit) +{ + zbx_uint32_t data_len = 0; + + zbx_serialize_prepare_value(data_len, limit); + *data = (unsigned char *)zbx_malloc(NULL, data_len); + (void)zbx_serialize_value(*data, limit); + + return data_len; +} + +/****************************************************************************** + * * + * Function: zbx_preprocessor_pack_top_result * + * * + * Purpose: pack top result data into a single buffer that can be used in IPC * + * * + * Parameters: data - [OUT] memory buffer for packed data * + * items - [IN] the array of item references * + * items_num - [IN] the number of items * + * * + ******************************************************************************/ +zbx_uint32_t zbx_preprocessor_pack_top_items_result(unsigned char **data, zbx_preproc_item_stats_t **items, + int items_num) +{ + unsigned char *ptr; + zbx_uint32_t data_len = 0, item_len = 0; + int i; + + if (0 != items_num) + { + zbx_serialize_prepare_value(item_len, items[0]->itemid); + zbx_serialize_prepare_value(item_len, items[0]->values_num); + zbx_serialize_prepare_value(item_len, items[0]->steps_num); + } + + zbx_serialize_prepare_value(data_len, items_num); + data_len += item_len * items_num; + *data = (unsigned char *)zbx_malloc(NULL, data_len); + + ptr = *data; + ptr += zbx_serialize_value(ptr, items_num); + + for (i = 0; i < items_num; i++) + { + ptr += zbx_serialize_value(ptr, items[i]->itemid); + ptr += zbx_serialize_value(ptr, items[i]->values_num); + ptr += zbx_serialize_value(ptr, items[i]->steps_num); + } + + return data_len; +} + +/****************************************************************************** + * * * Function: zbx_preprocessor_unpack_value * * * * Purpose: unpack item value data from IPC data buffer * @@ -774,6 +868,75 @@ void zbx_preprocessor_unpack_test_result(zbx_vector_ptr_t *results, zbx_vector_p (void)zbx_deserialize_str(offset, error, value_len); } + +/****************************************************************************** + * * + * Function: zbx_preprocessor_unpack_diag_stats * + * * + * Purpose: unpack preprocessing test data from IPC data buffer * + * * + * Parameters: values_num - [OUT] the number of queued values * + * values_preproc_num - [OUT] the number of queued values with * + * preprocessing steps * + * data - [IN] IPC data buffer * + * * + ******************************************************************************/ +void zbx_preprocessor_unpack_diag_stats(int *values_num, int *values_preproc_num, const unsigned char *data) +{ + const unsigned char *offset = data; + + offset += zbx_deserialize_int(offset, values_num); + (void)zbx_deserialize_int(offset, values_preproc_num); +} + +/****************************************************************************** + * * + * Function: zbx_preprocessor_unpack_top_request * + * * + * Purpose: unpack preprocessing test data from IPC data buffer * + * * + * Parameters: data - [OUT] memory buffer for packed data * + * limit - [IN] the number of top values to return * + * * + ******************************************************************************/ +void zbx_preprocessor_unpack_top_request(int *limit, const unsigned char *data) +{ + (void)zbx_deserialize_value(data, limit); +} + +/****************************************************************************** + * * + * Function: zbx_preprocessor_unpack_top_request * + * * + * Purpose: unpack preprocessing test data from IPC data buffer * + * * + * Parameters: items - [OUT] the item diag data * + * data - [IN] memory buffer for packed data * + * * + ******************************************************************************/ +void zbx_preprocessor_unpack_top_result(zbx_vector_ptr_t *items, const unsigned char *data) +{ + int i, items_num; + + data += zbx_deserialize_value(data, &items_num); + + if (0 != items_num) + { + zbx_vector_ptr_reserve(items, items_num); + + for (i = 0; i < items_num; i++) + { + zbx_preproc_item_stats_t *item; + + item = (zbx_preproc_item_stats_t *)zbx_malloc(NULL, sizeof(zbx_preproc_item_stats_t)); + data += zbx_deserialize_value(data, &item->itemid); + data += zbx_deserialize_value(data, &item->values_num); + data += zbx_deserialize_value(data, &item->steps_num); + zbx_vector_ptr_append(items, item); + } + } +} + /****************************************************************************** * * * Function: preprocessor_send * @@ -1030,3 +1193,54 @@ out: return ret; } +/****************************************************************************** + * * + * Function: zbx_preprocessor_get_diag_stats * + * * + * Purpose: get preprocessing manager diagnostic statistics * + * * + ******************************************************************************/ +int zbx_preprocessor_get_diag_stats(int *values_num, int *values_preproc_num, char **error) +{ + unsigned char *result; + + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_PREPROCESSING, ZBX_IPC_PREPROCESSOR_DIAG_STATS, + SEC_PER_MIN, NULL, 0, &result, error)) + { + return FAIL; + } + + zbx_preprocessor_unpack_diag_stats(values_num, values_preproc_num, result); + zbx_free(result); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_preprocessor_get_top_items * + * * + * Purpose: get the top N items by the number of queued values * + * * + ******************************************************************************/ +int zbx_preprocessor_get_top_items(int limit, zbx_vector_ptr_t *items, char **error) +{ + int ret; + unsigned char *data, *result; + zbx_uint32_t data_len; + + data_len = zbx_preprocessor_pack_top_items_request(&data, limit); + + if (SUCCEED != (ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_PREPROCESSING, ZBX_IPC_PREPROCESSOR_TOP_ITEMS, + SEC_PER_MIN, data, data_len, &result, error))) + { + goto out; + } + + zbx_preprocessor_unpack_top_result(items, result); + zbx_free(result); +out: + zbx_free(data); + + return ret; +} diff --git a/src/zabbix_server/preprocessor/preprocessing.h b/src/zabbix_server/preprocessor/preprocessing.h index 4067117f05c..d4957a46a03 100644 --- a/src/zabbix_server/preprocessor/preprocessing.h +++ b/src/zabbix_server/preprocessor/preprocessing.h @@ -34,6 +34,10 @@ #define ZBX_IPC_PREPROCESSOR_QUEUE 4 #define ZBX_IPC_PREPROCESSOR_TEST_REQUEST 5 #define ZBX_IPC_PREPROCESSOR_TEST_RESULT 6 +#define ZBX_IPC_PREPROCESSOR_DIAG_STATS 7 +#define ZBX_IPC_PREPROCESSOR_DIAG_STATS_RESULT 8 +#define ZBX_IPC_PREPROCESSOR_TOP_ITEMS 9 +#define ZBX_IPC_PREPROCESSOR_TOP_ITEMS_RESULT 10 typedef struct { AGENT_RESULT *result; @@ -75,4 +79,17 @@ zbx_uint32_t zbx_preprocessor_pack_test_result(unsigned char **data, const zbx_p void zbx_preprocessor_unpack_test_result(zbx_vector_ptr_t *results, zbx_vector_ptr_t *history, char **error, const unsigned char *data); +zbx_uint32_t zbx_preprocessor_pack_diag_stats(unsigned char **data, int values_num, int values_preproc_num); + +void zbx_preprocessor_unpack_diag_stats(int *values_num, int *values_preproc_num, const unsigned char *data); + +zbx_uint32_t zbx_preprocessor_pack_top_items_request(unsigned char **data, int limit); + +void zbx_preprocessor_unpack_top_request(int *limit, const unsigned char *data); + +zbx_uint32_t zbx_preprocessor_pack_top_items_result(unsigned char **data, zbx_preproc_item_stats_t **items, + int items_num); + +void zbx_preprocessor_unpack_top_result(zbx_vector_ptr_t *items, const unsigned char *data); + #endif /* ZABBIX_PREPROCESSING_H */ diff --git a/src/zabbix_server/server.c b/src/zabbix_server/server.c index 15e01aad6ef..a90725d7e6f 100644 --- a/src/zabbix_server/server.c +++ b/src/zabbix_server/server.c @@ -71,6 +71,7 @@ #include "zbxhistory.h" #include "postinit.h" #include "export.h" +#include "zbxdiag.h" #ifdef HAVE_OPENIPMI #include "ipmi/ipmi_manager.h" @@ -307,6 +308,8 @@ char *CONFIG_STATS_ALLOWED_IP = NULL; int CONFIG_DOUBLE_PRECISION = ZBX_DB_DBL_PRECISION_DISABLED; +volatile sig_atomic_t zbx_diaginfo_scope = ZBX_DIAGINFO_UNDEFINED; + int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num); int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num) @@ -951,6 +954,24 @@ int main(int argc, char **argv) return daemon_start(CONFIG_ALLOW_ROOT, CONFIG_USER, t.flags); } +static void zbx_main_sigusr_handler(int flags) +{ + if (ZBX_RTC_DIAGINFO == ZBX_RTC_GET_MSG(flags)) + { + int scope = ZBX_RTC_GET_SCOPE(flags); + + if (ZBX_DIAGINFO_ALL == scope) + { + zbx_diaginfo_scope = (1 << ZBX_DIAGINFO_HISTORYCACHE) | (1 << ZBX_DIAGINFO_VALUECACHE) | + (1 << ZBX_DIAGINFO_PREPROCESSING) | (1 << ZBX_DIAGINFO_LLD) | + (1 << ZBX_DIAGINFO_ALERTING); + } + else + zbx_diaginfo_scope = 1 << scope; + } + +} + int MAIN_ZABBIX_ENTRY(int flags) { zbx_socket_t listen_sock; @@ -1295,6 +1316,8 @@ int MAIN_ZABBIX_ENTRY(int flags) zbx_problems_export_init("main-process", 0); } + zbx_set_sigusr_handler(zbx_main_sigusr_handler); + while (-1 == wait(&i)) /* wait for any child to exit */ { if (EINTR != errno) @@ -1302,6 +1325,13 @@ int MAIN_ZABBIX_ENTRY(int flags) zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno)); break; } + + /* check if the wait was interrupted because of diaginfo remote command */ + if (ZBX_DIAGINFO_UNDEFINED != zbx_diaginfo_scope) + { + zbx_diag_log_info(zbx_diaginfo_scope); + zbx_diaginfo_scope = ZBX_DIAGINFO_UNDEFINED; + } } /* all exiting child processes should be caught by signal handlers */ diff --git a/src/zabbix_server/taskmanager/taskmanager.c b/src/zabbix_server/taskmanager/taskmanager.c index 7585f14efd0..4ea13b9df30 100644 --- a/src/zabbix_server/taskmanager/taskmanager.c +++ b/src/zabbix_server/taskmanager/taskmanager.c @@ -28,6 +28,7 @@ #include "../actions.h" #include "export.h" #include "taskmanager.h" +#include "zbxdiag.h" #define ZBX_TM_PROCESS_PERIOD 5 #define ZBX_TM_CLEANUP_PERIOD SEC_PER_HOUR @@ -173,26 +174,6 @@ static void tm_expire_remote_command(zbx_uint64_t taskid) /****************************************************************************** * * - * Function: tm_expire_data * - * * - * Purpose: process expired data task * - * * - ******************************************************************************/ -static void tm_expire_data(zbx_uint64_t taskid) -{ - zabbix_log(LOG_LEVEL_DEBUG, "In %s() taskid:" ZBX_FS_UI64, __func__, taskid); - - DBbegin(); - - DBexecute("update task set status=%d where taskid=" ZBX_FS_UI64, ZBX_TM_STATUS_EXPIRED, taskid); - - DBcommit(); - - zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); -} - -/****************************************************************************** - * * * Function: tm_process_remote_command_result * * * * Purpose: process remote command result task * @@ -533,6 +514,114 @@ static int tm_process_check_now(zbx_vector_uint64_t *taskids) /****************************************************************************** * * + * Function: tm_process_diaginfo * + * * + * Purpose: process diaginfo task * + * * + ******************************************************************************/ +static void tm_process_diaginfo(zbx_uint64_t taskid, const char *data) +{ + zbx_tm_task_t *task; + int ret; + char *info = NULL; + struct zbx_json_parse jp_data; + + task = zbx_tm_task_create(0, ZBX_TM_TASK_DATA_RESULT, ZBX_TM_STATUS_NEW, time(NULL), 0, 0); + + if (SUCCEED == zbx_json_open(data, &jp_data)) + { + ret = zbx_diag_get_info(&jp_data, &info); + task->data = zbx_tm_data_result_create(taskid, ret, info); + zbx_free(info); + } + else + task->data = zbx_tm_data_result_create(taskid, FAIL, zbx_json_strerror()); + + zbx_tm_save_task(task); + zbx_tm_task_free(task); +} + +/****************************************************************************** + * * + * Function: tm_process_data * + * * + * Purpose: process data tasks * + * * + * Return value: The number of successfully processed tasks * + * * + ******************************************************************************/ +static int tm_process_data(zbx_vector_uint64_t *taskids) +{ + DB_ROW row; + DB_RESULT result; + int processed_num = 0, data_type; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t done_taskids; + zbx_uint64_t taskid; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() tasks_num:%d", __func__, taskids->values_num); + + DBbegin(); + + zbx_vector_uint64_create(&done_taskids); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select t.taskid,td.type,td.data" + " from task t" + " left join task_data td" + " on t.taskid=td.taskid" + " where t.proxy_hostid is null" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.taskid", taskids->values, taskids->values_num); + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(taskid, row[0]); + + if (SUCCEED == DBis_null(row[1])) + { + zbx_vector_uint64_append(&done_taskids, taskid); + continue; + } + + data_type = atoi(row[1]); + + switch (data_type) + { + case ZBX_TM_DATA_TYPE_DIAGINFO: + tm_process_diaginfo(taskid, row[2]); + zbx_vector_uint64_append(&done_taskids, taskid); + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + } + DBfree_result(result); + + if (0 != (processed_num = done_taskids.values_num)) + { + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update task set status=%d where", + ZBX_TM_STATUS_DONE); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "taskid", done_taskids.values, + done_taskids.values_num); + DBexecute("%s", sql); + } + + zbx_free(sql); + zbx_vector_uint64_destroy(&done_taskids); + + DBcommit(); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s() processed:%d", __func__, processed_num); + + return processed_num; +} + +/****************************************************************************** + * * * Function: tm_expire_generic_tasks * * * * Purpose: expires tasks that don't require specific expiration handling * @@ -548,6 +637,7 @@ static int tm_expire_generic_tasks(zbx_vector_uint64_t *taskids) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update task set status=%d where", ZBX_TM_STATUS_EXPIRED); DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "taskid", taskids->values, taskids->values_num); DBexecute("%s", sql); + zbx_free(sql); return taskids->values_num; } @@ -567,11 +657,12 @@ static int tm_process_tasks(int now) DB_RESULT result; int type, processed_num = 0, expired_num = 0, clock, ttl; zbx_uint64_t taskid; - zbx_vector_uint64_t ack_taskids, check_now_taskids, expire_taskids; + zbx_vector_uint64_t ack_taskids, check_now_taskids, expire_taskids, data_taskids; zbx_vector_uint64_create(&ack_taskids); zbx_vector_uint64_create(&check_now_taskids); zbx_vector_uint64_create(&expire_taskids); + zbx_vector_uint64_create(&data_taskids); result = DBselect("select taskid,type,clock,ttl" " from task" @@ -618,10 +709,9 @@ static int tm_process_tasks(int now) case ZBX_TM_TASK_DATA: /* both - 'new' and 'in progress' tasks should expire */ if (0 != ttl && clock + ttl < now) - { - tm_expire_data(taskid); - expired_num++; - } + zbx_vector_uint64_append(&expire_taskids, taskid); + else + zbx_vector_uint64_append(&data_taskids, taskid); break; case ZBX_TM_TASK_DATA_RESULT: tm_process_data_result(taskid); @@ -641,9 +731,13 @@ static int tm_process_tasks(int now) if (0 < check_now_taskids.values_num) processed_num += tm_process_check_now(&check_now_taskids); + if (0 < data_taskids.values_num) + processed_num += tm_process_data(&data_taskids); + if (0 < expire_taskids.values_num) expired_num += tm_expire_generic_tasks(&expire_taskids); + zbx_vector_uint64_destroy(&data_taskids); zbx_vector_uint64_destroy(&expire_taskids); zbx_vector_uint64_destroy(&check_now_taskids); zbx_vector_uint64_destroy(&ack_taskids); |