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