1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "zbxalgo.h"
22 #include "memalloc.h"
23 #include "../../libs/zbxdbcache/valuecache.h"
24 #include "zbxlld.h"
25 #include "zbxalert.h"
26 #include "zbxdiag.h"
27 
28 #include "diag.h"
29 
30 /******************************************************************************
31  *                                                                            *
32  * Function: diag_historycache_item_compare_values                            *
33  *                                                                            *
34  * Purpose: sort itemid,values_num pair by values_num in descending order     *
35  *                                                                            *
36  ******************************************************************************/
diag_valuecache_item_compare_values(const void * d1,const void * d2)37 static int	diag_valuecache_item_compare_values(const void *d1, const void *d2)
38 {
39 	zbx_vc_item_stats_t	*i1 = *(zbx_vc_item_stats_t **)d1;
40 	zbx_vc_item_stats_t	*i2 = *(zbx_vc_item_stats_t **)d2;
41 
42 	return i2->values_num - i1->values_num;
43 }
44 
45 /******************************************************************************
46  *                                                                            *
47  * Function: diag_valuecache_item_compare_hourly                              *
48  *                                                                            *
49  * Purpose: sort itemid,values_num pair by hourly_num in descending order     *
50  *                                                                            *
51  ******************************************************************************/
diag_valuecache_item_compare_hourly(const void * d1,const void * d2)52 static int	diag_valuecache_item_compare_hourly(const void *d1, const void *d2)
53 {
54 	zbx_vc_item_stats_t	*i1 = *(zbx_vc_item_stats_t **)d1;
55 	zbx_vc_item_stats_t	*i2 = *(zbx_vc_item_stats_t **)d2;
56 
57 	return i2->hourly_num - i1->hourly_num;
58 }
59 
60 /******************************************************************************
61  *                                                                            *
62  * Function: diag_valuecache_add_items                                        *
63  *                                                                            *
64  * Purpose: add valuecache items diagnostic statistics to json                *
65  *                                                                            *
66  ******************************************************************************/
diag_valuecache_add_items(struct zbx_json * json,const char * field,zbx_vc_item_stats_t ** items,int items_num)67 static void	diag_valuecache_add_items(struct zbx_json *json, const char *field, zbx_vc_item_stats_t **items,
68 		int items_num)
69 {
70 	int	i;
71 
72 	zbx_json_addarray(json, field);
73 
74 	for (i = 0; i < items_num; i++)
75 	{
76 		zbx_json_addobject(json, NULL);
77 		zbx_json_addint64(json, "itemid", items[i]->itemid);
78 		zbx_json_addint64(json, "values", items[i]->values_num);
79 		zbx_json_addint64(json, "request.values", items[i]->hourly_num);
80 		zbx_json_close(json);
81 	}
82 	zbx_json_close(json);
83 }
84 
85 /******************************************************************************
86  *                                                                            *
87  * Function: diag_add_valuecache_info                                         *
88  *                                                                            *
89  * Purpose: add requested value cache diagnostic information to json data     *
90  *                                                                            *
91  * Parameters: jp    - [IN] the request                                       *
92  *             json  - [IN/OUT] the json to update                            *
93  *             error - [OUT] error message                                    *
94  *                                                                            *
95  * Return value: SUCCEED - the information was added successfully             *
96  *               FAIL    - otherwise                                          *
97  *                                                                            *
98  ******************************************************************************/
diag_add_valuecache_info(const struct zbx_json_parse * jp,struct zbx_json * json,char ** error)99 static int	diag_add_valuecache_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error)
100 {
101 	zbx_vector_ptr_t	tops;
102 	int			ret;
103 	double			time1, time2, time_total = 0;
104 	zbx_uint64_t		fields;
105 	zbx_diag_map_t		field_map[] = {
106 					{"", ZBX_DIAG_VALUECACHE_SIMPLE | ZBX_DIAG_VALUECACHE_MEMORY},
107 					{"items", ZBX_DIAG_VALUECACHE_ITEMS},
108 					{"values", ZBX_DIAG_VALUECACHE_VALUES},
109 					{"mode", ZBX_DIAG_VALUECACHE_MODE},
110 					{"memory", ZBX_DIAG_VALUECACHE_MEMORY},
111 					{NULL, 0}
112 					};
113 
114 	zbx_vector_ptr_create(&tops);
115 
116 	if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error)))
117 	{
118 		zbx_json_addobject(json, ZBX_DIAG_VALUECACHE);
119 
120 		if (0 != (fields & ZBX_DIAG_VALUECACHE_SIMPLE))
121 		{
122 			zbx_uint64_t	values_num, items_num;
123 			int		mode;
124 
125 			time1 = zbx_time();
126 			zbx_vc_get_diag_stats(&items_num, &values_num, &mode);
127 			time2 = zbx_time();
128 			time_total += time2 - time1;
129 
130 			if (0 != (fields & ZBX_DIAG_VALUECACHE_ITEMS))
131 				zbx_json_addint64(json, "items", items_num);
132 			if (0 != (fields & ZBX_DIAG_VALUECACHE_VALUES))
133 				zbx_json_addint64(json, "values", values_num);
134 			if (0 != (fields & ZBX_DIAG_VALUECACHE_MODE))
135 				zbx_json_addint64(json, "mode", mode);
136 		}
137 
138 		if (0 != (fields & ZBX_DIAG_VALUECACHE_MEMORY))
139 		{
140 			zbx_mem_stats_t	mem;
141 
142 			time1 = zbx_time();
143 			zbx_vc_get_mem_stats(&mem);
144 			time2 = zbx_time();
145 			time_total += time2 - time1;
146 
147 			diag_add_mem_stats(json, "memory", &mem);
148 		}
149 
150 		if (0 != tops.values_num)
151 		{
152 			zbx_vector_ptr_t	items;
153 			int			i;
154 
155 			zbx_vector_ptr_create(&items);
156 
157 			time1 = zbx_time();
158 			zbx_vc_get_item_stats(&items);
159 			time2 = zbx_time();
160 			time_total += time2 - time1;
161 
162 			zbx_json_addobject(json, "top");
163 
164 			for (i = 0; i < tops.values_num; i++)
165 			{
166 				zbx_diag_map_t	*map = (zbx_diag_map_t *)tops.values[i];
167 				int		limit;
168 
169 				if (0 == strcmp(map->name, "values"))
170 				{
171 					zbx_vector_ptr_sort(&items, diag_valuecache_item_compare_values);
172 				}
173 				else if (0 == strcmp(map->name, "request.values"))
174 				{
175 					zbx_vector_ptr_sort(&items, diag_valuecache_item_compare_hourly);
176 				}
177 				else
178 				{
179 					*error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name);
180 					ret = FAIL;
181 					goto out;
182 				}
183 
184 				limit = MIN((int)map->value, items.values_num);
185 				diag_valuecache_add_items(json, map->name, (zbx_vc_item_stats_t **)items.values, limit);
186 			}
187 			zbx_json_close(json);
188 
189 			zbx_vector_ptr_clear_ext(&items, zbx_ptr_free);
190 			zbx_vector_ptr_destroy(&items);
191 		}
192 
193 		zbx_json_addfloat(json, "time", time_total);
194 
195 		zbx_json_close(json);
196 	}
197 out:
198 	zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free);
199 	zbx_vector_ptr_destroy(&tops);
200 
201 	return ret;
202 }
203 
204 /******************************************************************************
205  *                                                                            *
206  * Function: diag_add_lld_items                                               *
207  *                                                                            *
208  * Purpose: add lld item top list to output json                              *
209  *                                                                            *
210  ******************************************************************************/
diag_add_lld_items(struct zbx_json * json,const char * field,const zbx_vector_uint64_pair_t * items)211 static void	diag_add_lld_items(struct zbx_json *json, const char *field, const zbx_vector_uint64_pair_t *items)
212 {
213 	int	i;
214 
215 	zbx_json_addarray(json, field);
216 
217 	for (i = 0; i < items->values_num; i++)
218 	{
219 		zbx_json_addobject(json, NULL);
220 		zbx_json_adduint64(json, "itemid", items->values[i].first);
221 		zbx_json_adduint64(json, "values", items->values[i].second);
222 		zbx_json_close(json);
223 	}
224 
225 	zbx_json_close(json);
226 }
227 
228 /******************************************************************************
229  *                                                                            *
230  * Function: diag_add_lld_info                                                *
231  *                                                                            *
232  * Purpose: add requested lld manager diagnostic information to json data     *
233  *                                                                            *
234  * Parameters: jp    - [IN] the request                                       *
235  *             json  - [IN/OUT] the json to update                            *
236  *             error - [OUT] error message                                    *
237  *                                                                            *
238  * Return value: SUCCEED - the information was added successfully             *
239  *               FAIL    - otherwise                                          *
240  *                                                                            *
241  ******************************************************************************/
diag_add_lld_info(const struct zbx_json_parse * jp,struct zbx_json * json,char ** error)242 static int	diag_add_lld_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error)
243 {
244 	zbx_vector_ptr_t	tops;
245 	int			ret;
246 	double			time1, time2, time_total = 0;
247 	zbx_uint64_t		fields;
248 	zbx_diag_map_t		field_map[] = {
249 					{"", ZBX_DIAG_LLD_SIMPLE},
250 					{"rules", ZBX_DIAG_LLD_RULES},
251 					{"values", ZBX_DIAG_LLD_VALUES},
252 					{NULL, 0}
253 					};
254 
255 	zbx_vector_ptr_create(&tops);
256 
257 	if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error)))
258 	{
259 		zbx_json_addobject(json, ZBX_DIAG_LLD);
260 
261 		if (0 != (fields & ZBX_DIAG_LLD_SIMPLE))
262 		{
263 			zbx_uint64_t	values_num, items_num;
264 
265 			time1 = zbx_time();
266 			if (FAIL == (ret = zbx_lld_get_diag_stats(&items_num, &values_num, error)))
267 				goto out;
268 			time2 = zbx_time();
269 			time_total += time2 - time1;
270 
271 			if (0 != (fields & ZBX_DIAG_LLD_RULES))
272 				zbx_json_addint64(json, "rules", items_num);
273 			if (0 != (fields & ZBX_DIAG_LLD_VALUES))
274 				zbx_json_addint64(json, "values", values_num);
275 		}
276 
277 		if (0 != tops.values_num)
278 		{
279 			int	i;
280 
281 			zbx_json_addobject(json, "top");
282 
283 			for (i = 0; i < tops.values_num; i++)
284 			{
285 				zbx_diag_map_t	*map = (zbx_diag_map_t *)tops.values[i];
286 
287 				if (0 == strcmp(map->name, "values"))
288 				{
289 					zbx_vector_uint64_pair_t	items;
290 
291 					zbx_vector_uint64_pair_create(&items);
292 
293 					time1 = zbx_time();
294 					if (FAIL == (ret = zbx_lld_get_top_items(map->value, &items, error)))
295 					{
296 						zbx_vector_uint64_pair_destroy(&items);
297 						goto out;
298 					}
299 					time2 = zbx_time();
300 					time_total += time2 - time1;
301 
302 					diag_add_lld_items(json, map->name, &items);
303 					zbx_vector_uint64_pair_destroy(&items);
304 				}
305 				else
306 				{
307 					*error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name);
308 					ret = FAIL;
309 					goto out;
310 				}
311 			}
312 
313 			zbx_json_close(json);
314 		}
315 
316 		zbx_json_addfloat(json, "time", time_total);
317 		zbx_json_close(json);
318 	}
319 out:
320 	zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free);
321 	zbx_vector_ptr_destroy(&tops);
322 
323 	return ret;
324 }
325 
326 /******************************************************************************
327  *                                                                            *
328  * Function: diag_add_alerting_mediatypes                                     *
329  *                                                                            *
330  * Purpose: add mediatype top list to output json                             *
331  *                                                                            *
332  * Parameters: json  - [OUT] the output json                                  *
333  *             field - [IN] the field name                                    *
334  *             items - [IN] a top mediatype list consisting of                *
335  *                          mediatype, alerts_num pairs                       *
336  *                                                                            *
337  ******************************************************************************/
diag_add_alerting_mediatypes(struct zbx_json * json,const char * field,const zbx_vector_uint64_pair_t * mediatypes)338 static void	diag_add_alerting_mediatypes(struct zbx_json *json, const char *field,
339 		const zbx_vector_uint64_pair_t *mediatypes)
340 {
341 	int	i;
342 
343 	zbx_json_addarray(json, field);
344 
345 	for (i = 0; i < mediatypes->values_num; i++)
346 	{
347 		zbx_json_addobject(json, NULL);
348 		zbx_json_adduint64(json, "mediatypeid", mediatypes->values[i].first);
349 		zbx_json_adduint64(json, "alerts", mediatypes->values[i].second);
350 		zbx_json_close(json);
351 	}
352 
353 	zbx_json_close(json);
354 }
355 
356 /******************************************************************************
357  *                                                                            *
358  * Function: diag_add_alerting_sources                                        *
359  *                                                                            *
360  * Purpose: add alert source top list to output json                          *
361  *                                                                            *
362  * Parameters: json  - [OUT] the output json                                  *
363  *             field - [IN] the field name                                    *
364  *             items - [IN] a top alert source list consisting of             *
365  *                          zbx_am_source_stats_t structures                  *
366  *                                                                            *
367  ******************************************************************************/
diag_add_alerting_sources(struct zbx_json * json,const char * field,const zbx_vector_ptr_t * sources)368 static void	diag_add_alerting_sources(struct zbx_json *json, const char *field, const zbx_vector_ptr_t *sources)
369 {
370 	int	i;
371 
372 	zbx_json_addarray(json, field);
373 
374 	for (i = 0; i < sources->values_num; i++)
375 	{
376 		const zbx_am_source_stats_t	*source = (const zbx_am_source_stats_t *)sources->values[i];
377 
378 		zbx_json_addobject(json, NULL);
379 		zbx_json_adduint64(json, "source", source->source);
380 		zbx_json_adduint64(json, "object", source->object);
381 		zbx_json_adduint64(json, "objectid", source->objectid);
382 		zbx_json_adduint64(json, "alerts", source->alerts_num);
383 		zbx_json_close(json);
384 	}
385 
386 	zbx_json_close(json);
387 }
388 
389 /******************************************************************************
390  *                                                                            *
391  * Function: diag_add_alerting_info                                           *
392  *                                                                            *
393  * Purpose: add requested alert manager diagnostic information to json data   *
394  *                                                                            *
395  * Parameters: jp    - [IN] the request                                       *
396  *             json  - [IN/OUT] the json to update                            *
397  *             error - [OUT] error message                                    *
398  *                                                                            *
399  * Return value: SUCCEED - the information was added successfully             *
400  *               FAIL    - otherwise                                          *
401  *                                                                            *
402  ******************************************************************************/
diag_add_alerting_info(const struct zbx_json_parse * jp,struct zbx_json * json,char ** error)403 static int	diag_add_alerting_info(const struct zbx_json_parse *jp, struct zbx_json *json, char **error)
404 {
405 	zbx_vector_ptr_t	tops;
406 	int			ret;
407 	double			time1, time2, time_total = 0;
408 	zbx_uint64_t		fields;
409 	zbx_diag_map_t		field_map[] = {
410 					{"", ZBX_DIAG_ALERTING_SIMPLE},
411 					{"alerts", ZBX_DIAG_ALERTING_ALERTS},
412 					{NULL, 0}
413 					};
414 
415 	zbx_vector_ptr_create(&tops);
416 
417 	if (SUCCEED == (ret = diag_parse_request(jp, field_map, &fields, &tops, error)))
418 	{
419 		zbx_json_addobject(json, ZBX_DIAG_ALERTING);
420 
421 		if (0 != (fields & ZBX_DIAG_ALERTING_SIMPLE))
422 		{
423 			zbx_uint64_t	alerts_num;
424 
425 			time1 = zbx_time();
426 			if (FAIL == (ret = zbx_alerter_get_diag_stats(&alerts_num, error)))
427 				goto out;
428 			time2 = zbx_time();
429 			time_total += time2 - time1;
430 
431 			if (0 != (fields & ZBX_DIAG_ALERTING_ALERTS))
432 				zbx_json_addint64(json, "alerts", alerts_num);
433 		}
434 
435 		if (0 != tops.values_num)
436 		{
437 			int	i;
438 
439 			zbx_json_addobject(json, "top");
440 
441 			for (i = 0; i < tops.values_num; i++)
442 			{
443 				zbx_diag_map_t	*map = (zbx_diag_map_t *)tops.values[i];
444 
445 				if (0 == strcmp(map->name, "media.alerts"))
446 				{
447 					zbx_vector_uint64_pair_t	mediatypes;
448 
449 					zbx_vector_uint64_pair_create(&mediatypes);
450 
451 					time1 = zbx_time();
452 					if (FAIL == (ret = zbx_alerter_get_top_mediatypes(map->value, &mediatypes,
453 							error)))
454 					{
455 						zbx_vector_uint64_pair_destroy(&mediatypes);
456 						goto out;
457 					}
458 					time2 = zbx_time();
459 					time_total += time2 - time1;
460 
461 					diag_add_alerting_mediatypes(json, map->name, &mediatypes);
462 					zbx_vector_uint64_pair_destroy(&mediatypes);
463 				}
464 				else if (0 == strcmp(map->name, "source.alerts"))
465 				{
466 					zbx_vector_ptr_t	sources;
467 
468 					zbx_vector_ptr_create(&sources);
469 
470 					time1 = zbx_time();
471 					if (FAIL == (ret = zbx_alerter_get_top_sources(map->value, &sources, error)))
472 					{
473 						zbx_vector_ptr_clear_ext(&sources, zbx_ptr_free);
474 						zbx_vector_ptr_destroy(&sources);
475 						goto out;
476 					}
477 					time2 = zbx_time();
478 					time_total += time2 - time1;
479 
480 					diag_add_alerting_sources(json, map->name, &sources);
481 					zbx_vector_ptr_clear_ext(&sources, zbx_ptr_free);
482 					zbx_vector_ptr_destroy(&sources);
483 				}
484 				else
485 				{
486 					*error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name);
487 					ret = FAIL;
488 					goto out;
489 				}
490 			}
491 
492 			zbx_json_close(json);
493 		}
494 
495 		zbx_json_addfloat(json, "time", time_total);
496 		zbx_json_close(json);
497 	}
498 out:
499 	zbx_vector_ptr_clear_ext(&tops, (zbx_ptr_free_func_t)diag_map_free);
500 	zbx_vector_ptr_destroy(&tops);
501 
502 	return ret;
503 }
504 
505 /******************************************************************************
506  *                                                                            *
507  * Function: diag_add_section_info                                            *
508  *                                                                            *
509  * Purpose: add requested section diagnostic information                      *
510  *                                                                            *
511  * Parameters: section - [IN] the section name                                *
512  *             jp      - [IN] the request                                     *
513  *             json    - [IN/OUT] the json to update                          *
514  *             error   - [OUT] the error message                              *
515  *                                                                            *
516  * Return value: SUCCEED - the information was retrieved successfully         *
517  *               FAIL    - otherwise                                          *
518  *                                                                            *
519  ******************************************************************************/
diag_add_section_info(const char * section,const struct zbx_json_parse * jp,struct zbx_json * json,char ** error)520 int	diag_add_section_info(const char *section, const struct zbx_json_parse *jp, struct zbx_json *json,
521 		char **error)
522 {
523 	int	ret = FAIL;
524 
525 	if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE))
526 		ret = diag_add_historycache_info(jp, json, error);
527 	else if (0 == strcmp(section, ZBX_DIAG_VALUECACHE))
528 		ret = diag_add_valuecache_info(jp, json, error);
529 	else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING))
530 		ret = diag_add_preproc_info(jp, json, error);
531 	else if (0 == strcmp(section, ZBX_DIAG_LLD))
532 		ret = diag_add_lld_info(jp, json, error);
533 	else if (0 == strcmp(section, ZBX_DIAG_ALERTING))
534 		ret = diag_add_alerting_info(jp, json, error);
535 	else if (0 == strcmp(section, ZBX_DIAG_LOCKS))
536 	{
537 		diag_add_locks_info(json);
538 		ret = SUCCEED;
539 	}
540 	else
541 		*error = zbx_dsprintf(*error, "Unsupported diagnostics section: %s", section);
542 
543 	return ret;
544 }
545 
546