Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-61671
-rw-r--r--configure.ac1
-rw-r--r--include/common.h2
-rw-r--r--include/dbcache.h7
-rw-r--r--include/memalloc.h19
-rw-r--r--include/preproc.h12
-rw-r--r--include/zbxalert.h40
-rw-r--r--include/zbxdiag.h48
-rw-r--r--include/zbxjson.h3
-rw-r--r--include/zbxlld.h5
-rw-r--r--include/zbxserver.h2
-rw-r--r--include/zbxtasks.h3
-rw-r--r--man/zabbix_proxy.man10
-rw-r--r--man/zabbix_server.man7
-rw-r--r--src/libs/Makefile.am10
-rw-r--r--src/libs/zbxdbcache/dbcache.c67
-rw-r--r--src/libs/zbxdbcache/valuecache.c110
-rw-r--r--src/libs/zbxdbcache/valuecache.h14
-rw-r--r--src/libs/zbxdiag/Makefile.am11
-rw-r--r--src/libs/zbxdiag/diag.c867
-rw-r--r--src/libs/zbxdiag/diag.h88
-rw-r--r--src/libs/zbxdiag/diag_proxy.c53
-rw-r--r--src/libs/zbxdiag/diag_server.c540
-rw-r--r--src/libs/zbxjson/json.h1
-rw-r--r--src/libs/zbxmemory/memalloc.c70
-rw-r--r--src/libs/zbxnix/control.c42
-rw-r--r--src/libs/zbxnix/daemon.c3
-rw-r--r--src/libs/zbxtasks/task.c1
-rw-r--r--src/zabbix_proxy/Makefile.am1
-rw-r--r--src/zabbix_proxy/proxy.c25
-rw-r--r--src/zabbix_proxy/taskmanager/taskmanager.c55
-rw-r--r--src/zabbix_server/Makefile.am1
-rw-r--r--src/zabbix_server/alerter/alert_manager.c243
-rw-r--r--src/zabbix_server/alerter/alerter_protocol.c281
-rw-r--r--src/zabbix_server/alerter/alerter_protocol.h67
-rw-r--r--src/zabbix_server/lld/lld_manager.c122
-rw-r--r--src/zabbix_server/lld/lld_manager.h31
-rw-r--r--src/zabbix_server/lld/lld_protocol.c182
-rw-r--r--src/zabbix_server/lld/lld_protocol.h28
-rw-r--r--src/zabbix_server/preprocessor/preproc_manager.c111
-rw-r--r--src/zabbix_server/preprocessor/preproc_worker.c2
-rw-r--r--src/zabbix_server/preprocessor/preprocessing.c214
-rw-r--r--src/zabbix_server/preprocessor/preprocessing.h17
-rw-r--r--src/zabbix_server/server.c30
-rw-r--r--src/zabbix_server/taskmanager/taskmanager.c144
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);