sqlite_health.c 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "sqlite_health.h"
  3. #include "sqlite_functions.h"
  4. #include "sqlite_db_migration.h"
  5. #define MAX_HEALTH_SQL_SIZE 2048
  6. #define sqlite3_bind_string_or_null(res,key,param) ((key) ? sqlite3_bind_text(res, param, string2str(key), -1, SQLITE_STATIC) : sqlite3_bind_null(res, param))
  7. /* Health related SQL queries
  8. Creates a health log table in sqlite, one per host guid
  9. */
  10. #define SQL_CREATE_HEALTH_LOG_TABLE(guid) "CREATE TABLE IF NOT EXISTS health_log_%s(hostname text, unique_id int, alarm_id int, alarm_event_id int, config_hash_id blob, updated_by_id int, updates_id int, when_key int, duration int, non_clear_duration int, flags int, exec_run_timestamp int, delay_up_to_timestamp int, name text, chart text, family text, exec text, recipient text, source text, units text, info text, exec_code int, new_status real, old_status real, delay int, new_value double, old_value double, last_repeat int, class text, component text, type text, chart_context text);", guid
  11. int sql_create_health_log_table(RRDHOST *host) {
  12. int rc;
  13. char command[MAX_HEALTH_SQL_SIZE + 1];
  14. if (unlikely(!db_meta)) {
  15. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  16. error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
  17. return 1;
  18. }
  19. char uuid_str[UUID_STR_LEN];
  20. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  21. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CREATE_HEALTH_LOG_TABLE(uuid_str));
  22. rc = db_execute(db_meta, command);
  23. if (unlikely(rc))
  24. error_report("HEALTH [%s]: SQLite error during creation of health log table", rrdhost_hostname(host));
  25. else {
  26. snprintfz(command, MAX_HEALTH_SQL_SIZE, "CREATE INDEX IF NOT EXISTS health_log_index_%s ON health_log_%s (unique_id); ", uuid_str, uuid_str);
  27. rc = db_execute(db_meta, command);
  28. if (unlikely(unlikely(rc)))
  29. error_report("HEALTH [%s]: SQLite error during creation of health log table index", rrdhost_hostname(host));
  30. }
  31. return rc;
  32. }
  33. /* Health related SQL queries
  34. Updates an entry in the table
  35. */
  36. #define SQL_UPDATE_HEALTH_LOG(guid) "UPDATE health_log_%s set updated_by_id = ?, flags = ?, exec_run_timestamp = ?, exec_code = ? where unique_id = ?;", guid
  37. void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
  38. sqlite3_stmt *res = NULL;
  39. int rc;
  40. char command[MAX_HEALTH_SQL_SIZE + 1];
  41. if (unlikely(!db_meta)) {
  42. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  43. error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
  44. return;
  45. }
  46. char uuid_str[UUID_STR_LEN];
  47. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  48. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_UPDATE_HEALTH_LOG(uuid_str));
  49. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  50. if (unlikely(rc != SQLITE_OK)) {
  51. sql_create_health_log_table(host);
  52. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  53. if (unlikely(rc != SQLITE_OK)) {
  54. error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host));
  55. return;
  56. }
  57. }
  58. rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) ae->updated_by_id);
  59. if (unlikely(rc != SQLITE_OK)) {
  60. error_report("Failed to bind updated_by_id parameter for SQL_UPDATE_HEALTH_LOG");
  61. goto failed;
  62. }
  63. rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->flags);
  64. if (unlikely(rc != SQLITE_OK)) {
  65. error_report("Failed to bind flags parameter for SQL_UPDATE_HEALTH_LOG");
  66. goto failed;
  67. }
  68. rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) ae->exec_run_timestamp);
  69. if (unlikely(rc != SQLITE_OK)) {
  70. error_report("Failed to bind exec_run_timestamp parameter for SQL_UPDATE_HEALTH_LOG");
  71. goto failed;
  72. }
  73. rc = sqlite3_bind_int(res, 4, ae->exec_code);
  74. if (unlikely(rc != SQLITE_OK)) {
  75. error_report("Failed to bind exec_code parameter for SQL_UPDATE_HEALTH_LOG");
  76. goto failed;
  77. }
  78. rc = sqlite3_bind_int64(res, 5, (sqlite3_int64) ae->unique_id);
  79. if (unlikely(rc != SQLITE_OK)) {
  80. error_report("Failed to bind unique_id parameter for SQL_UPDATE_HEALTH_LOG");
  81. goto failed;
  82. }
  83. rc = execute_insert(res);
  84. if (unlikely(rc != SQLITE_DONE)) {
  85. error_report("HEALTH [%s]: Failed to update health log, rc = %d", rrdhost_hostname(host), rc);
  86. }
  87. failed:
  88. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  89. error_report("HEALTH [%s]: Failed to finalize the prepared statement for updating health log.", rrdhost_hostname(host));
  90. }
  91. /* Health related SQL queries
  92. Inserts an entry in the table
  93. */
  94. #define SQL_INSERT_HEALTH_LOG(guid) "INSERT INTO health_log_%s(hostname, unique_id, alarm_id, alarm_event_id, " \
  95. "config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, " \
  96. "exec_run_timestamp, delay_up_to_timestamp, name, chart, family, exec, recipient, source, " \
  97. "units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, " \
  98. "class, component, type, chart_context) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", guid
  99. void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
  100. sqlite3_stmt *res = NULL;
  101. int rc;
  102. char command[MAX_HEALTH_SQL_SIZE + 1];
  103. if (unlikely(!db_meta)) {
  104. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  105. error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
  106. return;
  107. }
  108. char uuid_str[UUID_STR_LEN];
  109. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  110. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INSERT_HEALTH_LOG(uuid_str));
  111. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  112. if (unlikely(rc != SQLITE_OK)) {
  113. sql_create_health_log_table(host);
  114. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  115. if (unlikely(rc != SQLITE_OK)) {
  116. error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host));
  117. return;
  118. }
  119. }
  120. rc = sqlite3_bind_text(res, 1, rrdhost_hostname(host), -1, SQLITE_STATIC);
  121. if (unlikely(rc != SQLITE_OK)) {
  122. error_report("Failed to bind hostname parameter for SQL_INSERT_HEALTH_LOG");
  123. goto failed;
  124. }
  125. rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->unique_id);
  126. if (unlikely(rc != SQLITE_OK)) {
  127. error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG");
  128. goto failed;
  129. }
  130. rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) ae->alarm_id);
  131. if (unlikely(rc != SQLITE_OK)) {
  132. error_report("Failed to bind alarm_id parameter for SQL_INSERT_HEALTH_LOG");
  133. goto failed;
  134. }
  135. rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) ae->alarm_event_id);
  136. if (unlikely(rc != SQLITE_OK)) {
  137. error_report("Failed to bind alarm_event_id parameter for SQL_INSERT_HEALTH_LOG");
  138. goto failed;
  139. }
  140. rc = sqlite3_bind_blob(res, 5, &ae->config_hash_id, sizeof(ae->config_hash_id), SQLITE_STATIC);
  141. if (unlikely(rc != SQLITE_OK)) {
  142. error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG");
  143. goto failed;
  144. }
  145. rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->updated_by_id);
  146. if (unlikely(rc != SQLITE_OK)) {
  147. error_report("Failed to bind updated_by_id parameter for SQL_INSERT_HEALTH_LOG");
  148. goto failed;
  149. }
  150. rc = sqlite3_bind_int64(res, 7, (sqlite3_int64) ae->updates_id);
  151. if (unlikely(rc != SQLITE_OK)) {
  152. error_report("Failed to bind updates_id parameter for SQL_INSERT_HEALTH_LOG");
  153. goto failed;
  154. }
  155. rc = sqlite3_bind_int64(res, 8, (sqlite3_int64) ae->when);
  156. if (unlikely(rc != SQLITE_OK)) {
  157. error_report("Failed to bind when parameter for SQL_INSERT_HEALTH_LOG");
  158. goto failed;
  159. }
  160. rc = sqlite3_bind_int64(res, 9, (sqlite3_int64) ae->duration);
  161. if (unlikely(rc != SQLITE_OK)) {
  162. error_report("Failed to bind duration parameter for SQL_INSERT_HEALTH_LOG");
  163. goto failed;
  164. }
  165. rc = sqlite3_bind_int64(res, 10, (sqlite3_int64) ae->non_clear_duration);
  166. if (unlikely(rc != SQLITE_OK)) {
  167. error_report("Failed to bind non_clear_duration parameter for SQL_INSERT_HEALTH_LOG");
  168. goto failed;
  169. }
  170. rc = sqlite3_bind_int64(res, 11, (sqlite3_int64) ae->flags);
  171. if (unlikely(rc != SQLITE_OK)) {
  172. error_report("Failed to bind flags parameter for SQL_INSERT_HEALTH_LOG");
  173. goto failed;
  174. }
  175. rc = sqlite3_bind_int64(res, 12, (sqlite3_int64) ae->exec_run_timestamp);
  176. if (unlikely(rc != SQLITE_OK)) {
  177. error_report("Failed to bind exec_run_timestamp parameter for SQL_INSERT_HEALTH_LOG");
  178. goto failed;
  179. }
  180. rc = sqlite3_bind_int64(res, 13, (sqlite3_int64) ae->delay_up_to_timestamp);
  181. if (unlikely(rc != SQLITE_OK)) {
  182. error_report("Failed to bind delay_up_to_timestamp parameter for SQL_INSERT_HEALTH_LOG");
  183. goto failed;
  184. }
  185. rc = sqlite3_bind_string_or_null(res, ae->name, 14);
  186. if (unlikely(rc != SQLITE_OK)) {
  187. error_report("Failed to bind name parameter for SQL_INSERT_HEALTH_LOG");
  188. goto failed;
  189. }
  190. rc = sqlite3_bind_string_or_null(res, ae->chart, 15);
  191. if (unlikely(rc != SQLITE_OK)) {
  192. error_report("Failed to bind chart parameter for SQL_INSERT_HEALTH_LOG");
  193. goto failed;
  194. }
  195. rc = sqlite3_bind_string_or_null(res, ae->family, 16);
  196. if (unlikely(rc != SQLITE_OK)) {
  197. error_report("Failed to bind family parameter for SQL_INSERT_HEALTH_LOG");
  198. goto failed;
  199. }
  200. rc = sqlite3_bind_string_or_null(res, ae->exec, 17);
  201. if (unlikely(rc != SQLITE_OK)) {
  202. error_report("Failed to bind exec parameter for SQL_INSERT_HEALTH_LOG");
  203. goto failed;
  204. }
  205. rc = sqlite3_bind_string_or_null(res, ae->recipient, 18);
  206. if (unlikely(rc != SQLITE_OK)) {
  207. error_report("Failed to bind recipient parameter for SQL_INSERT_HEALTH_LOG");
  208. goto failed;
  209. }
  210. rc = sqlite3_bind_string_or_null(res, ae->source, 19);
  211. if (unlikely(rc != SQLITE_OK)) {
  212. error_report("Failed to bind source parameter for SQL_INSERT_HEALTH_LOG");
  213. goto failed;
  214. }
  215. rc = sqlite3_bind_string_or_null(res, ae->units, 20);
  216. if (unlikely(rc != SQLITE_OK)) {
  217. error_report("Failed to bind host_id parameter to store node instance information");
  218. goto failed;
  219. }
  220. rc = sqlite3_bind_string_or_null(res, ae->info, 21);
  221. if (unlikely(rc != SQLITE_OK)) {
  222. error_report("Failed to bind info parameter for SQL_INSERT_HEALTH_LOG");
  223. goto failed;
  224. }
  225. rc = sqlite3_bind_int(res, 22, ae->exec_code);
  226. if (unlikely(rc != SQLITE_OK)) {
  227. error_report("Failed to bind exec_code parameter for SQL_INSERT_HEALTH_LOG");
  228. goto failed;
  229. }
  230. rc = sqlite3_bind_int(res, 23, ae->new_status);
  231. if (unlikely(rc != SQLITE_OK)) {
  232. error_report("Failed to bind new_status parameter for SQL_INSERT_HEALTH_LOG");
  233. goto failed;
  234. }
  235. rc = sqlite3_bind_int(res, 24, ae->old_status);
  236. if (unlikely(rc != SQLITE_OK)) {
  237. error_report("Failed to bind old_status parameter for SQL_INSERT_HEALTH_LOG");
  238. goto failed;
  239. }
  240. rc = sqlite3_bind_int(res, 25, ae->delay);
  241. if (unlikely(rc != SQLITE_OK)) {
  242. error_report("Failed to bind delay parameter for SQL_INSERT_HEALTH_LOG");
  243. goto failed;
  244. }
  245. rc = sqlite3_bind_double(res, 26, ae->new_value);
  246. if (unlikely(rc != SQLITE_OK)) {
  247. error_report("Failed to bind new_value parameter for SQL_INSERT_HEALTH_LOG");
  248. goto failed;
  249. }
  250. rc = sqlite3_bind_double(res, 27, ae->old_value);
  251. if (unlikely(rc != SQLITE_OK)) {
  252. error_report("Failed to bind old_value parameter for SQL_INSERT_HEALTH_LOG");
  253. goto failed;
  254. }
  255. rc = sqlite3_bind_int64(res, 28, (sqlite3_int64) ae->last_repeat);
  256. if (unlikely(rc != SQLITE_OK)) {
  257. error_report("Failed to bind last_repeat parameter for SQL_INSERT_HEALTH_LOG");
  258. goto failed;
  259. }
  260. rc = sqlite3_bind_string_or_null(res, ae->classification, 29);
  261. if (unlikely(rc != SQLITE_OK)) {
  262. error_report("Failed to bind classification parameter for SQL_INSERT_HEALTH_LOG");
  263. goto failed;
  264. }
  265. rc = sqlite3_bind_string_or_null(res, ae->component, 30);
  266. if (unlikely(rc != SQLITE_OK)) {
  267. error_report("Failed to bind component parameter for SQL_INSERT_HEALTH_LOG");
  268. goto failed;
  269. }
  270. rc = sqlite3_bind_string_or_null(res, ae->type, 31);
  271. if (unlikely(rc != SQLITE_OK)) {
  272. error_report("Failed to bind type parameter for SQL_INSERT_HEALTH_LOG");
  273. goto failed;
  274. }
  275. rc = sqlite3_bind_string_or_null(res, ae->chart_context, 32);
  276. if (unlikely(rc != SQLITE_OK)) {
  277. error_report("Failed to bind chart_context parameter for SQL_INSERT_HEALTH_LOG");
  278. goto failed;
  279. }
  280. rc = execute_insert(res);
  281. if (unlikely(rc != SQLITE_DONE)) {
  282. error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc);
  283. goto failed;
  284. }
  285. ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
  286. host->health.health_log_entries_written++;
  287. failed:
  288. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  289. error_report("HEALTH [%s]: Failed to finalize the prepared statement for inserting to health log.", rrdhost_hostname(host));
  290. }
  291. void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae)
  292. {
  293. if (ae->flags & HEALTH_ENTRY_FLAG_SAVED)
  294. sql_health_alarm_log_update(host, ae);
  295. else
  296. sql_health_alarm_log_insert(host, ae);
  297. }
  298. /* Health related SQL queries
  299. Get a count of rows from health log table
  300. */
  301. #define SQL_COUNT_HEALTH_LOG(guid) "SELECT count(1) FROM health_log_%s;", guid
  302. void sql_health_alarm_log_count(RRDHOST *host) {
  303. sqlite3_stmt *res = NULL;
  304. int rc;
  305. char command[MAX_HEALTH_SQL_SIZE + 1];
  306. if (unlikely(!db_meta)) {
  307. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  308. error_report("Database has not been initialized");
  309. return;
  310. }
  311. char uuid_str[UUID_STR_LEN];
  312. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  313. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COUNT_HEALTH_LOG(uuid_str));
  314. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  315. if (unlikely(rc != SQLITE_OK)) {
  316. error_report("Failed to prepare statement to count health log entries from db");
  317. return;
  318. }
  319. rc = sqlite3_step_monitored(res);
  320. if (likely(rc == SQLITE_ROW))
  321. host->health.health_log_entries_written = (size_t) sqlite3_column_int64(res, 0);
  322. rc = sqlite3_finalize(res);
  323. if (unlikely(rc != SQLITE_OK))
  324. error_report("Failed to finalize the prepared statement to count health log entries from db");
  325. info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", rrdhost_hostname(host), uuid_str, (unsigned long int) host->health.health_log_entries_written);
  326. }
  327. /* Health related SQL queries
  328. Cleans up the health_log table on a non-claimed host
  329. */
  330. #define SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED(guid,limit) "DELETE FROM health_log_%s ORDER BY unique_id ASC LIMIT %lu;", guid, limit
  331. void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every) {
  332. sqlite3_stmt *res = NULL;
  333. int rc;
  334. char command[MAX_HEALTH_SQL_SIZE + 1];
  335. if (unlikely(!db_meta)) {
  336. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  337. error_report("Database has not been initialized");
  338. return;
  339. }
  340. char uuid_str[UUID_STR_LEN];
  341. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  342. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED(uuid_str, (unsigned long int) (host->health.health_log_entries_written - rotate_every)));
  343. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  344. if (unlikely(rc != SQLITE_OK)) {
  345. error_report("Failed to prepare statement to cleanup health log table");
  346. return;
  347. }
  348. rc = sqlite3_step_monitored(res);
  349. if (unlikely(rc != SQLITE_DONE))
  350. error_report("Failed to cleanup health log table, rc = %d", rc);
  351. rc = sqlite3_finalize(res);
  352. if (unlikely(rc != SQLITE_OK))
  353. error_report("Failed to finalize the prepared statement to cleanup health log table");
  354. host->health.health_log_entries_written = rotate_every;
  355. snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str);
  356. if (unlikely(table_exists_in_database(command))) {
  357. sql_aclk_alert_clean_dead_entries(host);
  358. }
  359. }
  360. /* Health related SQL queries
  361. Cleans up the health_log table on a claimed host
  362. */
  363. #define SQL_CLEANUP_HEALTH_LOG_CLAIMED(guid, guid2, guid3, limit) "DELETE from health_log_%s WHERE unique_id NOT IN (SELECT filtered_alert_unique_id FROM aclk_alert_%s) AND unique_id IN (SELECT unique_id FROM health_log_%s ORDER BY unique_id asc LIMIT %lu);", guid, guid2, guid3, limit
  364. void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) {
  365. sqlite3_stmt *res = NULL;
  366. int rc;
  367. char command[MAX_HEALTH_SQL_SIZE + 1];
  368. if (unlikely(!db_meta)) {
  369. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  370. error_report("Database has not been initialized");
  371. return;
  372. }
  373. char uuid_str[UUID_STR_LEN];
  374. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  375. snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str);
  376. if (!table_exists_in_database(command)) {
  377. sql_health_alarm_log_cleanup_not_claimed(host, rotate_every);
  378. return;
  379. }
  380. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG_CLAIMED(uuid_str, uuid_str, uuid_str, (unsigned long int) (host->health.health_log_entries_written - rotate_every)));
  381. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  382. if (unlikely(rc != SQLITE_OK)) {
  383. error_report("Failed to prepare statement to cleanup health log table");
  384. return;
  385. }
  386. rc = sqlite3_step_monitored(res);
  387. if (unlikely(rc != SQLITE_DONE))
  388. error_report("Failed to cleanup health log table, rc = %d", rc);
  389. rc = sqlite3_finalize(res);
  390. if (unlikely(rc != SQLITE_OK))
  391. error_report("Failed to finalize the prepared statement to cleanup health log table");
  392. sql_health_alarm_log_count(host);
  393. sql_aclk_alert_clean_dead_entries(host);
  394. }
  395. /* Health related SQL queries
  396. Cleans up the health_log table.
  397. */
  398. void sql_health_alarm_log_cleanup(RRDHOST *host) {
  399. static size_t rotate_every = 0;
  400. if(unlikely(rotate_every == 0)) {
  401. rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000);
  402. if(rotate_every < 100) rotate_every = 100;
  403. }
  404. if(likely(host->health.health_log_entries_written < rotate_every)) {
  405. return;
  406. }
  407. if (!claimed()) {
  408. sql_health_alarm_log_cleanup_not_claimed(host, rotate_every);
  409. } else
  410. sql_health_alarm_log_cleanup_claimed(host, rotate_every);
  411. }
  412. #define SQL_INJECT_REMOVED(guid, guid2) "insert into health_log_%s (hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, " \
  413. "delay_up_to_timestamp, name, chart, family, exec, recipient, source, units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, class, component, type, chart_context) " \
  414. "select hostname, ?1, ?2, ?3, config_hash_id, 0, ?4, unixepoch(), 0, 0, flags, exec_run_timestamp, " \
  415. "unixepoch(), name, chart, family, exec, recipient, source, units, info, exec_code, -2, new_status, delay, NULL, new_value, 0, class, component, type, chart_context " \
  416. "from health_log_%s where unique_id = ?5", guid, guid2
  417. #define SQL_INJECT_REMOVED_UPDATE(guid) "update health_log_%s set flags = flags | ?1, updated_by_id = ?2 where unique_id = ?3; ", guid
  418. void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm_event_id, uint32_t unique_id, uint32_t max_unique_id)
  419. {
  420. int rc;
  421. char command[MAX_HEALTH_SQL_SIZE + 1];
  422. if (!alarm_id || !alarm_event_id || !unique_id || !max_unique_id)
  423. return;
  424. sqlite3_stmt *res = NULL;
  425. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED(uuid_str, uuid_str));
  426. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  427. if (rc != SQLITE_OK) {
  428. error_report("Failed to prepare statement when trying to inject removed event");
  429. return;
  430. }
  431. rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) max_unique_id);
  432. if (unlikely(rc != SQLITE_OK)) {
  433. error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED");
  434. goto failed;
  435. }
  436. rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) alarm_id);
  437. if (unlikely(rc != SQLITE_OK)) {
  438. error_report("Failed to bind alarm_id parameter for SQL_INJECT_REMOVED");
  439. goto failed;
  440. }
  441. rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) alarm_event_id + 1);
  442. if (unlikely(rc != SQLITE_OK)) {
  443. error_report("Failed to bind alarm_event_id parameter for SQL_INJECT_REMOVED");
  444. goto failed;
  445. }
  446. rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) unique_id);
  447. if (unlikely(rc != SQLITE_OK)) {
  448. error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED");
  449. goto failed;
  450. }
  451. rc = sqlite3_bind_int64(res, 5, (sqlite3_int64) unique_id);
  452. if (unlikely(rc != SQLITE_OK)) {
  453. error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED");
  454. goto failed;
  455. }
  456. rc = execute_insert(res);
  457. if (unlikely(rc != SQLITE_DONE)) {
  458. error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED, rc = %d", rc);
  459. goto failed;
  460. }
  461. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  462. error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event.");
  463. //update the old entry
  464. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED_UPDATE(uuid_str));
  465. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  466. if (rc != SQLITE_OK) {
  467. error_report("Failed to prepare statement when trying to update during inject removed event");
  468. return;
  469. }
  470. rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) HEALTH_ENTRY_FLAG_UPDATED);
  471. if (unlikely(rc != SQLITE_OK)) {
  472. error_report("Failed to bind flags parameter for SQL_INJECT_REMOVED (update)");
  473. goto failed;
  474. }
  475. rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) max_unique_id);
  476. if (unlikely(rc != SQLITE_OK)) {
  477. error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED (update)");
  478. goto failed;
  479. }
  480. rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) unique_id);
  481. if (unlikely(rc != SQLITE_OK)) {
  482. error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED (update)");
  483. goto failed;
  484. }
  485. rc = execute_insert(res);
  486. if (unlikely(rc != SQLITE_DONE)) {
  487. error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE, rc = %d", rc);
  488. goto failed;
  489. }
  490. failed:
  491. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  492. error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event.");
  493. }
  494. #define SQL_SELECT_MAX_UNIQUE_ID(guid) "SELECT MAX(unique_id) from health_log_%s", guid
  495. uint32_t sql_get_max_unique_id (char *uuid_str)
  496. {
  497. int rc;
  498. char command[MAX_HEALTH_SQL_SIZE + 1];
  499. uint32_t max_unique_id = 0;
  500. sqlite3_stmt *res = NULL;
  501. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_MAX_UNIQUE_ID(uuid_str));
  502. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  503. if (rc != SQLITE_OK) {
  504. error_report("Failed to prepare statement when trying to get max unique id");
  505. return 0;
  506. }
  507. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  508. max_unique_id = (uint32_t) sqlite3_column_int64(res, 0);
  509. }
  510. rc = sqlite3_finalize(res);
  511. if (unlikely(rc != SQLITE_OK))
  512. error_report("Failed to finalize the statement");
  513. return max_unique_id;
  514. }
  515. #define SQL_SELECT_LAST_STATUSES(guid) "SELECT new_status, unique_id, alarm_id, alarm_event_id from health_log_%s group by alarm_id having max(alarm_event_id)", guid
  516. void sql_check_removed_alerts_state(char *uuid_str)
  517. {
  518. int rc;
  519. char command[MAX_HEALTH_SQL_SIZE + 1];
  520. uint32_t max_unique_id = 0;
  521. sqlite3_stmt *res = NULL;
  522. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_LAST_STATUSES(uuid_str));
  523. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  524. if (rc != SQLITE_OK) {
  525. error_report("Failed to prepare statement when trying to check removed statuses");
  526. return;
  527. }
  528. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  529. uint32_t alarm_id, alarm_event_id, unique_id;
  530. RRDCALC_STATUS status;
  531. status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
  532. unique_id = (uint32_t) sqlite3_column_int64(res, 1);
  533. alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
  534. alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3);
  535. if (unlikely(status != RRDCALC_STATUS_REMOVED)) {
  536. if (unlikely(!max_unique_id))
  537. max_unique_id = sql_get_max_unique_id (uuid_str);
  538. sql_inject_removed_status (uuid_str, alarm_id, alarm_event_id, unique_id, ++max_unique_id);
  539. }
  540. }
  541. rc = sqlite3_finalize(res);
  542. if (unlikely(rc != SQLITE_OK))
  543. error_report("Failed to finalize the statement");
  544. }
  545. /* Health related SQL queries
  546. Load from the health log table
  547. */
  548. #define SQL_LOAD_HEALTH_LOG(guid) "SELECT hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, name, chart, family, exec, recipient, source, units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, class, component, type, chart_context FROM health_log_%s group by alarm_id having max(alarm_event_id);", guid
  549. void sql_health_alarm_log_load(RRDHOST *host) {
  550. sqlite3_stmt *res = NULL;
  551. int ret;
  552. ssize_t errored = 0, loaded = 0;
  553. char command[MAX_HEALTH_SQL_SIZE + 1];
  554. host->health.health_log_entries_written = 0;
  555. if (unlikely(!db_meta)) {
  556. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  557. error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
  558. return;
  559. }
  560. char uuid_str[UUID_STR_LEN];
  561. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  562. sql_check_removed_alerts_state(uuid_str);
  563. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str));
  564. ret = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  565. if (unlikely(ret != SQLITE_OK)) {
  566. error_report("HEALTH [%s]: Failed to prepare sql statement to load health log.", rrdhost_hostname(host));
  567. return;
  568. }
  569. DICTIONARY *all_rrdcalcs = dictionary_create(
  570. DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
  571. RRDCALC *rc;
  572. foreach_rrdcalc_in_rrdhost_read(host, rc) {
  573. dictionary_set(all_rrdcalcs, rrdcalc_name(rc), rc, sizeof(*rc));
  574. }
  575. foreach_rrdcalc_in_rrdhost_done(rc);
  576. netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
  577. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  578. ALARM_ENTRY *ae = NULL;
  579. // check that we have valid ids
  580. uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 1);
  581. if(!unique_id) {
  582. error_report("HEALTH [%s]: Got invalid unique id. Ignoring it.", rrdhost_hostname(host));
  583. errored++;
  584. continue;
  585. }
  586. uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
  587. if(!alarm_id) {
  588. error_report("HEALTH [%s]: Got invalid alarm id. Ignoring it.", rrdhost_hostname(host));
  589. errored++;
  590. continue;
  591. }
  592. //need name, chart and family
  593. if (sqlite3_column_type(res, 13) == SQLITE_NULL) {
  594. error_report("HEALTH [%s]: Got null name field. Ignoring it.", rrdhost_hostname(host));
  595. errored++;
  596. continue;
  597. }
  598. if (sqlite3_column_type(res, 14) == SQLITE_NULL) {
  599. error_report("HEALTH [%s]: Got null chart field. Ignoring it.", rrdhost_hostname(host));
  600. errored++;
  601. continue;
  602. }
  603. if (sqlite3_column_type(res, 15) == SQLITE_NULL) {
  604. error_report("HEALTH [%s]: Got null family field. Ignoring it.", rrdhost_hostname(host));
  605. errored++;
  606. continue;
  607. }
  608. // Check if we got last_repeat field
  609. time_t last_repeat = (time_t)sqlite3_column_int64(res, 27);
  610. rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 14));
  611. if(unlikely(rc)) {
  612. if (rrdcalc_isrepeating(rc)) {
  613. rc->last_repeat = last_repeat;
  614. // We iterate through repeating alarm entries only to
  615. // find the latest last_repeat timestamp. Otherwise,
  616. // there is no need to keep them in memory.
  617. continue;
  618. }
  619. }
  620. ae = callocz(1, sizeof(ALARM_ENTRY));
  621. ae->unique_id = unique_id;
  622. ae->alarm_id = alarm_id;
  623. if (sqlite3_column_type(res, 4) != SQLITE_NULL)
  624. uuid_copy(ae->config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 4)));
  625. ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3);
  626. ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 5);
  627. ae->updates_id = (uint32_t) sqlite3_column_int64(res, 6);
  628. ae->when = (time_t) sqlite3_column_int64(res, 7);
  629. ae->duration = (time_t) sqlite3_column_int64(res, 8);
  630. ae->non_clear_duration = (time_t) sqlite3_column_int64(res, 9);
  631. ae->flags = (uint32_t) sqlite3_column_int64(res, 10);
  632. ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
  633. ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 11);
  634. ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 12);
  635. ae->name = string_strdupz((char *) sqlite3_column_text(res, 13));
  636. ae->chart = string_strdupz((char *) sqlite3_column_text(res, 14));
  637. ae->family = string_strdupz((char *) sqlite3_column_text(res, 15));
  638. if (sqlite3_column_type(res, 16) != SQLITE_NULL)
  639. ae->exec = string_strdupz((char *) sqlite3_column_text(res, 16));
  640. else
  641. ae->exec = NULL;
  642. if (sqlite3_column_type(res, 17) != SQLITE_NULL)
  643. ae->recipient = string_strdupz((char *) sqlite3_column_text(res, 17));
  644. else
  645. ae->recipient = NULL;
  646. if (sqlite3_column_type(res, 18) != SQLITE_NULL)
  647. ae->source = string_strdupz((char *) sqlite3_column_text(res, 18));
  648. else
  649. ae->source = NULL;
  650. if (sqlite3_column_type(res, 19) != SQLITE_NULL)
  651. ae->units = string_strdupz((char *) sqlite3_column_text(res, 19));
  652. else
  653. ae->units = NULL;
  654. if (sqlite3_column_type(res, 20) != SQLITE_NULL)
  655. ae->info = string_strdupz((char *) sqlite3_column_text(res, 20));
  656. else
  657. ae->info = NULL;
  658. ae->exec_code = (int) sqlite3_column_int(res, 21);
  659. ae->new_status = (RRDCALC_STATUS) sqlite3_column_int(res, 22);
  660. ae->old_status = (RRDCALC_STATUS)sqlite3_column_int(res, 23);
  661. ae->delay = (int) sqlite3_column_int(res, 24);
  662. ae->new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 25);
  663. ae->old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 26);
  664. ae->last_repeat = last_repeat;
  665. if (sqlite3_column_type(res, 28) != SQLITE_NULL)
  666. ae->classification = string_strdupz((char *) sqlite3_column_text(res, 28));
  667. else
  668. ae->classification = NULL;
  669. if (sqlite3_column_type(res, 29) != SQLITE_NULL)
  670. ae->component = string_strdupz((char *) sqlite3_column_text(res, 29));
  671. else
  672. ae->component = NULL;
  673. if (sqlite3_column_type(res, 30) != SQLITE_NULL)
  674. ae->type = string_strdupz((char *) sqlite3_column_text(res, 30));
  675. else
  676. ae->type = NULL;
  677. if (sqlite3_column_type(res, 31) != SQLITE_NULL)
  678. ae->chart_context = string_strdupz((char *) sqlite3_column_text(res, 31));
  679. else
  680. ae->chart_context = NULL;
  681. char value_string[100 + 1];
  682. string_freez(ae->old_value_string);
  683. string_freez(ae->new_value_string);
  684. ae->old_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae_units(ae), -1));
  685. ae->new_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae_units(ae), -1));
  686. ae->next = host->health_log.alarms;
  687. host->health_log.alarms = ae;
  688. if(unlikely(ae->unique_id > host->health_max_unique_id))
  689. host->health_max_unique_id = ae->unique_id;
  690. if(unlikely(ae->alarm_id >= host->health_max_alarm_id))
  691. host->health_max_alarm_id = ae->alarm_id;
  692. loaded++;
  693. }
  694. netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
  695. dictionary_destroy(all_rrdcalcs);
  696. all_rrdcalcs = NULL;
  697. if(!host->health_max_unique_id) host->health_max_unique_id = (uint32_t)now_realtime_sec();
  698. if(!host->health_max_alarm_id) host->health_max_alarm_id = (uint32_t)now_realtime_sec();
  699. host->health_log.next_log_id = host->health_max_unique_id + 1;
  700. if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id))
  701. host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
  702. log_health("[%s]: Table health_log_%s, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), uuid_str, loaded, errored);
  703. ret = sqlite3_finalize(res);
  704. if (unlikely(ret != SQLITE_OK))
  705. error_report("Failed to finalize the health log read statement");
  706. sql_health_alarm_log_count(host);
  707. }
  708. /*
  709. * Store an alert config hash in the database
  710. */
  711. #define SQL_STORE_ALERT_CONFIG_HASH "insert or replace into alert_hash (hash_id, date_updated, alarm, template, " \
  712. "on_key, class, component, type, os, hosts, lookup, every, units, calc, families, plugin, module, " \
  713. "charts, green, red, warn, crit, exec, to_key, info, delay, options, repeat, host_labels, " \
  714. "p_db_lookup_dimensions, p_db_lookup_method, p_db_lookup_options, p_db_lookup_after, " \
  715. "p_db_lookup_before, p_update_every) values (?1,unixepoch(),?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12," \
  716. "?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34);"
  717. int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg)
  718. {
  719. static __thread sqlite3_stmt *res = NULL;
  720. int rc, param = 0;
  721. if (unlikely(!db_meta)) {
  722. if (default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  723. return 0;
  724. error_report("Database has not been initialized");
  725. return 1;
  726. }
  727. if (unlikely(!res)) {
  728. rc = prepare_statement(db_meta, SQL_STORE_ALERT_CONFIG_HASH, &res);
  729. if (unlikely(rc != SQLITE_OK)) {
  730. error_report("Failed to prepare statement to store alert configuration, rc = %d", rc);
  731. return 1;
  732. }
  733. }
  734. rc = sqlite3_bind_blob(res, ++param, hash_id, sizeof(*hash_id), SQLITE_STATIC);
  735. if (unlikely(rc != SQLITE_OK))
  736. goto bind_fail;
  737. rc = sqlite3_bind_string_or_null(res, cfg->alarm, ++param);
  738. if (unlikely(rc != SQLITE_OK))
  739. goto bind_fail;
  740. rc = sqlite3_bind_string_or_null(res, cfg->template_key, ++param);
  741. if (unlikely(rc != SQLITE_OK))
  742. goto bind_fail;
  743. rc = sqlite3_bind_string_or_null(res, cfg->on, ++param);
  744. if (unlikely(rc != SQLITE_OK))
  745. goto bind_fail;
  746. rc = sqlite3_bind_string_or_null(res, cfg->classification, ++param);
  747. if (unlikely(rc != SQLITE_OK))
  748. goto bind_fail;
  749. rc = sqlite3_bind_string_or_null(res, cfg->component, ++param);
  750. if (unlikely(rc != SQLITE_OK))
  751. goto bind_fail;
  752. rc = sqlite3_bind_string_or_null(res, cfg->type, ++param);
  753. if (unlikely(rc != SQLITE_OK))
  754. goto bind_fail;
  755. rc = sqlite3_bind_string_or_null(res, cfg->os, ++param);
  756. if (unlikely(rc != SQLITE_OK))
  757. goto bind_fail;
  758. rc = sqlite3_bind_string_or_null(res, cfg->host, ++param);
  759. if (unlikely(rc != SQLITE_OK))
  760. goto bind_fail;
  761. rc = sqlite3_bind_string_or_null(res, cfg->lookup, ++param);
  762. if (unlikely(rc != SQLITE_OK))
  763. goto bind_fail;
  764. rc = sqlite3_bind_string_or_null(res, cfg->every, ++param);
  765. if (unlikely(rc != SQLITE_OK))
  766. goto bind_fail;
  767. rc = sqlite3_bind_string_or_null(res, cfg->units, ++param);
  768. if (unlikely(rc != SQLITE_OK))
  769. goto bind_fail;
  770. rc = sqlite3_bind_string_or_null(res, cfg->calc, ++param);
  771. if (unlikely(rc != SQLITE_OK))
  772. goto bind_fail;
  773. rc = sqlite3_bind_string_or_null(res, cfg->families, ++param);
  774. if (unlikely(rc != SQLITE_OK))
  775. goto bind_fail;
  776. rc = sqlite3_bind_string_or_null(res, cfg->plugin, ++param);
  777. if (unlikely(rc != SQLITE_OK))
  778. goto bind_fail;
  779. rc = sqlite3_bind_string_or_null(res, cfg->module, ++param);
  780. if (unlikely(rc != SQLITE_OK))
  781. goto bind_fail;
  782. rc = sqlite3_bind_string_or_null(res, cfg->charts, ++param);
  783. if (unlikely(rc != SQLITE_OK))
  784. goto bind_fail;
  785. rc = sqlite3_bind_string_or_null(res, cfg->green, ++param);
  786. if (unlikely(rc != SQLITE_OK))
  787. goto bind_fail;
  788. rc = sqlite3_bind_string_or_null(res, cfg->red, ++param);
  789. if (unlikely(rc != SQLITE_OK))
  790. goto bind_fail;
  791. rc = sqlite3_bind_string_or_null(res, cfg->warn, ++param);
  792. if (unlikely(rc != SQLITE_OK))
  793. goto bind_fail;
  794. rc = sqlite3_bind_string_or_null(res, cfg->crit, ++param);
  795. if (unlikely(rc != SQLITE_OK))
  796. goto bind_fail;
  797. rc = sqlite3_bind_string_or_null(res, cfg->exec, ++param);
  798. if (unlikely(rc != SQLITE_OK))
  799. goto bind_fail;
  800. rc = sqlite3_bind_string_or_null(res, cfg->to, ++param);
  801. if (unlikely(rc != SQLITE_OK))
  802. goto bind_fail;
  803. rc = sqlite3_bind_string_or_null(res, cfg->info, ++param);
  804. if (unlikely(rc != SQLITE_OK))
  805. goto bind_fail;
  806. rc = sqlite3_bind_string_or_null(res, cfg->delay, ++param);
  807. if (unlikely(rc != SQLITE_OK))
  808. goto bind_fail;
  809. rc = sqlite3_bind_string_or_null(res, cfg->options, ++param);
  810. if (unlikely(rc != SQLITE_OK))
  811. goto bind_fail;
  812. rc = sqlite3_bind_string_or_null(res, cfg->repeat, ++param);
  813. if (unlikely(rc != SQLITE_OK))
  814. goto bind_fail;
  815. rc = sqlite3_bind_string_or_null(res, cfg->host_labels, ++param);
  816. if (unlikely(rc != SQLITE_OK))
  817. goto bind_fail;
  818. if (cfg->p_db_lookup_after) {
  819. rc = sqlite3_bind_string_or_null(res, cfg->p_db_lookup_dimensions, ++param);
  820. if (unlikely(rc != SQLITE_OK))
  821. goto bind_fail;
  822. rc = sqlite3_bind_string_or_null(res, cfg->p_db_lookup_method, ++param);
  823. if (unlikely(rc != SQLITE_OK))
  824. goto bind_fail;
  825. rc = sqlite3_bind_int(res, ++param, (int) cfg->p_db_lookup_options);
  826. if (unlikely(rc != SQLITE_OK))
  827. goto bind_fail;
  828. rc = sqlite3_bind_int(res, ++param, (int) cfg->p_db_lookup_after);
  829. if (unlikely(rc != SQLITE_OK))
  830. goto bind_fail;
  831. rc = sqlite3_bind_int(res, ++param, (int) cfg->p_db_lookup_before);
  832. if (unlikely(rc != SQLITE_OK))
  833. goto bind_fail;
  834. } else {
  835. rc = sqlite3_bind_null(res, ++param);
  836. if (unlikely(rc != SQLITE_OK))
  837. goto bind_fail;
  838. rc = sqlite3_bind_null(res, ++param);
  839. if (unlikely(rc != SQLITE_OK))
  840. goto bind_fail;
  841. rc = sqlite3_bind_null(res, ++param);
  842. if (unlikely(rc != SQLITE_OK))
  843. goto bind_fail;
  844. rc = sqlite3_bind_null(res, ++param);
  845. if (unlikely(rc != SQLITE_OK))
  846. goto bind_fail;
  847. rc = sqlite3_bind_null(res, ++param);
  848. if (unlikely(rc != SQLITE_OK))
  849. goto bind_fail;
  850. }
  851. rc = sqlite3_bind_int(res, ++param, cfg->p_update_every);
  852. if (unlikely(rc != SQLITE_OK))
  853. goto bind_fail;
  854. rc = execute_insert(res);
  855. if (unlikely(rc != SQLITE_DONE))
  856. error_report("Failed to store alert config, rc = %d", rc);
  857. rc = sqlite3_reset(res);
  858. if (unlikely(rc != SQLITE_OK))
  859. error_report("Failed to reset statement in alert hash_id store function, rc = %d", rc);
  860. return 0;
  861. bind_fail:
  862. error_report("Failed to bind parameter %d to store alert hash_id, rc = %d", param, rc);
  863. rc = sqlite3_reset(res);
  864. if (unlikely(rc != SQLITE_OK))
  865. error_report("Failed to reset statement in alert hash_id store function, rc = %d", rc);
  866. return 1;
  867. }
  868. /*
  869. alert hashes are used for cloud communication.
  870. if cloud is disabled or openssl is not available (which will prevent cloud connectivity)
  871. skip hash calculations
  872. */
  873. #if !defined DISABLE_CLOUD && defined ENABLE_HTTPS
  874. #define DIGEST_ALERT_CONFIG_VAL(v) ((v) ? EVP_DigestUpdate(evpctx, (string2str(v)), string_strlen((v))) : EVP_DigestUpdate(evpctx, "", 1))
  875. #endif
  876. int alert_hash_and_store_config(
  877. uuid_t hash_id,
  878. struct alert_config *cfg,
  879. int store_hash)
  880. {
  881. #if !defined DISABLE_CLOUD && defined ENABLE_HTTPS
  882. EVP_MD_CTX *evpctx;
  883. unsigned char hash_value[EVP_MAX_MD_SIZE];
  884. unsigned int hash_len;
  885. evpctx = EVP_MD_CTX_create();
  886. EVP_DigestInit_ex(evpctx, EVP_sha256(), NULL);
  887. DIGEST_ALERT_CONFIG_VAL(cfg->alarm);
  888. DIGEST_ALERT_CONFIG_VAL(cfg->template_key);
  889. DIGEST_ALERT_CONFIG_VAL(cfg->os);
  890. DIGEST_ALERT_CONFIG_VAL(cfg->host);
  891. DIGEST_ALERT_CONFIG_VAL(cfg->on);
  892. DIGEST_ALERT_CONFIG_VAL(cfg->families);
  893. DIGEST_ALERT_CONFIG_VAL(cfg->plugin);
  894. DIGEST_ALERT_CONFIG_VAL(cfg->module);
  895. DIGEST_ALERT_CONFIG_VAL(cfg->charts);
  896. DIGEST_ALERT_CONFIG_VAL(cfg->lookup);
  897. DIGEST_ALERT_CONFIG_VAL(cfg->calc);
  898. DIGEST_ALERT_CONFIG_VAL(cfg->every);
  899. DIGEST_ALERT_CONFIG_VAL(cfg->green);
  900. DIGEST_ALERT_CONFIG_VAL(cfg->red);
  901. DIGEST_ALERT_CONFIG_VAL(cfg->warn);
  902. DIGEST_ALERT_CONFIG_VAL(cfg->crit);
  903. DIGEST_ALERT_CONFIG_VAL(cfg->exec);
  904. DIGEST_ALERT_CONFIG_VAL(cfg->to);
  905. DIGEST_ALERT_CONFIG_VAL(cfg->units);
  906. DIGEST_ALERT_CONFIG_VAL(cfg->info);
  907. DIGEST_ALERT_CONFIG_VAL(cfg->classification);
  908. DIGEST_ALERT_CONFIG_VAL(cfg->component);
  909. DIGEST_ALERT_CONFIG_VAL(cfg->type);
  910. DIGEST_ALERT_CONFIG_VAL(cfg->delay);
  911. DIGEST_ALERT_CONFIG_VAL(cfg->options);
  912. DIGEST_ALERT_CONFIG_VAL(cfg->repeat);
  913. DIGEST_ALERT_CONFIG_VAL(cfg->host_labels);
  914. DIGEST_ALERT_CONFIG_VAL(cfg->chart_labels);
  915. EVP_DigestFinal_ex(evpctx, hash_value, &hash_len);
  916. EVP_MD_CTX_destroy(evpctx);
  917. fatal_assert(hash_len > sizeof(uuid_t));
  918. char uuid_str[UUID_STR_LEN];
  919. uuid_unparse_lower(*((uuid_t *)&hash_value), uuid_str);
  920. uuid_copy(hash_id, *((uuid_t *)&hash_value));
  921. /* store everything, so it can be recreated when not in memory or just a subset ? */
  922. if (store_hash)
  923. (void)sql_store_alert_config_hash( (uuid_t *)&hash_value, cfg);
  924. #else
  925. UNUSED(hash_id);
  926. UNUSED(cfg);
  927. UNUSED(store_hash);
  928. #endif
  929. return 1;
  930. }
  931. #define SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT "SELECT new_status FROM health_log_%s WHERE alarm_id = %u AND unique_id != %u AND flags & %d ORDER BY unique_id DESC LIMIT 1"
  932. int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status)
  933. {
  934. int rc = 0, ret = -1;
  935. char command[MAX_HEALTH_SQL_SIZE + 1];
  936. char uuid_str[UUID_STR_LEN];
  937. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  938. sqlite3_stmt *res = NULL;
  939. snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT, uuid_str, ae->alarm_id, ae->unique_id, HEALTH_ENTRY_FLAG_EXEC_RUN);
  940. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  941. if (rc != SQLITE_OK) {
  942. error_report("Failed to prepare statement when trying to get last executed status");
  943. return ret;
  944. }
  945. ret = 0;
  946. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  947. *last_executed_status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
  948. ret = 1;
  949. }
  950. rc = sqlite3_finalize(res);
  951. if (unlikely(rc != SQLITE_OK))
  952. error_report("Failed to finalize the statement.");
  953. return ret;
  954. }
  955. #define SQL_SELECT_HEALTH_LOG(guid) "SELECT hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, name, chart, family, exec, recipient, source, units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, class, component, type, chart_context FROM health_log_%s WHERE 1=1 ", guid
  956. void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart) {
  957. buffer_strcat(wb, "[");
  958. unsigned int max = host->health_log.max;
  959. unsigned int count = 0;
  960. sqlite3_stmt *res = NULL;
  961. int rc;
  962. BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
  963. char uuid_str[UUID_STR_LEN];
  964. uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
  965. buffer_sprintf(command, SQL_SELECT_HEALTH_LOG(uuid_str));
  966. if (chart) {
  967. char chart_sql[MAX_HEALTH_SQL_SIZE + 1];
  968. snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND chart = '%s' ", chart);
  969. buffer_strcat(command, chart_sql);
  970. }
  971. if (after) {
  972. char after_sql[MAX_HEALTH_SQL_SIZE + 1];
  973. snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND unique_id > %u ", after);
  974. buffer_strcat(command, after_sql);
  975. }
  976. {
  977. char limit_sql[MAX_HEALTH_SQL_SIZE + 1];
  978. snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY unique_id DESC LIMIT %u ", max);
  979. buffer_strcat(command, limit_sql);
  980. }
  981. rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0);
  982. if (unlikely(rc != SQLITE_OK)) {
  983. error_report("Failed to prepare statement SQL_SELECT_HEALTH_LOG");
  984. return;
  985. }
  986. while (sqlite3_step(res) == SQLITE_ROW) {
  987. char old_value_string[100 + 1];
  988. char new_value_string[100 + 1];
  989. char config_hash_id[UUID_STR_LEN];
  990. uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 4)), config_hash_id);
  991. char *edit_command = health_edit_command_from_source((char *)sqlite3_column_text(res, 18));
  992. if (count)
  993. buffer_sprintf(wb, ",");
  994. count++;
  995. buffer_sprintf(
  996. wb,
  997. "\n\t{\n"
  998. "\t\t\"hostname\": \"%s\",\n"
  999. "\t\t\"utc_offset\": %d,\n"
  1000. "\t\t\"timezone\": \"%s\",\n"
  1001. "\t\t\"unique_id\": %u,\n"
  1002. "\t\t\"alarm_id\": %u,\n"
  1003. "\t\t\"alarm_event_id\": %u,\n"
  1004. "\t\t\"config_hash_id\": \"%s\",\n"
  1005. "\t\t\"name\": \"%s\",\n"
  1006. "\t\t\"chart\": \"%s\",\n"
  1007. "\t\t\"context\": \"%s\",\n"
  1008. "\t\t\"family\": \"%s\",\n"
  1009. "\t\t\"class\": \"%s\",\n"
  1010. "\t\t\"component\": \"%s\",\n"
  1011. "\t\t\"type\": \"%s\",\n"
  1012. "\t\t\"processed\": %s,\n"
  1013. "\t\t\"updated\": %s,\n"
  1014. "\t\t\"exec_run\": %lu,\n"
  1015. "\t\t\"exec_failed\": %s,\n"
  1016. "\t\t\"exec\": \"%s\",\n"
  1017. "\t\t\"recipient\": \"%s\",\n"
  1018. "\t\t\"exec_code\": %d,\n"
  1019. "\t\t\"source\": \"%s\",\n"
  1020. "\t\t\"command\": \"%s\",\n"
  1021. "\t\t\"units\": \"%s\",\n"
  1022. "\t\t\"when\": %lu,\n"
  1023. "\t\t\"duration\": %lu,\n"
  1024. "\t\t\"non_clear_duration\": %lu,\n"
  1025. "\t\t\"status\": \"%s\",\n"
  1026. "\t\t\"old_status\": \"%s\",\n"
  1027. "\t\t\"delay\": %d,\n"
  1028. "\t\t\"delay_up_to_timestamp\": %lu,\n"
  1029. "\t\t\"updated_by_id\": %u,\n"
  1030. "\t\t\"updates_id\": %u,\n"
  1031. "\t\t\"value_string\": \"%s\",\n"
  1032. "\t\t\"old_value_string\": \"%s\",\n"
  1033. "\t\t\"last_repeat\": \"%lu\",\n"
  1034. "\t\t\"silenced\": \"%s\",\n",
  1035. sqlite3_column_text(res, 0),
  1036. host->utc_offset,
  1037. rrdhost_abbrev_timezone(host),
  1038. (unsigned int) sqlite3_column_int64(res, 1),
  1039. (unsigned int) sqlite3_column_int64(res, 2),
  1040. (unsigned int) sqlite3_column_int64(res, 3),
  1041. config_hash_id,
  1042. sqlite3_column_text(res, 13),
  1043. sqlite3_column_text(res, 14),
  1044. sqlite3_column_text(res, 31),
  1045. sqlite3_column_text(res, 15),
  1046. sqlite3_column_text(res, 28) ? (const char *) sqlite3_column_text(res, 28) : (char *) "Unknown",
  1047. sqlite3_column_text(res, 29) ? (const char *) sqlite3_column_text(res, 29) : (char *) "Unknown",
  1048. sqlite3_column_text(res, 30) ? (const char *) sqlite3_column_text(res, 30) : (char *) "Unknown",
  1049. (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false",
  1050. (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false",
  1051. (long unsigned int)sqlite3_column_int64(res, 11),
  1052. (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false",
  1053. sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : string2str(host->health.health_default_exec),
  1054. sqlite3_column_text(res, 17) ? (const char *) sqlite3_column_text(res, 17) : string2str(host->health.health_default_recipient),
  1055. sqlite3_column_int(res, 21),
  1056. sqlite3_column_text(res, 18),
  1057. edit_command,
  1058. sqlite3_column_text(res, 19),
  1059. (long unsigned int)sqlite3_column_int64(res, 7),
  1060. (long unsigned int)sqlite3_column_int64(res, 8),
  1061. (long unsigned int)sqlite3_column_int64(res, 9),
  1062. rrdcalc_status2string(sqlite3_column_int(res, 22)),
  1063. rrdcalc_status2string(sqlite3_column_int(res, 23)),
  1064. sqlite3_column_int(res, 24),
  1065. (long unsigned int)sqlite3_column_int64(res, 12),
  1066. (unsigned int)sqlite3_column_int64(res, 5),
  1067. (unsigned int)sqlite3_column_int64(res, 6),
  1068. sqlite3_column_type(res, 25) == SQLITE_NULL ? "-" : format_value_and_unit(new_value_string, 100, sqlite3_column_double(res, 25), (char *) sqlite3_column_text(res, 19), -1),
  1069. sqlite3_column_type(res, 26) == SQLITE_NULL ? "-" : format_value_and_unit(old_value_string, 100, sqlite3_column_double(res, 26), (char *) sqlite3_column_text(res, 19), -1),
  1070. (long unsigned int)sqlite3_column_int64(res, 27),
  1071. (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false");
  1072. health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 20), ",\n");
  1073. if(unlikely(sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
  1074. buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
  1075. }
  1076. buffer_strcat(wb, "\t\t\"value\":");
  1077. if (sqlite3_column_type(res, 25) == SQLITE_NULL)
  1078. buffer_strcat(wb, "null");
  1079. else
  1080. buffer_print_netdata_double(wb, sqlite3_column_double(res, 25));
  1081. buffer_strcat(wb, ",\n");
  1082. buffer_strcat(wb, "\t\t\"old_value\":");
  1083. if (sqlite3_column_type(res, 26) == SQLITE_NULL)
  1084. buffer_strcat(wb, "null");
  1085. else
  1086. buffer_print_netdata_double(wb, sqlite3_column_double(res, 26));
  1087. buffer_strcat(wb, "\n");
  1088. buffer_strcat(wb, "\t}");
  1089. freez(edit_command);
  1090. }
  1091. buffer_strcat(wb, "\n]");
  1092. rc = sqlite3_finalize(res);
  1093. if (unlikely(rc != SQLITE_OK))
  1094. error_report("Failed to finalize statement for SQL_SELECT_HEALTH_LOG");
  1095. buffer_free(command);
  1096. }