api_v2.c 86 KB

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