api_v2.c 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "internal.h"
  3. #include "aclk/aclk_capas.h"
  4. // ----------------------------------------------------------------------------
  5. // /api/v2/contexts API
  6. struct alert_transitions_facets alert_transition_facets[] = {
  7. [ATF_STATUS] = {
  8. .id = "f_status",
  9. .name = "Alert Status",
  10. .query_param = "f_status",
  11. .order = 1,
  12. },
  13. [ATF_TYPE] = {
  14. .id = "f_type",
  15. .name = "Alert Type",
  16. .query_param = "f_type",
  17. .order = 2,
  18. },
  19. [ATF_ROLE] = {
  20. .id = "f_role",
  21. .name = "Recipient Role",
  22. .query_param = "f_role",
  23. .order = 3,
  24. },
  25. [ATF_CLASS] = {
  26. .id = "f_class",
  27. .name = "Alert Class",
  28. .query_param = "f_class",
  29. .order = 4,
  30. },
  31. [ATF_COMPONENT] = {
  32. .id = "f_component",
  33. .name = "Alert Component",
  34. .query_param = "f_component",
  35. .order = 5,
  36. },
  37. [ATF_NODE] = {
  38. .id = "f_node",
  39. .name = "Alert Node",
  40. .query_param = "f_node",
  41. .order = 6,
  42. },
  43. [ATF_ALERT_NAME] = {
  44. .id = "f_alert",
  45. .name = "Alert Name",
  46. .query_param = "f_alert",
  47. .order = 7,
  48. },
  49. [ATF_CHART_NAME] = {
  50. .id = "f_instance",
  51. .name = "Instance Name",
  52. .query_param = "f_instance",
  53. .order = 8,
  54. },
  55. [ATF_CONTEXT] = {
  56. .id = "f_context",
  57. .name = "Context",
  58. .query_param = "f_context",
  59. .order = 9,
  60. },
  61. // terminator
  62. [ATF_TOTAL_ENTRIES] = {
  63. .id = NULL,
  64. .name = NULL,
  65. .query_param = NULL,
  66. .order = 9999,
  67. }
  68. };
  69. struct facet_entry {
  70. uint32_t count;
  71. };
  72. struct alert_transitions_callback_data {
  73. struct rrdcontext_to_json_v2_data *ctl;
  74. BUFFER *wb;
  75. bool debug;
  76. bool only_one_config;
  77. struct {
  78. SIMPLE_PATTERN *pattern;
  79. DICTIONARY *dict;
  80. } facets[ATF_TOTAL_ENTRIES];
  81. uint32_t max_items_to_return;
  82. uint32_t items_to_return;
  83. uint32_t items_evaluated;
  84. uint32_t items_matched;
  85. struct sql_alert_transition_fixed_size *base; // double linked list - last item is base->prev
  86. struct sql_alert_transition_fixed_size *last_added; // the last item added, not the last of the list
  87. struct {
  88. size_t first;
  89. size_t skips_before;
  90. size_t skips_after;
  91. size_t backwards;
  92. size_t forwards;
  93. size_t prepend;
  94. size_t append;
  95. size_t shifts;
  96. } operations;
  97. uint32_t configs_added;
  98. };
  99. typedef enum __attribute__ ((__packed__)) {
  100. FTS_MATCHED_NONE = 0,
  101. FTS_MATCHED_HOST,
  102. FTS_MATCHED_CONTEXT,
  103. FTS_MATCHED_INSTANCE,
  104. FTS_MATCHED_DIMENSION,
  105. FTS_MATCHED_LABEL,
  106. FTS_MATCHED_ALERT,
  107. FTS_MATCHED_ALERT_INFO,
  108. FTS_MATCHED_FAMILY,
  109. FTS_MATCHED_TITLE,
  110. FTS_MATCHED_UNITS,
  111. } FTS_MATCH;
  112. static const char *fts_match_to_string(FTS_MATCH match) {
  113. switch(match) {
  114. case FTS_MATCHED_HOST:
  115. return "HOST";
  116. case FTS_MATCHED_CONTEXT:
  117. return "CONTEXT";
  118. case FTS_MATCHED_INSTANCE:
  119. return "INSTANCE";
  120. case FTS_MATCHED_DIMENSION:
  121. return "DIMENSION";
  122. case FTS_MATCHED_ALERT:
  123. return "ALERT";
  124. case FTS_MATCHED_ALERT_INFO:
  125. return "ALERT_INFO";
  126. case FTS_MATCHED_LABEL:
  127. return "LABEL";
  128. case FTS_MATCHED_FAMILY:
  129. return "FAMILY";
  130. case FTS_MATCHED_TITLE:
  131. return "TITLE";
  132. case FTS_MATCHED_UNITS:
  133. return "UNITS";
  134. default:
  135. return "NONE";
  136. }
  137. }
  138. struct function_v2_entry {
  139. size_t size;
  140. size_t used;
  141. size_t *node_ids;
  142. STRING *help;
  143. };
  144. struct context_v2_entry {
  145. size_t count;
  146. STRING *id;
  147. STRING *family;
  148. uint32_t priority;
  149. time_t first_time_s;
  150. time_t last_time_s;
  151. RRD_FLAGS flags;
  152. FTS_MATCH match;
  153. };
  154. struct alert_v2_entry {
  155. RRDCALC *tmp;
  156. STRING *name;
  157. STRING *summary;
  158. size_t ati;
  159. size_t critical;
  160. size_t warning;
  161. size_t clear;
  162. size_t error;
  163. size_t instances;
  164. DICTIONARY *nodes;
  165. DICTIONARY *configs;
  166. };
  167. typedef struct full_text_search_index {
  168. size_t searches;
  169. size_t string_searches;
  170. size_t char_searches;
  171. } FTS_INDEX;
  172. static inline bool full_text_search_string(FTS_INDEX *fts, SIMPLE_PATTERN *q, STRING *ptr) {
  173. fts->searches++;
  174. fts->string_searches++;
  175. return simple_pattern_matches_string(q, ptr);
  176. }
  177. static inline bool full_text_search_char(FTS_INDEX *fts, SIMPLE_PATTERN *q, char *ptr) {
  178. fts->searches++;
  179. fts->char_searches++;
  180. return simple_pattern_matches(q, ptr);
  181. }
  182. struct contexts_v2_node {
  183. size_t ni;
  184. RRDHOST *host;
  185. };
  186. struct rrdcontext_to_json_v2_data {
  187. time_t now;
  188. BUFFER *wb;
  189. struct api_v2_contexts_request *request;
  190. CONTEXTS_V2_MODE mode;
  191. CONTEXTS_V2_OPTIONS options;
  192. struct query_versions versions;
  193. struct {
  194. SIMPLE_PATTERN *scope_pattern;
  195. SIMPLE_PATTERN *pattern;
  196. size_t ni;
  197. DICTIONARY *dict; // the result set
  198. } nodes;
  199. struct {
  200. SIMPLE_PATTERN *scope_pattern;
  201. SIMPLE_PATTERN *pattern;
  202. size_t ci;
  203. DICTIONARY *dict; // the result set
  204. } contexts;
  205. struct {
  206. SIMPLE_PATTERN *alert_name_pattern;
  207. time_t alarm_id_filter;
  208. size_t ati;
  209. DICTIONARY *alerts;
  210. DICTIONARY *alert_instances;
  211. } alerts;
  212. struct {
  213. FTS_MATCH host_match;
  214. char host_node_id_str[UUID_STR_LEN];
  215. SIMPLE_PATTERN *pattern;
  216. FTS_INDEX fts;
  217. } q;
  218. struct {
  219. DICTIONARY *dict; // the result set
  220. } functions;
  221. struct {
  222. bool enabled;
  223. bool relative;
  224. time_t after;
  225. time_t before;
  226. } window;
  227. struct query_timings timings;
  228. };
  229. static void alerts_v2_add(struct alert_v2_entry *t, RRDCALC *rc) {
  230. t->instances++;
  231. switch(rc->status) {
  232. case RRDCALC_STATUS_CRITICAL:
  233. t->critical++;
  234. break;
  235. case RRDCALC_STATUS_WARNING:
  236. t->warning++;
  237. break;
  238. case RRDCALC_STATUS_CLEAR:
  239. t->clear++;
  240. break;
  241. case RRDCALC_STATUS_REMOVED:
  242. case RRDCALC_STATUS_UNINITIALIZED:
  243. break;
  244. case RRDCALC_STATUS_UNDEFINED:
  245. default:
  246. if(!netdata_double_isnumber(rc->value))
  247. t->error++;
  248. break;
  249. }
  250. dictionary_set(t->nodes, rc->rrdset->rrdhost->machine_guid, NULL, 0);
  251. char key[UUID_STR_LEN + 1];
  252. uuid_unparse_lower(rc->config_hash_id, key);
  253. dictionary_set(t->configs, key, NULL, 0);
  254. }
  255. static void alerts_v2_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data) {
  256. struct rrdcontext_to_json_v2_data *ctl = data;
  257. struct alert_v2_entry *t = value;
  258. RRDCALC *rc = t->tmp;
  259. t->name = rc->name;
  260. t->summary = rc->summary;
  261. t->ati = ctl->alerts.ati++;
  262. t->nodes = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_VALUE_LINK_DONT_CLONE|DICT_OPTION_NAME_LINK_DONT_CLONE);
  263. t->configs = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_VALUE_LINK_DONT_CLONE|DICT_OPTION_NAME_LINK_DONT_CLONE);
  264. alerts_v2_add(t, rc);
  265. }
  266. static bool alerts_v2_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused) {
  267. struct alert_v2_entry *t = old_value, *n = new_value;
  268. RRDCALC *rc = n->tmp;
  269. alerts_v2_add(t, rc);
  270. return true;
  271. }
  272. static void alerts_v2_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
  273. struct alert_v2_entry *t = value;
  274. dictionary_destroy(t->nodes);
  275. dictionary_destroy(t->configs);
  276. }
  277. static void alert_instances_v2_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data) {
  278. struct rrdcontext_to_json_v2_data *ctl = data;
  279. struct sql_alert_instance_v2_entry *t = value;
  280. RRDCALC *rc = t->tmp;
  281. t->context = rc->rrdset->context;
  282. t->chart_id = rc->rrdset->id;
  283. t->chart_name = rc->rrdset->name;
  284. t->family = rc->rrdset->family;
  285. t->units = rc->units;
  286. t->classification = rc->classification;
  287. t->type = rc->type;
  288. t->recipient = rc->recipient;
  289. t->component = rc->component;
  290. t->name = rc->name;
  291. t->source = rc->source;
  292. t->status = rc->status;
  293. t->flags = rc->run_flags;
  294. t->info = rc->info;
  295. t->summary = rc->summary;
  296. t->value = rc->value;
  297. t->last_updated = rc->last_updated;
  298. t->last_status_change = rc->last_status_change;
  299. t->last_status_change_value = rc->last_status_change_value;
  300. t->host = rc->rrdset->rrdhost;
  301. t->alarm_id = rc->id;
  302. t->ni = ctl->nodes.ni;
  303. t->global_id = rc->ae ? rc->ae->global_id : 0;
  304. t->name = rc->name;
  305. uuid_copy(t->config_hash_id, rc->config_hash_id);
  306. if(rc->ae)
  307. uuid_copy(t->last_transition_id, rc->ae->transition_id);
  308. }
  309. static bool alert_instances_v2_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value __maybe_unused, void *new_value __maybe_unused, void *data __maybe_unused) {
  310. internal_fatal(true, "This should never happen!");
  311. return true;
  312. }
  313. static void alert_instances_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value __maybe_unused, void *data __maybe_unused) {
  314. ;
  315. }
  316. static FTS_MATCH rrdcontext_to_json_v2_full_text_search(struct rrdcontext_to_json_v2_data *ctl, RRDCONTEXT *rc, SIMPLE_PATTERN *q) {
  317. if(unlikely(full_text_search_string(&ctl->q.fts, q, rc->id) ||
  318. full_text_search_string(&ctl->q.fts, q, rc->family)))
  319. return FTS_MATCHED_CONTEXT;
  320. if(unlikely(full_text_search_string(&ctl->q.fts, q, rc->title)))
  321. return FTS_MATCHED_TITLE;
  322. if(unlikely(full_text_search_string(&ctl->q.fts, q, rc->units)))
  323. return FTS_MATCHED_UNITS;
  324. FTS_MATCH matched = FTS_MATCHED_NONE;
  325. RRDINSTANCE *ri;
  326. dfe_start_read(rc->rrdinstances, ri) {
  327. if(matched) break;
  328. if(ctl->window.enabled && !query_matches_retention(ctl->window.after, ctl->window.before, ri->first_time_s, (ri->flags & RRD_FLAG_COLLECTED) ? ctl->now : ri->last_time_s, 0))
  329. continue;
  330. if(unlikely(full_text_search_string(&ctl->q.fts, q, ri->id)) ||
  331. (ri->name != ri->id && full_text_search_string(&ctl->q.fts, q, ri->name))) {
  332. matched = FTS_MATCHED_INSTANCE;
  333. break;
  334. }
  335. RRDMETRIC *rm;
  336. dfe_start_read(ri->rrdmetrics, rm) {
  337. if(ctl->window.enabled && !query_matches_retention(ctl->window.after, ctl->window.before, rm->first_time_s, (rm->flags & RRD_FLAG_COLLECTED) ? ctl->now : rm->last_time_s, 0))
  338. continue;
  339. if(unlikely(full_text_search_string(&ctl->q.fts, q, rm->id)) ||
  340. (rm->name != rm->id && full_text_search_string(&ctl->q.fts, q, rm->name))) {
  341. matched = FTS_MATCHED_DIMENSION;
  342. break;
  343. }
  344. }
  345. dfe_done(rm);
  346. size_t label_searches = 0;
  347. if(unlikely(ri->rrdlabels && rrdlabels_entries(ri->rrdlabels) &&
  348. rrdlabels_match_simple_pattern_parsed(ri->rrdlabels, q, ':', &label_searches))) {
  349. ctl->q.fts.searches += label_searches;
  350. ctl->q.fts.char_searches += label_searches;
  351. matched = FTS_MATCHED_LABEL;
  352. break;
  353. }
  354. ctl->q.fts.searches += label_searches;
  355. ctl->q.fts.char_searches += label_searches;
  356. if(ri->rrdset) {
  357. RRDSET *st = ri->rrdset;
  358. rw_spinlock_read_lock(&st->alerts.spinlock);
  359. for (RRDCALC *rcl = st->alerts.base; rcl; rcl = rcl->next) {
  360. if(unlikely(full_text_search_string(&ctl->q.fts, q, rcl->name))) {
  361. matched = FTS_MATCHED_ALERT;
  362. break;
  363. }
  364. if(unlikely(full_text_search_string(&ctl->q.fts, q, rcl->info))) {
  365. matched = FTS_MATCHED_ALERT_INFO;
  366. break;
  367. }
  368. }
  369. rw_spinlock_read_unlock(&st->alerts.spinlock);
  370. }
  371. }
  372. dfe_done(ri);
  373. return matched;
  374. }
  375. static bool rrdcontext_matches_alert(struct rrdcontext_to_json_v2_data *ctl, RRDCONTEXT *rc) {
  376. size_t matches = 0;
  377. RRDINSTANCE *ri;
  378. dfe_start_read(rc->rrdinstances, ri) {
  379. if(ri->rrdset) {
  380. RRDSET *st = ri->rrdset;
  381. rw_spinlock_read_lock(&st->alerts.spinlock);
  382. for (RRDCALC *rcl = st->alerts.base; rcl; rcl = rcl->next) {
  383. if(ctl->alerts.alert_name_pattern && !simple_pattern_matches_string(ctl->alerts.alert_name_pattern, rcl->name))
  384. continue;
  385. if(ctl->alerts.alarm_id_filter && ctl->alerts.alarm_id_filter != rcl->id)
  386. continue;
  387. size_t m = ctl->request->alerts.status & CONTEXTS_V2_ALERT_STATUSES ? 0 : 1;
  388. if (!m) {
  389. if ((ctl->request->alerts.status & CONTEXT_V2_ALERT_UNINITIALIZED) &&
  390. rcl->status == RRDCALC_STATUS_UNINITIALIZED)
  391. m++;
  392. if ((ctl->request->alerts.status & CONTEXT_V2_ALERT_UNDEFINED) &&
  393. rcl->status == RRDCALC_STATUS_UNDEFINED)
  394. m++;
  395. if ((ctl->request->alerts.status & CONTEXT_V2_ALERT_CLEAR) &&
  396. rcl->status == RRDCALC_STATUS_CLEAR)
  397. m++;
  398. if ((ctl->request->alerts.status & CONTEXT_V2_ALERT_RAISED) &&
  399. rcl->status >= RRDCALC_STATUS_RAISED)
  400. m++;
  401. if ((ctl->request->alerts.status & CONTEXT_V2_ALERT_WARNING) &&
  402. rcl->status == RRDCALC_STATUS_WARNING)
  403. m++;
  404. if ((ctl->request->alerts.status & CONTEXT_V2_ALERT_CRITICAL) &&
  405. rcl->status == RRDCALC_STATUS_CRITICAL)
  406. m++;
  407. if(!m)
  408. continue;
  409. }
  410. struct alert_v2_entry t = {
  411. .tmp = rcl,
  412. };
  413. struct alert_v2_entry *a2e = dictionary_set(ctl->alerts.alerts, string2str(rcl->name), &t,
  414. sizeof(struct alert_v2_entry));
  415. size_t ati = a2e->ati;
  416. matches++;
  417. if (ctl->options & (CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES | CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)) {
  418. char key[20 + 1];
  419. snprintfz(key, sizeof(key) - 1, "%p", rcl);
  420. struct sql_alert_instance_v2_entry z = {
  421. .ati = ati,
  422. .tmp = rcl,
  423. };
  424. dictionary_set(ctl->alerts.alert_instances, key, &z, sizeof(z));
  425. }
  426. }
  427. rw_spinlock_read_unlock(&st->alerts.spinlock);
  428. }
  429. }
  430. dfe_done(ri);
  431. return matches != 0;
  432. }
  433. static ssize_t rrdcontext_to_json_v2_add_context(void *data, RRDCONTEXT_ACQUIRED *rca, bool queryable_context __maybe_unused) {
  434. struct rrdcontext_to_json_v2_data *ctl = data;
  435. RRDCONTEXT *rc = rrdcontext_acquired_value(rca);
  436. if(ctl->window.enabled && !query_matches_retention(ctl->window.after, ctl->window.before, rc->first_time_s, (rc->flags & RRD_FLAG_COLLECTED) ? ctl->now : rc->last_time_s, 0))
  437. return 0; // continue to next context
  438. FTS_MATCH match = ctl->q.host_match;
  439. if((ctl->mode & CONTEXTS_V2_SEARCH) && ctl->q.pattern) {
  440. match = rrdcontext_to_json_v2_full_text_search(ctl, rc, ctl->q.pattern);
  441. if(match == FTS_MATCHED_NONE)
  442. return 0; // continue to next context
  443. }
  444. if(ctl->mode & CONTEXTS_V2_ALERTS) {
  445. if(!rrdcontext_matches_alert(ctl, rc))
  446. return 0; // continue to next context
  447. }
  448. if(ctl->contexts.dict) {
  449. struct context_v2_entry t = {
  450. .count = 1,
  451. .id = rc->id,
  452. .family = string_dup(rc->family),
  453. .priority = rc->priority,
  454. .first_time_s = rc->first_time_s,
  455. .last_time_s = rc->last_time_s,
  456. .flags = rc->flags,
  457. .match = match,
  458. };
  459. dictionary_set(ctl->contexts.dict, string2str(rc->id), &t, sizeof(struct context_v2_entry));
  460. }
  461. return 1;
  462. }
  463. void buffer_json_agent_status_id(BUFFER *wb, size_t ai, usec_t duration_ut) {
  464. buffer_json_member_add_object(wb, "st");
  465. {
  466. buffer_json_member_add_uint64(wb, "ai", ai);
  467. buffer_json_member_add_uint64(wb, "code", 200);
  468. buffer_json_member_add_string(wb, "msg", "");
  469. if (duration_ut)
  470. buffer_json_member_add_double(wb, "ms", (NETDATA_DOUBLE) duration_ut / 1000.0);
  471. }
  472. buffer_json_object_close(wb);
  473. }
  474. void buffer_json_node_add_v2(BUFFER *wb, RRDHOST *host, size_t ni, usec_t duration_ut, bool status) {
  475. buffer_json_member_add_string(wb, "mg", host->machine_guid);
  476. if(host->node_id)
  477. buffer_json_member_add_uuid(wb, "nd", host->node_id);
  478. buffer_json_member_add_string(wb, "nm", rrdhost_hostname(host));
  479. buffer_json_member_add_uint64(wb, "ni", ni);
  480. if(status)
  481. buffer_json_agent_status_id(wb, 0, duration_ut);
  482. }
  483. static void rrdhost_receiver_to_json(BUFFER *wb, RRDHOST_STATUS *s, const char *key) {
  484. buffer_json_member_add_object(wb, key);
  485. {
  486. buffer_json_member_add_uint64(wb, "id", s->ingest.id);
  487. buffer_json_member_add_uint64(wb, "hops", s->ingest.hops);
  488. buffer_json_member_add_string(wb, "type", rrdhost_ingest_type_to_string(s->ingest.type));
  489. buffer_json_member_add_string(wb, "status", rrdhost_ingest_status_to_string(s->ingest.status));
  490. buffer_json_member_add_time_t(wb, "since", s->ingest.since);
  491. buffer_json_member_add_time_t(wb, "age", s->now - s->ingest.since);
  492. if(s->ingest.type == RRDHOST_INGEST_TYPE_CHILD) {
  493. if(s->ingest.status == RRDHOST_INGEST_STATUS_OFFLINE)
  494. buffer_json_member_add_string(wb, "reason", stream_handshake_error_to_string(s->ingest.reason));
  495. if(s->ingest.status == RRDHOST_INGEST_STATUS_REPLICATING) {
  496. buffer_json_member_add_object(wb, "replication");
  497. {
  498. buffer_json_member_add_boolean(wb, "in_progress", s->ingest.replication.in_progress);
  499. buffer_json_member_add_double(wb, "completion", s->ingest.replication.completion);
  500. buffer_json_member_add_uint64(wb, "instances", s->ingest.replication.instances);
  501. }
  502. buffer_json_object_close(wb); // replication
  503. }
  504. if(s->ingest.status == RRDHOST_INGEST_STATUS_REPLICATING || s->ingest.status == RRDHOST_INGEST_STATUS_ONLINE) {
  505. buffer_json_member_add_object(wb, "source");
  506. {
  507. char buf[1024 + 1];
  508. snprintfz(buf, sizeof(buf) - 1, "[%s]:%d%s", s->ingest.peers.local.ip, s->ingest.peers.local.port, s->ingest.ssl ? ":SSL" : "");
  509. buffer_json_member_add_string(wb, "local", buf);
  510. snprintfz(buf, sizeof(buf) - 1, "[%s]:%d%s", s->ingest.peers.peer.ip, s->ingest.peers.peer.port, s->ingest.ssl ? ":SSL" : "");
  511. buffer_json_member_add_string(wb, "remote", buf);
  512. stream_capabilities_to_json_array(wb, s->ingest.capabilities, "capabilities");
  513. }
  514. buffer_json_object_close(wb); // source
  515. }
  516. }
  517. }
  518. buffer_json_object_close(wb); // collection
  519. }
  520. static void rrdhost_sender_to_json(BUFFER *wb, RRDHOST_STATUS *s, const char *key) {
  521. if(s->stream.status == RRDHOST_STREAM_STATUS_DISABLED)
  522. return;
  523. buffer_json_member_add_object(wb, key);
  524. {
  525. buffer_json_member_add_uint64(wb, "id", s->stream.id);
  526. buffer_json_member_add_uint64(wb, "hops", s->stream.hops);
  527. buffer_json_member_add_string(wb, "status", rrdhost_streaming_status_to_string(s->stream.status));
  528. buffer_json_member_add_time_t(wb, "since", s->stream.since);
  529. buffer_json_member_add_time_t(wb, "age", s->now - s->stream.since);
  530. if (s->stream.status == RRDHOST_STREAM_STATUS_OFFLINE)
  531. buffer_json_member_add_string(wb, "reason", stream_handshake_error_to_string(s->stream.reason));
  532. if (s->stream.status == RRDHOST_STREAM_STATUS_REPLICATING) {
  533. buffer_json_member_add_object(wb, "replication");
  534. {
  535. buffer_json_member_add_boolean(wb, "in_progress", s->stream.replication.in_progress);
  536. buffer_json_member_add_double(wb, "completion", s->stream.replication.completion);
  537. buffer_json_member_add_uint64(wb, "instances", s->stream.replication.instances);
  538. }
  539. buffer_json_object_close(wb);
  540. }
  541. buffer_json_member_add_object(wb, "destination");
  542. {
  543. char buf[1024 + 1];
  544. snprintfz(buf, sizeof(buf) - 1, "[%s]:%d%s", s->stream.peers.local.ip, s->stream.peers.local.port, s->stream.ssl ? ":SSL" : "");
  545. buffer_json_member_add_string(wb, "local", buf);
  546. snprintfz(buf, sizeof(buf) - 1, "[%s]:%d%s", s->stream.peers.peer.ip, s->stream.peers.peer.port, s->stream.ssl ? ":SSL" : "");
  547. buffer_json_member_add_string(wb, "remote", buf);
  548. stream_capabilities_to_json_array(wb, s->stream.capabilities, "capabilities");
  549. buffer_json_member_add_object(wb, "traffic");
  550. {
  551. buffer_json_member_add_boolean(wb, "compression", s->stream.compression);
  552. buffer_json_member_add_uint64(wb, "data", s->stream.sent_bytes_on_this_connection_per_type[STREAM_TRAFFIC_TYPE_DATA]);
  553. buffer_json_member_add_uint64(wb, "metadata", s->stream.sent_bytes_on_this_connection_per_type[STREAM_TRAFFIC_TYPE_METADATA]);
  554. buffer_json_member_add_uint64(wb, "functions", s->stream.sent_bytes_on_this_connection_per_type[STREAM_TRAFFIC_TYPE_FUNCTIONS]);
  555. buffer_json_member_add_uint64(wb, "replication", s->stream.sent_bytes_on_this_connection_per_type[STREAM_TRAFFIC_TYPE_REPLICATION]);
  556. buffer_json_member_add_uint64(wb, "dyncfg", s->stream.sent_bytes_on_this_connection_per_type[STREAM_TRAFFIC_TYPE_DYNCFG]);
  557. }
  558. buffer_json_object_close(wb); // traffic
  559. buffer_json_member_add_array(wb, "candidates");
  560. struct rrdpush_destinations *d;
  561. for (d = s->host->destinations; d; d = d->next) {
  562. buffer_json_add_array_item_object(wb);
  563. buffer_json_member_add_uint64(wb, "attempts", d->attempts);
  564. {
  565. if (d->ssl) {
  566. snprintfz(buf, sizeof(buf) - 1, "%s:SSL", string2str(d->destination));
  567. buffer_json_member_add_string(wb, "destination", buf);
  568. }
  569. else
  570. buffer_json_member_add_string(wb, "destination", string2str(d->destination));
  571. buffer_json_member_add_time_t(wb, "since", d->since);
  572. buffer_json_member_add_time_t(wb, "age", s->now - d->since);
  573. buffer_json_member_add_string(wb, "last_handshake", stream_handshake_error_to_string(d->reason));
  574. if(d->postpone_reconnection_until > s->now) {
  575. buffer_json_member_add_time_t(wb, "next_check", d->postpone_reconnection_until);
  576. buffer_json_member_add_time_t(wb, "next_in", d->postpone_reconnection_until - s->now);
  577. }
  578. }
  579. buffer_json_object_close(wb); // each candidate
  580. }
  581. buffer_json_array_close(wb); // candidates
  582. }
  583. buffer_json_object_close(wb); // destination
  584. }
  585. buffer_json_object_close(wb); // streaming
  586. }
  587. static void agent_capabilities_to_json(BUFFER *wb, RRDHOST *host, const char *key) {
  588. buffer_json_member_add_array(wb, key);
  589. struct capability *capas = aclk_get_node_instance_capas(host);
  590. for(struct capability *capa = capas; capa->name ;capa++) {
  591. buffer_json_add_array_item_object(wb);
  592. {
  593. buffer_json_member_add_string(wb, "name", capa->name);
  594. buffer_json_member_add_uint64(wb, "version", capa->version);
  595. buffer_json_member_add_boolean(wb, "enabled", capa->enabled);
  596. }
  597. buffer_json_object_close(wb);
  598. }
  599. buffer_json_array_close(wb);
  600. freez(capas);
  601. }
  602. static inline void rrdhost_health_to_json_v2(BUFFER *wb, const char *key, RRDHOST_STATUS *s) {
  603. buffer_json_member_add_object(wb, key);
  604. {
  605. buffer_json_member_add_string(wb, "status", rrdhost_health_status_to_string(s->health.status));
  606. if (s->health.status == RRDHOST_HEALTH_STATUS_RUNNING) {
  607. buffer_json_member_add_object(wb, "alerts");
  608. {
  609. buffer_json_member_add_uint64(wb, "critical", s->health.alerts.critical);
  610. buffer_json_member_add_uint64(wb, "warning", s->health.alerts.warning);
  611. buffer_json_member_add_uint64(wb, "clear", s->health.alerts.clear);
  612. buffer_json_member_add_uint64(wb, "undefined", s->health.alerts.undefined);
  613. buffer_json_member_add_uint64(wb, "uninitialized", s->health.alerts.uninitialized);
  614. }
  615. buffer_json_object_close(wb); // alerts
  616. }
  617. }
  618. buffer_json_object_close(wb); // health
  619. }
  620. static void rrdcontext_to_json_v2_rrdhost(BUFFER *wb, RRDHOST *host, struct rrdcontext_to_json_v2_data *ctl, size_t node_id) {
  621. buffer_json_add_array_item_object(wb); // this node
  622. buffer_json_node_add_v2(wb, host, node_id, 0,
  623. (ctl->mode & CONTEXTS_V2_AGENTS) && !(ctl->mode & CONTEXTS_V2_NODE_INSTANCES));
  624. if(ctl->mode & (CONTEXTS_V2_NODES_INFO | CONTEXTS_V2_NODE_INSTANCES)) {
  625. RRDHOST_STATUS s;
  626. rrdhost_status(host, ctl->now, &s);
  627. if (ctl->mode & (CONTEXTS_V2_NODES_INFO)) {
  628. buffer_json_member_add_string(wb, "v", rrdhost_program_version(host));
  629. host_labels2json(host, wb, "labels");
  630. if (host->system_info) {
  631. buffer_json_member_add_object(wb, "hw");
  632. {
  633. buffer_json_member_add_string_or_empty(wb, "architecture", host->system_info->architecture);
  634. buffer_json_member_add_string_or_empty(wb, "cpu_frequency", host->system_info->host_cpu_freq);
  635. buffer_json_member_add_string_or_empty(wb, "cpus", host->system_info->host_cores);
  636. buffer_json_member_add_string_or_empty(wb, "memory", host->system_info->host_ram_total);
  637. buffer_json_member_add_string_or_empty(wb, "disk_space", host->system_info->host_disk_space);
  638. buffer_json_member_add_string_or_empty(wb, "virtualization", host->system_info->virtualization);
  639. buffer_json_member_add_string_or_empty(wb, "container", host->system_info->container);
  640. }
  641. buffer_json_object_close(wb);
  642. buffer_json_member_add_object(wb, "os");
  643. {
  644. buffer_json_member_add_string_or_empty(wb, "id", host->system_info->host_os_id);
  645. buffer_json_member_add_string_or_empty(wb, "nm", host->system_info->host_os_name);
  646. buffer_json_member_add_string_or_empty(wb, "v", host->system_info->host_os_version);
  647. buffer_json_member_add_object(wb, "kernel");
  648. buffer_json_member_add_string_or_empty(wb, "nm", host->system_info->kernel_name);
  649. buffer_json_member_add_string_or_empty(wb, "v", host->system_info->kernel_version);
  650. buffer_json_object_close(wb);
  651. }
  652. buffer_json_object_close(wb);
  653. }
  654. // created - the node is created but never connected to cloud
  655. // unreachable - not currently connected
  656. // stale - connected but not having live data
  657. // reachable - connected with live data
  658. // pruned - not connected for some time and has been removed
  659. buffer_json_member_add_string(wb, "state", rrdhost_state_cloud_emulation(host) ? "reachable" : "stale");
  660. rrdhost_health_to_json_v2(wb, "health", &s);
  661. agent_capabilities_to_json(wb, host, "capabilities");
  662. }
  663. if (ctl->mode & (CONTEXTS_V2_NODE_INSTANCES)) {
  664. buffer_json_member_add_array(wb, "instances");
  665. buffer_json_add_array_item_object(wb); // this instance
  666. {
  667. buffer_json_agent_status_id(wb, 0, 0);
  668. buffer_json_member_add_object(wb, "db");
  669. {
  670. buffer_json_member_add_string(wb, "status", rrdhost_db_status_to_string(s.db.status));
  671. buffer_json_member_add_string(wb, "liveness", rrdhost_db_liveness_to_string(s.db.liveness));
  672. buffer_json_member_add_string(wb, "mode", rrd_memory_mode_name(s.db.mode));
  673. buffer_json_member_add_time_t(wb, "first_time", s.db.first_time_s);
  674. buffer_json_member_add_time_t(wb, "last_time", s.db.last_time_s);
  675. buffer_json_member_add_uint64(wb, "metrics", s.db.metrics);
  676. buffer_json_member_add_uint64(wb, "instances", s.db.instances);
  677. buffer_json_member_add_uint64(wb, "contexts", s.db.contexts);
  678. }
  679. buffer_json_object_close(wb);
  680. rrdhost_receiver_to_json(wb, &s, "ingest");
  681. rrdhost_sender_to_json(wb, &s, "stream");
  682. buffer_json_member_add_object(wb, "ml");
  683. buffer_json_member_add_string(wb, "status", rrdhost_ml_status_to_string(s.ml.status));
  684. buffer_json_member_add_string(wb, "type", rrdhost_ml_type_to_string(s.ml.type));
  685. if (s.ml.status == RRDHOST_ML_STATUS_RUNNING) {
  686. buffer_json_member_add_object(wb, "metrics");
  687. {
  688. buffer_json_member_add_uint64(wb, "anomalous", s.ml.metrics.anomalous);
  689. buffer_json_member_add_uint64(wb, "normal", s.ml.metrics.normal);
  690. buffer_json_member_add_uint64(wb, "trained", s.ml.metrics.trained);
  691. buffer_json_member_add_uint64(wb, "pending", s.ml.metrics.pending);
  692. buffer_json_member_add_uint64(wb, "silenced", s.ml.metrics.silenced);
  693. }
  694. buffer_json_object_close(wb); // metrics
  695. }
  696. buffer_json_object_close(wb); // ml
  697. rrdhost_health_to_json_v2(wb, "health", &s);
  698. host_functions2json(host, wb); // functions
  699. agent_capabilities_to_json(wb, host, "capabilities");
  700. }
  701. buffer_json_object_close(wb); // this instance
  702. buffer_json_array_close(wb); // instances
  703. }
  704. }
  705. buffer_json_object_close(wb); // this node
  706. }
  707. static ssize_t rrdcontext_to_json_v2_add_host(void *data, RRDHOST *host, bool queryable_host) {
  708. if(!queryable_host || !host->rrdctx.contexts)
  709. // the host matches the 'scope_host' but does not match the 'host' patterns
  710. // or the host does not have any contexts
  711. return 0; // continue to next host
  712. struct rrdcontext_to_json_v2_data *ctl = data;
  713. if(ctl->window.enabled && !rrdhost_matches_window(host, ctl->window.after, ctl->window.before, ctl->now))
  714. // the host does not have data in the requested window
  715. return 0; // continue to next host
  716. if(ctl->request->timeout_ms && now_monotonic_usec() > ctl->timings.received_ut + ctl->request->timeout_ms * USEC_PER_MS)
  717. // timed out
  718. return -2; // stop the query
  719. if(ctl->request->interrupt_callback && ctl->request->interrupt_callback(ctl->request->interrupt_callback_data))
  720. // interrupted
  721. return -1; // stop the query
  722. bool host_matched = (ctl->mode & CONTEXTS_V2_NODES);
  723. bool do_contexts = (ctl->mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_ALERTS));
  724. ctl->q.host_match = FTS_MATCHED_NONE;
  725. if((ctl->mode & CONTEXTS_V2_SEARCH)) {
  726. // check if we match the host itself
  727. if(ctl->q.pattern && (
  728. full_text_search_string(&ctl->q.fts, ctl->q.pattern, host->hostname) ||
  729. full_text_search_char(&ctl->q.fts, ctl->q.pattern, host->machine_guid) ||
  730. (ctl->q.pattern && full_text_search_char(&ctl->q.fts, ctl->q.pattern, ctl->q.host_node_id_str)))) {
  731. ctl->q.host_match = FTS_MATCHED_HOST;
  732. do_contexts = true;
  733. }
  734. }
  735. if(do_contexts) {
  736. // save it
  737. SIMPLE_PATTERN *old_q = ctl->q.pattern;
  738. if(ctl->q.host_match == FTS_MATCHED_HOST)
  739. // do not do pattern matching on contexts - we matched the host itself
  740. ctl->q.pattern = NULL;
  741. ssize_t added = query_scope_foreach_context(
  742. host, ctl->request->scope_contexts,
  743. ctl->contexts.scope_pattern, ctl->contexts.pattern,
  744. rrdcontext_to_json_v2_add_context, queryable_host, ctl);
  745. // restore it
  746. ctl->q.pattern = old_q;
  747. if(unlikely(added < 0))
  748. return -1; // stop the query
  749. if(added)
  750. host_matched = true;
  751. }
  752. if(!host_matched)
  753. return 0;
  754. if(ctl->mode & CONTEXTS_V2_FUNCTIONS) {
  755. struct function_v2_entry t = {
  756. .used = 1,
  757. .size = 1,
  758. .node_ids = &ctl->nodes.ni,
  759. .help = NULL,
  760. };
  761. host_functions_to_dict(host, ctl->functions.dict, &t, sizeof(t), &t.help);
  762. }
  763. if(ctl->mode & CONTEXTS_V2_NODES) {
  764. struct contexts_v2_node t = {
  765. .ni = ctl->nodes.ni++,
  766. .host = host,
  767. };
  768. dictionary_set(ctl->nodes.dict, host->machine_guid, &t, sizeof(struct contexts_v2_node));
  769. }
  770. return 1;
  771. }
  772. static void buffer_json_contexts_v2_mode_to_array(BUFFER *wb, const char *key, CONTEXTS_V2_MODE mode) {
  773. buffer_json_member_add_array(wb, key);
  774. if(mode & CONTEXTS_V2_VERSIONS)
  775. buffer_json_add_array_item_string(wb, "versions");
  776. if(mode & CONTEXTS_V2_AGENTS)
  777. buffer_json_add_array_item_string(wb, "agents");
  778. if(mode & CONTEXTS_V2_AGENTS_INFO)
  779. buffer_json_add_array_item_string(wb, "agents-info");
  780. if(mode & CONTEXTS_V2_NODES)
  781. buffer_json_add_array_item_string(wb, "nodes");
  782. if(mode & CONTEXTS_V2_NODES_INFO)
  783. buffer_json_add_array_item_string(wb, "nodes-info");
  784. if(mode & CONTEXTS_V2_NODE_INSTANCES)
  785. buffer_json_add_array_item_string(wb, "nodes-instances");
  786. if(mode & CONTEXTS_V2_CONTEXTS)
  787. buffer_json_add_array_item_string(wb, "contexts");
  788. if(mode & CONTEXTS_V2_SEARCH)
  789. buffer_json_add_array_item_string(wb, "search");
  790. if(mode & CONTEXTS_V2_ALERTS)
  791. buffer_json_add_array_item_string(wb, "alerts");
  792. if(mode & CONTEXTS_V2_ALERT_TRANSITIONS)
  793. buffer_json_add_array_item_string(wb, "alert_transitions");
  794. buffer_json_array_close(wb);
  795. }
  796. void buffer_json_query_timings(BUFFER *wb, const char *key, struct query_timings *timings) {
  797. timings->finished_ut = now_monotonic_usec();
  798. if(!timings->executed_ut)
  799. timings->executed_ut = timings->finished_ut;
  800. if(!timings->preprocessed_ut)
  801. timings->preprocessed_ut = timings->received_ut;
  802. buffer_json_member_add_object(wb, key);
  803. buffer_json_member_add_double(wb, "prep_ms", (NETDATA_DOUBLE)(timings->preprocessed_ut - timings->received_ut) / USEC_PER_MS);
  804. buffer_json_member_add_double(wb, "query_ms", (NETDATA_DOUBLE)(timings->executed_ut - timings->preprocessed_ut) / USEC_PER_MS);
  805. buffer_json_member_add_double(wb, "output_ms", (NETDATA_DOUBLE)(timings->finished_ut - timings->executed_ut) / USEC_PER_MS);
  806. buffer_json_member_add_double(wb, "total_ms", (NETDATA_DOUBLE)(timings->finished_ut - timings->received_ut) / USEC_PER_MS);
  807. buffer_json_member_add_double(wb, "cloud_ms", (NETDATA_DOUBLE)(timings->finished_ut - timings->received_ut) / USEC_PER_MS);
  808. buffer_json_object_close(wb);
  809. }
  810. void build_info_to_json_object(BUFFER *b);
  811. void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now_s, bool info, bool array) {
  812. if(!now_s)
  813. now_s = now_realtime_sec();
  814. if(array) {
  815. buffer_json_member_add_array(wb, "agents");
  816. buffer_json_add_array_item_object(wb);
  817. }
  818. else
  819. buffer_json_member_add_object(wb, "agent");
  820. buffer_json_member_add_string(wb, "mg", localhost->machine_guid);
  821. buffer_json_member_add_uuid(wb, "nd", localhost->node_id);
  822. buffer_json_member_add_string(wb, "nm", rrdhost_hostname(localhost));
  823. buffer_json_member_add_time_t(wb, "now", now_s);
  824. if(array)
  825. buffer_json_member_add_uint64(wb, "ai", 0);
  826. if(info) {
  827. buffer_json_member_add_object(wb, "application");
  828. build_info_to_json_object(wb);
  829. buffer_json_object_close(wb); // netdata
  830. buffer_json_cloud_status(wb, now_s);
  831. buffer_json_member_add_array(wb, "db_size");
  832. for (size_t tier = 0; tier < storage_tiers; tier++) {
  833. STORAGE_ENGINE *eng = localhost->db[tier].eng;
  834. if (!eng) continue;
  835. uint64_t max = storage_engine_disk_space_max(eng->backend, localhost->db[tier].instance);
  836. uint64_t used = storage_engine_disk_space_used(eng->backend, localhost->db[tier].instance);
  837. time_t first_time_s = storage_engine_global_first_time_s(eng->backend, localhost->db[tier].instance);
  838. size_t currently_collected_metrics = storage_engine_collected_metrics(eng->backend, localhost->db[tier].instance);
  839. NETDATA_DOUBLE percent;
  840. if (used && max)
  841. percent = (NETDATA_DOUBLE) used * 100.0 / (NETDATA_DOUBLE) max;
  842. else
  843. percent = 0.0;
  844. buffer_json_add_array_item_object(wb);
  845. buffer_json_member_add_uint64(wb, "tier", tier);
  846. if(used || max) {
  847. buffer_json_member_add_uint64(wb, "disk_used", used);
  848. buffer_json_member_add_uint64(wb, "disk_max", max);
  849. buffer_json_member_add_double(wb, "disk_percent", percent);
  850. }
  851. if(first_time_s) {
  852. buffer_json_member_add_time_t(wb, "from", first_time_s);
  853. buffer_json_member_add_time_t(wb, "to", now_s);
  854. buffer_json_member_add_time_t(wb, "retention", now_s - first_time_s);
  855. if(used || max) // we have disk space information
  856. buffer_json_member_add_time_t(wb, "expected_retention",
  857. (time_t) ((NETDATA_DOUBLE) (now_s - first_time_s) * 100.0 / percent));
  858. }
  859. if(currently_collected_metrics)
  860. buffer_json_member_add_uint64(wb, "currently_collected_metrics", currently_collected_metrics);
  861. buffer_json_object_close(wb);
  862. }
  863. buffer_json_array_close(wb); // db_size
  864. }
  865. if(timings)
  866. buffer_json_query_timings(wb, "timings", timings);
  867. buffer_json_object_close(wb);
  868. if(array)
  869. buffer_json_array_close(wb);
  870. }
  871. void buffer_json_cloud_timings(BUFFER *wb, const char *key, struct query_timings *timings) {
  872. if(!timings->finished_ut)
  873. timings->finished_ut = now_monotonic_usec();
  874. buffer_json_member_add_object(wb, key);
  875. buffer_json_member_add_double(wb, "routing_ms", 0.0);
  876. buffer_json_member_add_double(wb, "node_max_ms", 0.0);
  877. buffer_json_member_add_double(wb, "total_ms", (NETDATA_DOUBLE)(timings->finished_ut - timings->received_ut) / USEC_PER_MS);
  878. buffer_json_object_close(wb);
  879. }
  880. static void functions_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
  881. struct function_v2_entry *t = value;
  882. // it is initialized with a static reference - we need to mallocz() the array
  883. size_t *v = t->node_ids;
  884. t->node_ids = mallocz(sizeof(size_t));
  885. *t->node_ids = *v;
  886. t->size = 1;
  887. t->used = 1;
  888. }
  889. static bool functions_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused) {
  890. struct function_v2_entry *t = old_value, *n = new_value;
  891. size_t *v = n->node_ids;
  892. if(t->used >= t->size) {
  893. t->node_ids = reallocz(t->node_ids, t->size * 2 * sizeof(size_t));
  894. t->size *= 2;
  895. }
  896. t->node_ids[t->used++] = *v;
  897. return true;
  898. }
  899. static void functions_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
  900. struct function_v2_entry *t = value;
  901. freez(t->node_ids);
  902. }
  903. static bool contexts_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused) {
  904. struct context_v2_entry *o = old_value;
  905. struct context_v2_entry *n = new_value;
  906. o->count++;
  907. if(o->family != n->family) {
  908. if((o->flags & RRD_FLAG_COLLECTED) && !(n->flags & RRD_FLAG_COLLECTED))
  909. // keep old
  910. ;
  911. else if(!(o->flags & RRD_FLAG_COLLECTED) && (n->flags & RRD_FLAG_COLLECTED)) {
  912. // keep new
  913. string_freez(o->family);
  914. o->family = string_dup(n->family);
  915. }
  916. else {
  917. // merge
  918. STRING *old_family = o->family;
  919. o->family = string_2way_merge(o->family, n->family);
  920. string_freez(old_family);
  921. }
  922. }
  923. if(o->priority != n->priority) {
  924. if((o->flags & RRD_FLAG_COLLECTED) && !(n->flags & RRD_FLAG_COLLECTED))
  925. // keep o
  926. ;
  927. else if(!(o->flags & RRD_FLAG_COLLECTED) && (n->flags & RRD_FLAG_COLLECTED))
  928. // keep n
  929. o->priority = n->priority;
  930. else
  931. // keep the min
  932. o->priority = MIN(o->priority, n->priority);
  933. }
  934. if(o->first_time_s && n->first_time_s)
  935. o->first_time_s = MIN(o->first_time_s, n->first_time_s);
  936. else if(!o->first_time_s)
  937. o->first_time_s = n->first_time_s;
  938. if(o->last_time_s && n->last_time_s)
  939. o->last_time_s = MAX(o->last_time_s, n->last_time_s);
  940. else if(!o->last_time_s)
  941. o->last_time_s = n->last_time_s;
  942. o->flags |= n->flags;
  943. o->match = MIN(o->match, n->match);
  944. string_freez(n->family);
  945. return true;
  946. }
  947. static void contexts_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
  948. struct context_v2_entry *z = value;
  949. string_freez(z->family);
  950. }
  951. static void rrdcontext_v2_set_transition_filter(const char *machine_guid, const char *context, time_t alarm_id, void *data) {
  952. struct rrdcontext_to_json_v2_data *ctl = data;
  953. if(machine_guid && *machine_guid) {
  954. if(ctl->nodes.scope_pattern)
  955. simple_pattern_free(ctl->nodes.scope_pattern);
  956. if(ctl->nodes.pattern)
  957. simple_pattern_free(ctl->nodes.pattern);
  958. ctl->nodes.scope_pattern = string_to_simple_pattern(machine_guid);
  959. ctl->nodes.pattern = NULL;
  960. }
  961. if(context && *context) {
  962. if(ctl->contexts.scope_pattern)
  963. simple_pattern_free(ctl->contexts.scope_pattern);
  964. if(ctl->contexts.pattern)
  965. simple_pattern_free(ctl->contexts.pattern);
  966. ctl->contexts.scope_pattern = string_to_simple_pattern(context);
  967. ctl->contexts.pattern = NULL;
  968. }
  969. ctl->alerts.alarm_id_filter = alarm_id;
  970. }
  971. struct alert_instances_callback_data {
  972. BUFFER *wb;
  973. struct rrdcontext_to_json_v2_data *ctl;
  974. bool debug;
  975. };
  976. static void contexts_v2_alert_config_to_json_from_sql_alert_config_data(struct sql_alert_config_data *t, void *data) {
  977. struct alert_transitions_callback_data *d = data;
  978. BUFFER *wb = d->wb;
  979. bool debug = d->debug;
  980. d->configs_added++;
  981. if(d->only_one_config)
  982. buffer_json_add_array_item_object(wb); // alert config
  983. {
  984. buffer_json_member_add_string(wb, "name", t->name);
  985. buffer_json_member_add_uuid(wb, "config_hash_id", t->config_hash_id);
  986. buffer_json_member_add_object(wb, "selectors");
  987. {
  988. bool is_template = t->selectors.on_template && *t->selectors.on_template ? true : false;
  989. buffer_json_member_add_string(wb, "type", is_template ? "template" : "alarm");
  990. buffer_json_member_add_string(wb, "on", is_template ? t->selectors.on_template : t->selectors.on_key);
  991. buffer_json_member_add_string(wb, "os", t->selectors.os);
  992. buffer_json_member_add_string(wb, "hosts", t->selectors.hosts);
  993. buffer_json_member_add_string(wb, "families", t->selectors.families);
  994. buffer_json_member_add_string(wb, "plugin", t->selectors.plugin);
  995. buffer_json_member_add_string(wb, "module", t->selectors.module);
  996. buffer_json_member_add_string(wb, "host_labels", t->selectors.host_labels);
  997. buffer_json_member_add_string(wb, "chart_labels", t->selectors.chart_labels);
  998. buffer_json_member_add_string(wb, "charts", t->selectors.charts);
  999. }
  1000. buffer_json_object_close(wb); // selectors
  1001. buffer_json_member_add_object(wb, "value"); // value
  1002. {
  1003. // buffer_json_member_add_string(wb, "every", t->value.every); // does not exist in Netdata Cloud
  1004. buffer_json_member_add_string(wb, "units", t->value.units);
  1005. buffer_json_member_add_uint64(wb, "update_every", t->value.update_every);
  1006. if (t->value.db.after || debug) {
  1007. buffer_json_member_add_object(wb, "db");
  1008. {
  1009. // buffer_json_member_add_string(wb, "lookup", t->value.db.lookup); // does not exist in Netdata Cloud
  1010. buffer_json_member_add_time_t(wb, "after", t->value.db.after);
  1011. buffer_json_member_add_time_t(wb, "before", t->value.db.before);
  1012. buffer_json_member_add_string(wb, "method", t->value.db.method);
  1013. buffer_json_member_add_string(wb, "dimensions", t->value.db.dimensions);
  1014. web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options",(RRDR_OPTIONS) t->value.db.options);
  1015. }
  1016. buffer_json_object_close(wb); // db
  1017. }
  1018. if (t->value.calc || debug)
  1019. buffer_json_member_add_string(wb, "calc", t->value.calc);
  1020. }
  1021. buffer_json_object_close(wb); // value
  1022. if (t->status.warn || t->status.crit || debug) {
  1023. buffer_json_member_add_object(wb, "status"); // status
  1024. {
  1025. NETDATA_DOUBLE green = t->status.green ? str2ndd(t->status.green, NULL) : NAN;
  1026. NETDATA_DOUBLE red = t->status.red ? str2ndd(t->status.red, NULL) : NAN;
  1027. if (!isnan(green) || debug)
  1028. buffer_json_member_add_double(wb, "green", green);
  1029. if (!isnan(red) || debug)
  1030. buffer_json_member_add_double(wb, "red", red);
  1031. if (t->status.warn || debug)
  1032. buffer_json_member_add_string(wb, "warn", t->status.warn);
  1033. if (t->status.crit || debug)
  1034. buffer_json_member_add_string(wb, "crit", t->status.crit);
  1035. }
  1036. buffer_json_object_close(wb); // status
  1037. }
  1038. buffer_json_member_add_object(wb, "notification");
  1039. {
  1040. buffer_json_member_add_string(wb, "type", "agent");
  1041. buffer_json_member_add_string(wb, "exec", t->notification.exec ? t->notification.exec : NULL);
  1042. buffer_json_member_add_string(wb, "to", t->notification.to_key ? t->notification.to_key : string2str(localhost->health.health_default_recipient));
  1043. buffer_json_member_add_string(wb, "delay", t->notification.delay);
  1044. buffer_json_member_add_string(wb, "repeat", t->notification.repeat);
  1045. buffer_json_member_add_string(wb, "options", t->notification.options);
  1046. }
  1047. buffer_json_object_close(wb); // notification
  1048. buffer_json_member_add_string(wb, "class", t->classification);
  1049. buffer_json_member_add_string(wb, "component", t->component);
  1050. buffer_json_member_add_string(wb, "type", t->type);
  1051. buffer_json_member_add_string(wb, "info", t->info);
  1052. buffer_json_member_add_string(wb, "summary", t->summary);
  1053. // buffer_json_member_add_string(wb, "source", t->source); // moved to alert instance
  1054. }
  1055. if(d->only_one_config)
  1056. buffer_json_object_close(wb);
  1057. }
  1058. int contexts_v2_alert_config_to_json(struct web_client *w, const char *config_hash_id) {
  1059. struct alert_transitions_callback_data data = {
  1060. .wb = w->response.data,
  1061. .debug = false,
  1062. .only_one_config = false,
  1063. };
  1064. DICTIONARY *configs = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
  1065. dictionary_set(configs, config_hash_id, NULL, 0);
  1066. buffer_flush(w->response.data);
  1067. buffer_json_initialize(w->response.data, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
  1068. int added = sql_get_alert_configuration(configs, contexts_v2_alert_config_to_json_from_sql_alert_config_data, &data, false);
  1069. buffer_json_finalize(w->response.data);
  1070. int ret = HTTP_RESP_OK;
  1071. if(added <= 0) {
  1072. buffer_flush(w->response.data);
  1073. w->response.data->content_type = CT_TEXT_PLAIN;
  1074. if(added < 0) {
  1075. buffer_strcat(w->response.data, "Failed to execute SQL query.");
  1076. ret = HTTP_RESP_INTERNAL_SERVER_ERROR;
  1077. }
  1078. else {
  1079. buffer_strcat(w->response.data, "Config is not found.");
  1080. ret = HTTP_RESP_NOT_FOUND;
  1081. }
  1082. }
  1083. return ret;
  1084. }
  1085. static int contexts_v2_alert_instance_to_json_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data) {
  1086. struct sql_alert_instance_v2_entry *t = value;
  1087. struct alert_instances_callback_data *d = data;
  1088. struct rrdcontext_to_json_v2_data *ctl = d->ctl; (void)ctl;
  1089. bool debug = d->debug; (void)debug;
  1090. BUFFER *wb = d->wb;
  1091. buffer_json_add_array_item_object(wb);
  1092. {
  1093. buffer_json_member_add_uint64(wb, "ni", t->ni);
  1094. buffer_json_member_add_string(wb, "nm", string2str(t->name));
  1095. buffer_json_member_add_string(wb, "ch", string2str(t->chart_id));
  1096. buffer_json_member_add_string(wb, "ch_n", string2str(t->chart_name));
  1097. if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY)
  1098. buffer_json_member_add_uint64(wb, "ati", t->ati);
  1099. if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES) {
  1100. buffer_json_member_add_string(wb, "units", string2str(t->units));
  1101. buffer_json_member_add_string(wb, "fami", string2str(t->family));
  1102. buffer_json_member_add_string(wb, "info", string2str(t->info));
  1103. buffer_json_member_add_string(wb, "sum", string2str(t->summary));
  1104. buffer_json_member_add_string(wb, "ctx", string2str(t->context));
  1105. buffer_json_member_add_string(wb, "st", rrdcalc_status2string(t->status));
  1106. buffer_json_member_add_uuid(wb, "tr_i", &t->last_transition_id);
  1107. buffer_json_member_add_double(wb, "tr_v", t->last_status_change_value);
  1108. buffer_json_member_add_time_t(wb, "tr_t", t->last_status_change);
  1109. buffer_json_member_add_uuid(wb, "cfg", &t->config_hash_id);
  1110. buffer_json_member_add_string(wb, "src", string2str(t->source));
  1111. buffer_json_member_add_string(wb, "to", string2str(t->recipient));
  1112. buffer_json_member_add_string(wb, "tp", string2str(t->type));
  1113. buffer_json_member_add_string(wb, "cm", string2str(t->component));
  1114. buffer_json_member_add_string(wb, "cl", string2str(t->classification));
  1115. // Agent specific fields
  1116. buffer_json_member_add_uint64(wb, "gi", t->global_id);
  1117. // rrdcalc_flags_to_json_array (wb, "flags", t->flags);
  1118. }
  1119. if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_VALUES) {
  1120. // Netdata Cloud fetched these by querying the agents
  1121. buffer_json_member_add_double(wb, "v", t->value);
  1122. buffer_json_member_add_time_t(wb, "t", t->last_updated);
  1123. }
  1124. }
  1125. buffer_json_object_close(wb); // alert instance
  1126. return 1;
  1127. }
  1128. static void contexts_v2_alert_instances_to_json(BUFFER *wb, const char *key, struct rrdcontext_to_json_v2_data *ctl, bool debug) {
  1129. buffer_json_member_add_array(wb, key);
  1130. {
  1131. struct alert_instances_callback_data data = {
  1132. .wb = wb,
  1133. .ctl = ctl,
  1134. .debug = debug,
  1135. };
  1136. dictionary_walkthrough_rw(ctl->alerts.alert_instances, DICTIONARY_LOCK_READ,
  1137. contexts_v2_alert_instance_to_json_callback, &data);
  1138. }
  1139. buffer_json_array_close(wb); // alerts_instances
  1140. }
  1141. static void contexts_v2_alerts_to_json(BUFFER *wb, struct rrdcontext_to_json_v2_data *ctl, bool debug) {
  1142. if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY) {
  1143. buffer_json_member_add_array(wb, "alerts");
  1144. {
  1145. struct alert_v2_entry *t;
  1146. dfe_start_read(ctl->alerts.alerts, t)
  1147. {
  1148. buffer_json_add_array_item_object(wb);
  1149. {
  1150. buffer_json_member_add_uint64(wb, "ati", t->ati);
  1151. buffer_json_member_add_string(wb, "nm", string2str(t->name));
  1152. buffer_json_member_add_string(wb, "sum", string2str(t->summary));
  1153. buffer_json_member_add_uint64(wb, "cr", t->critical);
  1154. buffer_json_member_add_uint64(wb, "wr", t->warning);
  1155. buffer_json_member_add_uint64(wb, "cl", t->clear);
  1156. buffer_json_member_add_uint64(wb, "er", t->error);
  1157. buffer_json_member_add_uint64(wb, "in", t->instances);
  1158. buffer_json_member_add_uint64(wb, "nd", dictionary_entries(t->nodes));
  1159. buffer_json_member_add_uint64(wb, "cfg", dictionary_entries(t->configs));
  1160. }
  1161. buffer_json_object_close(wb); // alert name
  1162. }
  1163. dfe_done(t);
  1164. }
  1165. buffer_json_array_close(wb); // alerts
  1166. }
  1167. if(ctl->request->options & (CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES|CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)) {
  1168. contexts_v2_alert_instances_to_json(wb, "alert_instances", ctl, debug);
  1169. }
  1170. }
  1171. #define SQL_TRANSITION_DATA_SMALL_STRING (6 * 8)
  1172. #define SQL_TRANSITION_DATA_MEDIUM_STRING (12 * 8)
  1173. #define SQL_TRANSITION_DATA_BIG_STRING 512
  1174. struct sql_alert_transition_fixed_size {
  1175. usec_t global_id;
  1176. uuid_t transition_id;
  1177. uuid_t host_id;
  1178. uuid_t config_hash_id;
  1179. uint32_t alarm_id;
  1180. char alert_name[SQL_TRANSITION_DATA_SMALL_STRING];
  1181. char chart[RRD_ID_LENGTH_MAX];
  1182. char chart_name[RRD_ID_LENGTH_MAX];
  1183. char chart_context[SQL_TRANSITION_DATA_MEDIUM_STRING];
  1184. char family[SQL_TRANSITION_DATA_SMALL_STRING];
  1185. char recipient[SQL_TRANSITION_DATA_MEDIUM_STRING];
  1186. char units[SQL_TRANSITION_DATA_SMALL_STRING];
  1187. char exec[SQL_TRANSITION_DATA_BIG_STRING];
  1188. char info[SQL_TRANSITION_DATA_BIG_STRING];
  1189. char summary[SQL_TRANSITION_DATA_BIG_STRING];
  1190. char classification[SQL_TRANSITION_DATA_SMALL_STRING];
  1191. char type[SQL_TRANSITION_DATA_SMALL_STRING];
  1192. char component[SQL_TRANSITION_DATA_SMALL_STRING];
  1193. time_t when_key;
  1194. time_t duration;
  1195. time_t non_clear_duration;
  1196. uint64_t flags;
  1197. time_t delay_up_to_timestamp;
  1198. time_t exec_run_timestamp;
  1199. int exec_code;
  1200. int new_status;
  1201. int old_status;
  1202. int delay;
  1203. time_t last_repeat;
  1204. NETDATA_DOUBLE new_value;
  1205. NETDATA_DOUBLE old_value;
  1206. char machine_guid[UUID_STR_LEN];
  1207. struct sql_alert_transition_fixed_size *next;
  1208. struct sql_alert_transition_fixed_size *prev;
  1209. };
  1210. static struct sql_alert_transition_fixed_size *contexts_v2_alert_transition_dup(struct sql_alert_transition_data *t, const char *machine_guid, struct sql_alert_transition_fixed_size *dst) {
  1211. struct sql_alert_transition_fixed_size *n = dst ? dst : mallocz(sizeof(*n));
  1212. n->global_id = t->global_id;
  1213. uuid_copy(n->transition_id, *t->transition_id);
  1214. uuid_copy(n->host_id, *t->host_id);
  1215. uuid_copy(n->config_hash_id, *t->config_hash_id);
  1216. n->alarm_id = t->alarm_id;
  1217. strncpyz(n->alert_name, t->alert_name ? t->alert_name : "", sizeof(n->alert_name) - 1);
  1218. strncpyz(n->chart, t->chart ? t->chart : "", sizeof(n->chart) - 1);
  1219. strncpyz(n->chart_name, t->chart_name ? t->chart_name : n->chart, sizeof(n->chart_name) - 1);
  1220. strncpyz(n->chart_context, t->chart_context ? t->chart_context : "", sizeof(n->chart_context) - 1);
  1221. strncpyz(n->family, t->family ? t->family : "", sizeof(n->family) - 1);
  1222. strncpyz(n->recipient, t->recipient ? t->recipient : "", sizeof(n->recipient) - 1);
  1223. strncpyz(n->units, t->units ? t->units : "", sizeof(n->units) - 1);
  1224. strncpyz(n->exec, t->exec ? t->exec : "", sizeof(n->exec) - 1);
  1225. strncpyz(n->info, t->info ? t->info : "", sizeof(n->info) - 1);
  1226. strncpyz(n->summary, t->summary ? t->summary : "", sizeof(n->summary) - 1);
  1227. strncpyz(n->classification, t->classification ? t->classification : "", sizeof(n->classification) - 1);
  1228. strncpyz(n->type, t->type ? t->type : "", sizeof(n->type) - 1);
  1229. strncpyz(n->component, t->component ? t->component : "", sizeof(n->component) - 1);
  1230. n->when_key = t->when_key;
  1231. n->duration = t->duration;
  1232. n->non_clear_duration = t->non_clear_duration;
  1233. n->flags = t->flags;
  1234. n->delay_up_to_timestamp = t->delay_up_to_timestamp;
  1235. n->exec_run_timestamp = t->exec_run_timestamp;
  1236. n->exec_code = t->exec_code;
  1237. n->new_status = t->new_status;
  1238. n->old_status = t->old_status;
  1239. n->delay = t->delay;
  1240. n->last_repeat = t->last_repeat;
  1241. n->new_value = t->new_value;
  1242. n->old_value = t->old_value;
  1243. memcpy(n->machine_guid, machine_guid, sizeof(n->machine_guid));
  1244. n->next = n->prev = NULL;
  1245. return n;
  1246. }
  1247. static void contexts_v2_alert_transition_free(struct sql_alert_transition_fixed_size *t) {
  1248. freez(t);
  1249. }
  1250. static inline void contexts_v2_alert_transition_keep(struct alert_transitions_callback_data *d, struct sql_alert_transition_data *t, const char *machine_guid) {
  1251. d->items_matched++;
  1252. if(unlikely(t->global_id <= d->ctl->request->alerts.global_id_anchor)) {
  1253. // this is in our past, we are not interested
  1254. d->operations.skips_before++;
  1255. return;
  1256. }
  1257. if(unlikely(!d->base)) {
  1258. d->last_added = contexts_v2_alert_transition_dup(t, machine_guid, NULL);
  1259. DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(d->base, d->last_added, prev, next);
  1260. d->items_to_return++;
  1261. d->operations.first++;
  1262. return;
  1263. }
  1264. struct sql_alert_transition_fixed_size *last = d->last_added;
  1265. while(last->prev != d->base->prev && t->global_id > last->prev->global_id) {
  1266. last = last->prev;
  1267. d->operations.backwards++;
  1268. }
  1269. while(last->next && t->global_id < last->next->global_id) {
  1270. last = last->next;
  1271. d->operations.forwards++;
  1272. }
  1273. if(d->items_to_return >= d->max_items_to_return) {
  1274. if(last == d->base->prev && t->global_id < last->global_id) {
  1275. d->operations.skips_after++;
  1276. return;
  1277. }
  1278. }
  1279. d->items_to_return++;
  1280. if(t->global_id > last->global_id) {
  1281. if(d->items_to_return > d->max_items_to_return) {
  1282. d->items_to_return--;
  1283. d->operations.shifts++;
  1284. d->last_added = d->base->prev;
  1285. DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(d->base, d->last_added, prev, next);
  1286. d->last_added = contexts_v2_alert_transition_dup(t, machine_guid, d->last_added);
  1287. }
  1288. DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(d->base, d->last_added, prev, next);
  1289. d->operations.prepend++;
  1290. }
  1291. else {
  1292. d->last_added = contexts_v2_alert_transition_dup(t, machine_guid, NULL);
  1293. DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(d->base, d->last_added, prev, next);
  1294. d->operations.append++;
  1295. }
  1296. while(d->items_to_return > d->max_items_to_return) {
  1297. // we have to remove something
  1298. struct sql_alert_transition_fixed_size *tmp = d->base->prev;
  1299. DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(d->base, tmp, prev, next);
  1300. d->items_to_return--;
  1301. if(unlikely(d->last_added == tmp))
  1302. d->last_added = d->base;
  1303. contexts_v2_alert_transition_free(tmp);
  1304. d->operations.shifts++;
  1305. }
  1306. }
  1307. static void contexts_v2_alert_transition_callback(struct sql_alert_transition_data *t, void *data) {
  1308. struct alert_transitions_callback_data *d = data;
  1309. d->items_evaluated++;
  1310. char machine_guid[UUID_STR_LEN] = "";
  1311. uuid_unparse_lower(*t->host_id, machine_guid);
  1312. const char *facets[ATF_TOTAL_ENTRIES] = {
  1313. [ATF_STATUS] = rrdcalc_status2string(t->new_status),
  1314. [ATF_CLASS] = t->classification,
  1315. [ATF_TYPE] = t->type,
  1316. [ATF_COMPONENT] = t->component,
  1317. [ATF_ROLE] = t->recipient && *t->recipient ? t->recipient : string2str(localhost->health.health_default_recipient),
  1318. [ATF_NODE] = machine_guid,
  1319. [ATF_ALERT_NAME] = t->alert_name,
  1320. [ATF_CHART_NAME] = t->chart_name,
  1321. [ATF_CONTEXT] = t->chart_context,
  1322. };
  1323. for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
  1324. if (!facets[i] || !*facets[i]) facets[i] = "unknown";
  1325. struct facet_entry tmp = {
  1326. .count = 0,
  1327. };
  1328. dictionary_set(d->facets[i].dict, facets[i], &tmp, sizeof(tmp));
  1329. }
  1330. bool selected[ATF_TOTAL_ENTRIES] = { 0 };
  1331. uint32_t selected_by = 0;
  1332. for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
  1333. selected[i] = !d->facets[i].pattern || simple_pattern_matches(d->facets[i].pattern, facets[i]);
  1334. if(selected[i])
  1335. selected_by++;
  1336. }
  1337. if(selected_by == ATF_TOTAL_ENTRIES) {
  1338. // this item is selected by all facets
  1339. // put it in our result (if it fits)
  1340. contexts_v2_alert_transition_keep(d, t, machine_guid);
  1341. }
  1342. if(selected_by >= ATF_TOTAL_ENTRIES - 1) {
  1343. // this item is selected by all, or all except one facet
  1344. // in both cases we need to add it to our counters
  1345. for (size_t i = 0; i < ATF_TOTAL_ENTRIES; i++) {
  1346. uint32_t counted_by = selected_by;
  1347. if (counted_by != ATF_TOTAL_ENTRIES) {
  1348. counted_by = 0;
  1349. for (size_t j = 0; j < ATF_TOTAL_ENTRIES; j++) {
  1350. if (i == j || selected[j])
  1351. counted_by++;
  1352. }
  1353. }
  1354. if (counted_by == ATF_TOTAL_ENTRIES) {
  1355. // we need to count it on this facet
  1356. struct facet_entry *x = dictionary_get(d->facets[i].dict, facets[i]);
  1357. internal_fatal(!x, "facet is not found");
  1358. if(x)
  1359. x->count++;
  1360. }
  1361. }
  1362. }
  1363. }
  1364. static void contexts_v2_alert_transitions_to_json(BUFFER *wb, struct rrdcontext_to_json_v2_data *ctl, bool debug) {
  1365. struct alert_transitions_callback_data data = {
  1366. .wb = wb,
  1367. .ctl = ctl,
  1368. .debug = debug,
  1369. .only_one_config = true,
  1370. .max_items_to_return = ctl->request->alerts.last,
  1371. .items_to_return = 0,
  1372. .base = NULL,
  1373. };
  1374. for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
  1375. data.facets[i].dict = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(struct facet_entry));
  1376. if(ctl->request->alerts.facets[i])
  1377. data.facets[i].pattern = simple_pattern_create(ctl->request->alerts.facets[i], ",|", SIMPLE_PATTERN_EXACT, false);
  1378. }
  1379. sql_alert_transitions(
  1380. ctl->nodes.dict,
  1381. ctl->window.after,
  1382. ctl->window.before,
  1383. ctl->request->contexts,
  1384. ctl->request->alerts.alert,
  1385. ctl->request->alerts.transition,
  1386. contexts_v2_alert_transition_callback,
  1387. &data,
  1388. debug);
  1389. buffer_json_member_add_array(wb, "facets");
  1390. for (size_t i = 0; i < ATF_TOTAL_ENTRIES; i++) {
  1391. buffer_json_add_array_item_object(wb);
  1392. {
  1393. buffer_json_member_add_string(wb, "id", alert_transition_facets[i].id);
  1394. buffer_json_member_add_string(wb, "name", alert_transition_facets[i].name);
  1395. buffer_json_member_add_uint64(wb, "order", alert_transition_facets[i].order);
  1396. buffer_json_member_add_array(wb, "options");
  1397. {
  1398. struct facet_entry *x;
  1399. dfe_start_read(data.facets[i].dict, x) {
  1400. buffer_json_add_array_item_object(wb);
  1401. {
  1402. buffer_json_member_add_string(wb, "id", x_dfe.name);
  1403. if (i == ATF_NODE) {
  1404. RRDHOST *host = rrdhost_find_by_guid(x_dfe.name);
  1405. if (host)
  1406. buffer_json_member_add_string(wb, "name", rrdhost_hostname(host));
  1407. else
  1408. buffer_json_member_add_string(wb, "name", x_dfe.name);
  1409. } else
  1410. buffer_json_member_add_string(wb, "name", x_dfe.name);
  1411. buffer_json_member_add_uint64(wb, "count", x->count);
  1412. }
  1413. buffer_json_object_close(wb);
  1414. }
  1415. dfe_done(x);
  1416. }
  1417. buffer_json_array_close(wb); // options
  1418. }
  1419. buffer_json_object_close(wb); // facet
  1420. }
  1421. buffer_json_array_close(wb); // facets
  1422. buffer_json_member_add_array(wb, "transitions");
  1423. for(struct sql_alert_transition_fixed_size *t = data.base; t ; t = t->next) {
  1424. buffer_json_add_array_item_object(wb);
  1425. {
  1426. RRDHOST *host = rrdhost_find_by_guid(t->machine_guid);
  1427. buffer_json_member_add_uint64(wb, "gi", t->global_id);
  1428. buffer_json_member_add_uuid(wb, "transition_id", &t->transition_id);
  1429. buffer_json_member_add_uuid(wb, "config_hash_id", &t->config_hash_id);
  1430. buffer_json_member_add_string(wb, "machine_guid", t->machine_guid);
  1431. if(host) {
  1432. buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(host));
  1433. if(host->node_id)
  1434. buffer_json_member_add_uuid(wb, "node_id", host->node_id);
  1435. }
  1436. buffer_json_member_add_string(wb, "alert", *t->alert_name ? t->alert_name : NULL);
  1437. buffer_json_member_add_string(wb, "instance", *t->chart ? t->chart : NULL);
  1438. buffer_json_member_add_string(wb, "instance_n", *t->chart_name ? t->chart_name : NULL);
  1439. buffer_json_member_add_string(wb, "context", *t->chart_context ? t->chart_context : NULL);
  1440. // buffer_json_member_add_string(wb, "family", *t->family ? t->family : NULL);
  1441. buffer_json_member_add_string(wb, "component", *t->component ? t->component : NULL);
  1442. buffer_json_member_add_string(wb, "classification", *t->classification ? t->classification : NULL);
  1443. buffer_json_member_add_string(wb, "type", *t->type ? t->type : NULL);
  1444. buffer_json_member_add_time_t(wb, "when", t->when_key);
  1445. buffer_json_member_add_string(wb, "info", *t->info ? t->info : "");
  1446. buffer_json_member_add_string(wb, "summary", *t->summary ? t->summary : "");
  1447. buffer_json_member_add_string(wb, "units", *t->units ? t->units : NULL);
  1448. buffer_json_member_add_object(wb, "new");
  1449. {
  1450. buffer_json_member_add_string(wb, "status", rrdcalc_status2string(t->new_status));
  1451. buffer_json_member_add_double(wb, "value", t->new_value);
  1452. }
  1453. buffer_json_object_close(wb); // new
  1454. buffer_json_member_add_object(wb, "old");
  1455. {
  1456. buffer_json_member_add_string(wb, "status", rrdcalc_status2string(t->old_status));
  1457. buffer_json_member_add_double(wb, "value", t->old_value);
  1458. buffer_json_member_add_time_t(wb, "duration", t->duration);
  1459. buffer_json_member_add_time_t(wb, "raised_duration", t->non_clear_duration);
  1460. }
  1461. buffer_json_object_close(wb); // old
  1462. buffer_json_member_add_object(wb, "notification");
  1463. {
  1464. buffer_json_member_add_time_t(wb, "when", t->exec_run_timestamp);
  1465. buffer_json_member_add_time_t(wb, "delay", t->delay);
  1466. buffer_json_member_add_time_t(wb, "delay_up_to_time", t->delay_up_to_timestamp);
  1467. health_entry_flags_to_json_array(wb, "flags", t->flags);
  1468. buffer_json_member_add_string(wb, "exec", *t->exec ? t->exec : string2str(localhost->health.health_default_exec));
  1469. buffer_json_member_add_uint64(wb, "exec_code", t->exec_code);
  1470. buffer_json_member_add_string(wb, "to", *t->recipient ? t->recipient : string2str(localhost->health.health_default_recipient));
  1471. }
  1472. buffer_json_object_close(wb); // notification
  1473. }
  1474. buffer_json_object_close(wb); // a transition
  1475. }
  1476. buffer_json_array_close(wb); // all transitions
  1477. if(ctl->options & CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS) {
  1478. DICTIONARY *configs = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
  1479. for(struct sql_alert_transition_fixed_size *t = data.base; t ; t = t->next) {
  1480. char guid[UUID_STR_LEN];
  1481. uuid_unparse_lower(t->config_hash_id, guid);
  1482. dictionary_set(configs, guid, NULL, 0);
  1483. }
  1484. buffer_json_member_add_array(wb, "configurations");
  1485. sql_get_alert_configuration(configs, contexts_v2_alert_config_to_json_from_sql_alert_config_data, &data, debug);
  1486. buffer_json_array_close(wb);
  1487. dictionary_destroy(configs);
  1488. }
  1489. while(data.base) {
  1490. struct sql_alert_transition_fixed_size *t = data.base;
  1491. DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(data.base, t, prev, next);
  1492. contexts_v2_alert_transition_free(t);
  1493. }
  1494. for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
  1495. dictionary_destroy(data.facets[i].dict);
  1496. simple_pattern_free(data.facets[i].pattern);
  1497. }
  1498. buffer_json_member_add_object(wb, "items");
  1499. {
  1500. // all the items in the window, under the scope_nodes, ignoring the facets (filters)
  1501. buffer_json_member_add_uint64(wb, "evaluated", data.items_evaluated);
  1502. // all the items matching the query (if you didn't put anchor_gi and last, these are all the items you would get back)
  1503. buffer_json_member_add_uint64(wb, "matched", data.items_matched);
  1504. // the items included in this response
  1505. buffer_json_member_add_uint64(wb, "returned", data.items_to_return);
  1506. // same as last=X parameter
  1507. buffer_json_member_add_uint64(wb, "max_to_return", data.max_items_to_return);
  1508. // items before the first returned, this should be 0 if anchor_gi is not set
  1509. buffer_json_member_add_uint64(wb, "before", data.operations.skips_before);
  1510. // items after the last returned, when this is zero there aren't any items after the current list
  1511. buffer_json_member_add_uint64(wb, "after", data.operations.skips_after + data.operations.shifts);
  1512. }
  1513. buffer_json_object_close(wb); // items
  1514. if(debug) {
  1515. buffer_json_member_add_object(wb, "stats");
  1516. {
  1517. buffer_json_member_add_uint64(wb, "first", data.operations.first);
  1518. buffer_json_member_add_uint64(wb, "prepend", data.operations.prepend);
  1519. buffer_json_member_add_uint64(wb, "append", data.operations.append);
  1520. buffer_json_member_add_uint64(wb, "backwards", data.operations.backwards);
  1521. buffer_json_member_add_uint64(wb, "forwards", data.operations.forwards);
  1522. buffer_json_member_add_uint64(wb, "shifts", data.operations.shifts);
  1523. buffer_json_member_add_uint64(wb, "skips_before", data.operations.skips_before);
  1524. buffer_json_member_add_uint64(wb, "skips_after", data.operations.skips_after);
  1525. }
  1526. buffer_json_object_close(wb);
  1527. }
  1528. }
  1529. int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTEXTS_V2_MODE mode) {
  1530. int resp = HTTP_RESP_OK;
  1531. bool run = true;
  1532. if(mode & CONTEXTS_V2_SEARCH)
  1533. mode |= CONTEXTS_V2_CONTEXTS;
  1534. if(mode & (CONTEXTS_V2_AGENTS_INFO))
  1535. mode |= CONTEXTS_V2_AGENTS;
  1536. if(mode & (CONTEXTS_V2_FUNCTIONS | CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_NODES_INFO | CONTEXTS_V2_NODE_INSTANCES))
  1537. mode |= CONTEXTS_V2_NODES;
  1538. if(mode & CONTEXTS_V2_ALERTS) {
  1539. mode |= CONTEXTS_V2_NODES;
  1540. req->options &= ~CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS;
  1541. if(!(req->options & (CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY|CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES|CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)))
  1542. req->options |= CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY;
  1543. }
  1544. if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
  1545. mode |= CONTEXTS_V2_NODES;
  1546. req->options &= ~CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES;
  1547. }
  1548. struct rrdcontext_to_json_v2_data ctl = {
  1549. .wb = wb,
  1550. .request = req,
  1551. .mode = mode,
  1552. .options = req->options,
  1553. .versions = { 0 },
  1554. .nodes.scope_pattern = string_to_simple_pattern(req->scope_nodes),
  1555. .nodes.pattern = string_to_simple_pattern(req->nodes),
  1556. .contexts.pattern = string_to_simple_pattern(req->contexts),
  1557. .contexts.scope_pattern = string_to_simple_pattern(req->scope_contexts),
  1558. .q.pattern = string_to_simple_pattern_nocase(req->q),
  1559. .alerts.alert_name_pattern = string_to_simple_pattern(req->alerts.alert),
  1560. .window = {
  1561. .enabled = false,
  1562. .relative = false,
  1563. .after = req->after,
  1564. .before = req->before,
  1565. },
  1566. .timings = {
  1567. .received_ut = now_monotonic_usec(),
  1568. }
  1569. };
  1570. bool debug = ctl.options & CONTEXT_V2_OPTION_DEBUG;
  1571. if(mode & CONTEXTS_V2_NODES) {
  1572. ctl.nodes.dict = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
  1573. NULL, sizeof(struct contexts_v2_node));
  1574. }
  1575. if(mode & CONTEXTS_V2_CONTEXTS) {
  1576. ctl.contexts.dict = dictionary_create_advanced(
  1577. DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL,
  1578. sizeof(struct context_v2_entry));
  1579. dictionary_register_conflict_callback(ctl.contexts.dict, contexts_conflict_callback, &ctl);
  1580. dictionary_register_delete_callback(ctl.contexts.dict, contexts_delete_callback, &ctl);
  1581. }
  1582. if(mode & CONTEXTS_V2_FUNCTIONS) {
  1583. ctl.functions.dict = dictionary_create_advanced(
  1584. DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL,
  1585. sizeof(struct function_v2_entry));
  1586. dictionary_register_insert_callback(ctl.functions.dict, functions_insert_callback, &ctl);
  1587. dictionary_register_conflict_callback(ctl.functions.dict, functions_conflict_callback, &ctl);
  1588. dictionary_register_delete_callback(ctl.functions.dict, functions_delete_callback, &ctl);
  1589. }
  1590. if(mode & CONTEXTS_V2_ALERTS) {
  1591. if(req->alerts.transition) {
  1592. ctl.options |= CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES|CONTEXT_V2_OPTION_ALERTS_WITH_VALUES;
  1593. run = sql_find_alert_transition(req->alerts.transition, rrdcontext_v2_set_transition_filter, &ctl);
  1594. if(!run) {
  1595. resp = HTTP_RESP_NOT_FOUND;
  1596. goto cleanup;
  1597. }
  1598. }
  1599. ctl.alerts.alerts = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
  1600. NULL, sizeof(struct alert_v2_entry));
  1601. dictionary_register_insert_callback(ctl.alerts.alerts, alerts_v2_insert_callback, &ctl);
  1602. dictionary_register_conflict_callback(ctl.alerts.alerts, alerts_v2_conflict_callback, &ctl);
  1603. dictionary_register_delete_callback(ctl.alerts.alerts, alerts_v2_delete_callback, &ctl);
  1604. if(ctl.options & (CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES | CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)) {
  1605. ctl.alerts.alert_instances = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
  1606. NULL, sizeof(struct sql_alert_instance_v2_entry));
  1607. dictionary_register_insert_callback(ctl.alerts.alert_instances, alert_instances_v2_insert_callback, &ctl);
  1608. dictionary_register_conflict_callback(ctl.alerts.alert_instances, alert_instances_v2_conflict_callback, &ctl);
  1609. dictionary_register_delete_callback(ctl.alerts.alert_instances, alert_instances_delete_callback, &ctl);
  1610. }
  1611. }
  1612. if(req->after || req->before) {
  1613. ctl.window.relative = rrdr_relative_window_to_absolute_query(&ctl.window.after, &ctl.window.before, &ctl.now
  1614. , false
  1615. );
  1616. ctl.window.enabled = !(mode & CONTEXTS_V2_ALERT_TRANSITIONS);
  1617. }
  1618. else
  1619. ctl.now = now_realtime_sec();
  1620. buffer_json_initialize(wb, "\"", "\"", 0, true,
  1621. ((req->options & CONTEXT_V2_OPTION_MINIFY) && !(req->options & CONTEXT_V2_OPTION_DEBUG)) ? BUFFER_JSON_OPTIONS_MINIFY : BUFFER_JSON_OPTIONS_DEFAULT);
  1622. buffer_json_member_add_uint64(wb, "api", 2);
  1623. if(req->options & CONTEXT_V2_OPTION_DEBUG) {
  1624. buffer_json_member_add_object(wb, "request");
  1625. {
  1626. buffer_json_contexts_v2_mode_to_array(wb, "mode", mode);
  1627. web_client_api_request_v2_contexts_options_to_buffer_json_array(wb, "options", req->options);
  1628. buffer_json_member_add_object(wb, "scope");
  1629. {
  1630. buffer_json_member_add_string(wb, "scope_nodes", req->scope_nodes);
  1631. if (mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS))
  1632. buffer_json_member_add_string(wb, "scope_contexts", req->scope_contexts);
  1633. }
  1634. buffer_json_object_close(wb);
  1635. buffer_json_member_add_object(wb, "selectors");
  1636. {
  1637. buffer_json_member_add_string(wb, "nodes", req->nodes);
  1638. if (mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS))
  1639. buffer_json_member_add_string(wb, "contexts", req->contexts);
  1640. if(mode & (CONTEXTS_V2_ALERTS | CONTEXTS_V2_ALERT_TRANSITIONS)) {
  1641. buffer_json_member_add_object(wb, "alerts");
  1642. if(mode & CONTEXTS_V2_ALERTS)
  1643. web_client_api_request_v2_contexts_alerts_status_to_buffer_json_array(wb, "status", req->alerts.status);
  1644. if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
  1645. buffer_json_member_add_string(wb, "context", req->contexts);
  1646. buffer_json_member_add_uint64(wb, "anchor_gi", req->alerts.global_id_anchor);
  1647. buffer_json_member_add_uint64(wb, "last", req->alerts.last);
  1648. }
  1649. buffer_json_member_add_string(wb, "alert", req->alerts.alert);
  1650. buffer_json_member_add_string(wb, "transition", req->alerts.transition);
  1651. buffer_json_object_close(wb); // alerts
  1652. }
  1653. }
  1654. buffer_json_object_close(wb); // selectors
  1655. buffer_json_member_add_object(wb, "filters");
  1656. {
  1657. if (mode & CONTEXTS_V2_SEARCH)
  1658. buffer_json_member_add_string(wb, "q", req->q);
  1659. buffer_json_member_add_time_t(wb, "after", req->after);
  1660. buffer_json_member_add_time_t(wb, "before", req->before);
  1661. }
  1662. buffer_json_object_close(wb); // filters
  1663. if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
  1664. buffer_json_member_add_object(wb, "facets");
  1665. {
  1666. for (int i = 0; i < ATF_TOTAL_ENTRIES; i++) {
  1667. buffer_json_member_add_string(wb, alert_transition_facets[i].query_param, req->alerts.facets[i]);
  1668. }
  1669. }
  1670. buffer_json_object_close(wb); // facets
  1671. }
  1672. }
  1673. buffer_json_object_close(wb);
  1674. }
  1675. ssize_t ret = 0;
  1676. if(run)
  1677. ret = query_scope_foreach_host(ctl.nodes.scope_pattern, ctl.nodes.pattern,
  1678. rrdcontext_to_json_v2_add_host, &ctl,
  1679. &ctl.versions, ctl.q.host_node_id_str);
  1680. if(unlikely(ret < 0)) {
  1681. buffer_flush(wb);
  1682. if(ret == -2) {
  1683. buffer_strcat(wb, "query timeout");
  1684. resp = HTTP_RESP_GATEWAY_TIMEOUT;
  1685. }
  1686. else {
  1687. buffer_strcat(wb, "query interrupted");
  1688. resp = HTTP_RESP_CLIENT_CLOSED_REQUEST;
  1689. }
  1690. goto cleanup;
  1691. }
  1692. ctl.timings.executed_ut = now_monotonic_usec();
  1693. if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
  1694. contexts_v2_alert_transitions_to_json(wb, &ctl, debug);
  1695. }
  1696. else {
  1697. if (mode & CONTEXTS_V2_NODES) {
  1698. buffer_json_member_add_array(wb, "nodes");
  1699. struct contexts_v2_node *t;
  1700. dfe_start_read(ctl.nodes.dict, t) {
  1701. rrdcontext_to_json_v2_rrdhost(wb, t->host, &ctl, t->ni);
  1702. }
  1703. dfe_done(t);
  1704. buffer_json_array_close(wb);
  1705. }
  1706. if (mode & CONTEXTS_V2_FUNCTIONS) {
  1707. buffer_json_member_add_array(wb, "functions");
  1708. {
  1709. struct function_v2_entry *t;
  1710. dfe_start_read(ctl.functions.dict, t) {
  1711. buffer_json_add_array_item_object(wb);
  1712. buffer_json_member_add_string(wb, "name", t_dfe.name);
  1713. buffer_json_member_add_string(wb, "help", string2str(t->help));
  1714. buffer_json_member_add_array(wb, "ni");
  1715. for (size_t i = 0; i < t->used; i++)
  1716. buffer_json_add_array_item_uint64(wb, t->node_ids[i]);
  1717. buffer_json_array_close(wb);
  1718. buffer_json_object_close(wb);
  1719. }
  1720. dfe_done(t);
  1721. }
  1722. buffer_json_array_close(wb);
  1723. }
  1724. if (mode & CONTEXTS_V2_CONTEXTS) {
  1725. buffer_json_member_add_object(wb, "contexts");
  1726. {
  1727. struct context_v2_entry *z;
  1728. dfe_start_read(ctl.contexts.dict, z) {
  1729. bool collected = z->flags & RRD_FLAG_COLLECTED;
  1730. buffer_json_member_add_object(wb, string2str(z->id));
  1731. {
  1732. buffer_json_member_add_string(wb, "family", string2str(z->family));
  1733. buffer_json_member_add_uint64(wb, "priority", z->priority);
  1734. buffer_json_member_add_time_t(wb, "first_entry", z->first_time_s);
  1735. buffer_json_member_add_time_t(wb, "last_entry", collected ? ctl.now : z->last_time_s);
  1736. buffer_json_member_add_boolean(wb, "live", collected);
  1737. if (mode & CONTEXTS_V2_SEARCH)
  1738. buffer_json_member_add_string(wb, "match", fts_match_to_string(z->match));
  1739. }
  1740. buffer_json_object_close(wb);
  1741. }
  1742. dfe_done(z);
  1743. }
  1744. buffer_json_object_close(wb); // contexts
  1745. }
  1746. if (mode & CONTEXTS_V2_ALERTS)
  1747. contexts_v2_alerts_to_json(wb, &ctl, debug);
  1748. if (mode & CONTEXTS_V2_SEARCH) {
  1749. buffer_json_member_add_object(wb, "searches");
  1750. {
  1751. buffer_json_member_add_uint64(wb, "strings", ctl.q.fts.string_searches);
  1752. buffer_json_member_add_uint64(wb, "char", ctl.q.fts.char_searches);
  1753. buffer_json_member_add_uint64(wb, "total", ctl.q.fts.searches);
  1754. }
  1755. buffer_json_object_close(wb);
  1756. }
  1757. if (mode & (CONTEXTS_V2_VERSIONS))
  1758. version_hashes_api_v2(wb, &ctl.versions);
  1759. if (mode & CONTEXTS_V2_AGENTS)
  1760. buffer_json_agents_v2(wb, &ctl.timings, ctl.now, mode & (CONTEXTS_V2_AGENTS_INFO), true);
  1761. }
  1762. buffer_json_cloud_timings(wb, "timings", &ctl.timings);
  1763. buffer_json_finalize(wb);
  1764. cleanup:
  1765. dictionary_destroy(ctl.nodes.dict);
  1766. dictionary_destroy(ctl.contexts.dict);
  1767. dictionary_destroy(ctl.functions.dict);
  1768. dictionary_destroy(ctl.alerts.alerts);
  1769. dictionary_destroy(ctl.alerts.alert_instances);
  1770. simple_pattern_free(ctl.nodes.scope_pattern);
  1771. simple_pattern_free(ctl.nodes.pattern);
  1772. simple_pattern_free(ctl.contexts.pattern);
  1773. simple_pattern_free(ctl.contexts.scope_pattern);
  1774. simple_pattern_free(ctl.q.pattern);
  1775. simple_pattern_free(ctl.alerts.alert_name_pattern);
  1776. return resp;
  1777. }