@cryptotaxi247 / netdata-1 / commits / c0c1e0e85

Better cleanup of health log table (#15045)

Emmanuel Vasilakis committed May 23, 2023 at 15:56 UTC c0c1e0e85a627d0509a37ea4e7ef00c2cf4aa29f
9 files changed +348 -248
database/sqlite/sqlite_aclk_alert.c
+7 -11
@@ -75,7 +75,7 @@ static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char
75 return ret;
76 }
77
78 -#define MAX_REMOVED_PERIOD 86400
78 +#define MAX_REMOVED_PERIOD 604800 //a week
79 //decide if some events should be sent or not
80
81 #define SQL_SELECT_ALERT_BY_ID "SELECT hl.new_status, hl.config_hash_id, hl.unique_id FROM health_log_%s hl, aclk_alert_%s aa " \
@@ -321,7 +321,7 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc)
321 }
322 }
323
324 - char uuid_str[GUID_LEN + 1];
324 + char uuid_str[UUID_STR_LEN];
325 uint64_t first_sequence_id = 0;
326 uint64_t last_sequence_id = 0;
327 static __thread uint64_t log_first_sequence_id = 0;
@@ -463,7 +463,7 @@ void aclk_push_alert_events_for_all_hosts(void)
463
464 void sql_queue_existing_alerts_to_aclk(RRDHOST *host)
465 {
466 - char uuid_str[GUID_LEN + 1];
466 + char uuid_str[UUID_STR_LEN];
467 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
468 BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
469
@@ -747,7 +747,7 @@ void aclk_process_send_alarm_snapshot(char *node_id, char *claim_id __maybe_unus
747 void health_alarm_entry2proto_nolock(struct alarm_log_entry *alarm_log, ALARM_ENTRY *ae, RRDHOST *host)
748 {
749 char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
750 - char config_hash_id[GUID_LEN + 1];
750 + char config_hash_id[UUID_STR_LEN];
751 uuid_unparse_lower(ae->config_hash_id, config_hash_id);
752
753 alarm_log->chart = strdupz(ae_chart_name(ae));
@@ -939,18 +939,14 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused)
939 #endif
940 }
941
942 -#define SQL_DELETE_ALERT_ENTRIES "DELETE FROM aclk_alert_%s WHERE filtered_alert_unique_id NOT IN (SELECT unique_id FROM health_log_%s);"
943 -
942 +#define SQL_DELETE_ALERT_ENTRIES "DELETE FROM aclk_alert_%s WHERE filtered_alert_unique_id + %d < UNIXEPOCH();"
943 void sql_aclk_alert_clean_dead_entries(RRDHOST *host)
944 {
946 - if (!claimed())
947 - return;
948 -
945 char uuid_str[UUID_STR_LEN];
946 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
947
952 - char sql[512];
953 - snprintfz(sql,511,SQL_DELETE_ALERT_ENTRIES, uuid_str, uuid_str);
948 + char sql[ACLK_SYNC_QUERY_SIZE];
949 + snprintfz(sql, ACLK_SYNC_QUERY_SIZE - 1, SQL_DELETE_ALERT_ENTRIES, uuid_str, MAX_REMOVED_PERIOD);
950
951 char *err_msg = NULL;
952 int rc = sqlite3_exec_monitored(db_meta, sql, NULL, NULL, &err_msg);
database/sqlite/sqlite_db_migration.c
+1 -1
@@ -12,7 +12,7 @@ static int return_int_cb(void *data, int argc, char **argv, char **column)
12 }
13
14
15 -static int table_exists_in_database(const char *table)
15 +int table_exists_in_database(const char *table)
16 {
17 char *err_msg = NULL;
18 char sql[128];
database/sqlite/sqlite_db_migration.h
+1
@@ -8,5 +8,6 @@
8
9 int perform_database_migration(sqlite3 *database, int target_version);
10 int perform_context_database_migration(sqlite3 *database, int target_version);
11 +int table_exists_in_database(const char *table);
12
13 #endif //NETDATA_SQLITE_DB_MIGRATION_H
database/sqlite/sqlite_health.c
+288 -28
@@ -2,6 +2,7 @@
2
3 #include "sqlite_health.h"
4 #include "sqlite_functions.h"
5 +#include "sqlite_db_migration.h"
6
7 #define MAX_HEALTH_SQL_SIZE 2048
8 #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))
@@ -20,7 +21,7 @@ int sql_create_health_log_table(RRDHOST *host) {
21 return 1;
22 }
23
23 - char uuid_str[GUID_LEN + 1];
24 + char uuid_str[UUID_STR_LEN];
25 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
26
27 snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CREATE_HEALTH_LOG_TABLE(uuid_str));
@@ -53,7 +54,7 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
54 return;
55 }
56
56 - char uuid_str[GUID_LEN + 1];
57 + char uuid_str[UUID_STR_LEN];
58 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
59
60 snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_UPDATE_HEALTH_LOG(uuid_str));
@@ -128,7 +129,7 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
129 return;
130 }
131
131 - char uuid_str[GUID_LEN + 1];
132 + char uuid_str[UUID_STR_LEN];
133 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
134
135 snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INSERT_HEALTH_LOG(uuid_str));
@@ -358,34 +359,61 @@ void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae)
359 }
360
361 /* Health related SQL queries
361 - Cleans up the health_log table.
362 + Get a count of rows from health log table
363 */
363 -#define SQL_CLEANUP_HEALTH_LOG(guid,guid2,limit) "DELETE from health_log_%s where unique_id in (SELECT unique_id from health_log_%s order by unique_id asc LIMIT %lu);", guid, guid2, limit
364 -void sql_health_alarm_log_cleanup(RRDHOST *host) {
364 +#define SQL_COUNT_HEALTH_LOG(guid) "SELECT count(1) FROM health_log_%s;", guid
365 +void sql_health_alarm_log_count(RRDHOST *host) {
366 sqlite3_stmt *res = NULL;
366 - static size_t rotate_every = 0;
367 int rc;
368 char command[MAX_HEALTH_SQL_SIZE + 1];
369
370 - if(unlikely(rotate_every == 0)) {
371 - rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000);
372 - if(rotate_every < 100) rotate_every = 100;
370 + if (unlikely(!db_meta)) {
371 + if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
372 + error_report("Database has not been initialized");
373 + return;
374 }
375
375 - if(likely(host->health.health_log_entries_written < rotate_every)) {
376 + char uuid_str[UUID_STR_LEN];
377 + uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
378 +
379 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COUNT_HEALTH_LOG(uuid_str));
380 +
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 count health log entries from db");
384 return;
385 }
386
387 + rc = sqlite3_step_monitored(res);
388 + if (likely(rc == SQLITE_ROW))
389 + host->health.health_log_entries_written = (size_t) sqlite3_column_int64(res, 0);
390 +
391 + rc = sqlite3_finalize(res);
392 + if (unlikely(rc != SQLITE_OK))
393 + error_report("Failed to finalize the prepared statement to count health log entries from db");
394 +
395 + info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", rrdhost_hostname(host), uuid_str, (unsigned long int) host->health.health_log_entries_written);
396 +}
397 +
398 +/* Health related SQL queries
399 + Cleans up the health_log table on a non-claimed host
400 +*/
401 +#define SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED(guid,limit) "DELETE FROM health_log_%s ORDER BY unique_id ASC LIMIT %lu;", guid, limit
402 +void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every) {
403 + sqlite3_stmt *res = NULL;
404 + int rc;
405 + char command[MAX_HEALTH_SQL_SIZE + 1];
406 +
407 if (unlikely(!db_meta)) {
408 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
409 error_report("Database has not been initialized");
410 return;
411 }
412
385 - char uuid_str[GUID_LEN + 1];
413 + char uuid_str[UUID_STR_LEN];
414 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
415
388 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG(uuid_str, uuid_str, (unsigned long int) (host->health.health_log_entries_written - rotate_every)));
416 + 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)));
417
418 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
419 if (unlikely(rc != SQLITE_OK)) {
@@ -403,14 +431,17 @@ void sql_health_alarm_log_cleanup(RRDHOST *host) {
431
432 host->health.health_log_entries_written = rotate_every;
433
406 - sql_aclk_alert_clean_dead_entries(host);
434 + snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str);
435 + if (unlikely(table_exists_in_database(command))) {
436 + sql_aclk_alert_clean_dead_entries(host);
437 + }
438 }
439
440 /* Health related SQL queries
410 - Get a count of rows from health log table
441 + Cleans up the health_log table on a claimed host
442 */
412 -#define SQL_COUNT_HEALTH_LOG(guid) "SELECT count(1) FROM health_log_%s;", guid
413 -void sql_health_alarm_log_count(RRDHOST *host) {
443 +#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
444 +void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) {
445 sqlite3_stmt *res = NULL;
446 int rc;
447 char command[MAX_HEALTH_SQL_SIZE + 1];
@@ -421,26 +452,55 @@ void sql_health_alarm_log_count(RRDHOST *host) {
452 return;
453 }
454
424 - char uuid_str[GUID_LEN + 1];
455 + char uuid_str[UUID_STR_LEN];
456 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
457 + snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str);
458
427 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COUNT_HEALTH_LOG(uuid_str));
459 + if (!table_exists_in_database(command)) {
460 + sql_health_alarm_log_cleanup_not_claimed(host, rotate_every);
461 + return;
462 + }
463 +
464 + 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)));
465
466 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
467 if (unlikely(rc != SQLITE_OK)) {
431 - error_report("Failed to prepare statement to count health log entries from db");
468 + error_report("Failed to prepare statement to cleanup health log table");
469 return;
470 }
471
472 rc = sqlite3_step_monitored(res);
436 - if (likely(rc == SQLITE_ROW))
437 - host->health.health_log_entries_written = (size_t) sqlite3_column_int64(res, 0);
473 + if (unlikely(rc != SQLITE_DONE))
474 + error_report("Failed to cleanup health log table, rc = %d", rc);
475
476 rc = sqlite3_finalize(res);
477 if (unlikely(rc != SQLITE_OK))
441 - error_report("Failed to finalize the prepared statement to count health log entries from db");
478 + error_report("Failed to finalize the prepared statement to cleanup health log table");
479
443 - info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", rrdhost_hostname(host), uuid_str, (unsigned long int) host->health.health_log_entries_written);
480 + sql_health_alarm_log_count(host);
481 +
482 + sql_aclk_alert_clean_dead_entries(host);
483 +}
484 +
485 +/* Health related SQL queries
486 + Cleans up the health_log table.
487 +*/
488 +void sql_health_alarm_log_cleanup(RRDHOST *host) {
489 + static size_t rotate_every = 0;
490 +
491 + if(unlikely(rotate_every == 0)) {
492 + rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000);
493 + if(rotate_every < 100) rotate_every = 100;
494 + }
495 +
496 + if(likely(host->health.health_log_entries_written < rotate_every)) {
497 + return;
498 + }
499 +
500 + if (!claimed()) {
501 + sql_health_alarm_log_cleanup_not_claimed(host, rotate_every);
502 + } else
503 + sql_health_alarm_log_cleanup_claimed(host, rotate_every);
504 }
505
506 #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, " \
@@ -608,7 +668,7 @@ void sql_check_removed_alerts_state(char *uuid_str)
668 /* Health related SQL queries
669 Load from the health log table
670 */
611 -#define SQL_LOAD_HEALTH_LOG(guid,limit) "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 (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 order by unique_id desc limit %u) order by unique_id asc;", guid, limit
671 +#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
672 void sql_health_alarm_log_load(RRDHOST *host) {
673 sqlite3_stmt *res = NULL;
674 int ret;
@@ -623,12 +683,12 @@ void sql_health_alarm_log_load(RRDHOST *host) {
683 return;
684 }
685
626 - char uuid_str[GUID_LEN + 1];
686 + char uuid_str[UUID_STR_LEN];
687 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
688
689 sql_check_removed_alerts_state(uuid_str);
690
631 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str, host->health_log.max));
691 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str));
692
693 ret = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
694 if (unlikely(ret != SQLITE_OK)) {
@@ -1076,7 +1136,7 @@ int alert_hash_and_store_config(
1136 EVP_MD_CTX_destroy(evpctx);
1137 fatal_assert(hash_len > sizeof(uuid_t));
1138
1079 - char uuid_str[GUID_LEN + 1];
1139 + char uuid_str[UUID_STR_LEN];
1140 uuid_unparse_lower(*((uuid_t *)&hash_value), uuid_str);
1141 uuid_copy(hash_id, *((uuid_t *)&hash_value));
1142
@@ -1091,3 +1151,203 @@ int alert_hash_and_store_config(
1151
1152 return 1;
1153 }
1154 +
1155 +#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"
1156 +int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status)
1157 +{
1158 + int rc = 0, ret = -1;
1159 + char command[MAX_HEALTH_SQL_SIZE + 1];
1160 +
1161 + char uuid_str[UUID_STR_LEN];
1162 + uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
1163 +
1164 + sqlite3_stmt *res = NULL;
1165 +
1166 + 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);
1167 +
1168 + rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
1169 + if (rc != SQLITE_OK) {
1170 + error_report("Failed to prepare statement when trying to get last executed status");
1171 + return ret;
1172 + }
1173 +
1174 + ret = 0;
1175 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
1176 + *last_executed_status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
1177 + ret = 1;
1178 + }
1179 +
1180 + rc = sqlite3_finalize(res);
1181 + if (unlikely(rc != SQLITE_OK))
1182 + error_report("Failed to finalize the statement.");
1183 +
1184 + return ret;
1185 +}
1186 +
1187 +#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
1188 +void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart) {
1189 +
1190 + buffer_strcat(wb, "[");
1191 +
1192 + unsigned int max = host->health_log.max;
1193 + unsigned int count = 0;
1194 +
1195 + sqlite3_stmt *res = NULL;
1196 + int rc;
1197 +
1198 + BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
1199 + char uuid_str[UUID_STR_LEN];
1200 + uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
1201 +
1202 + buffer_sprintf(command, SQL_SELECT_HEALTH_LOG(uuid_str));
1203 +
1204 + if (chart) {
1205 + char chart_sql[MAX_HEALTH_SQL_SIZE + 1];
1206 + snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND chart = '%s' ", chart);
1207 + buffer_strcat(command, chart_sql);
1208 + }
1209 +
1210 + if (after) {
1211 + char after_sql[MAX_HEALTH_SQL_SIZE + 1];
1212 + snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND unique_id > %u ", after);
1213 + buffer_strcat(command, after_sql);
1214 + }
1215 +
1216 + {
1217 + char limit_sql[MAX_HEALTH_SQL_SIZE + 1];
1218 + snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY unique_id DESC LIMIT %u ", max);
1219 + buffer_strcat(command, limit_sql);
1220 + }
1221 +
1222 + rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0);
1223 + if (unlikely(rc != SQLITE_OK)) {
1224 + error_report("Failed to prepare statement SQL_SELECT_HEALTH_LOG");
1225 + return;
1226 + }
1227 +
1228 + while (sqlite3_step(res) == SQLITE_ROW) {
1229 +
1230 + char old_value_string[100 + 1];
1231 + char new_value_string[100 + 1];
1232 +
1233 + char config_hash_id[UUID_STR_LEN];
1234 + uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 4)), config_hash_id);
1235 +
1236 + char *edit_command = health_edit_command_from_source((char *)sqlite3_column_text(res, 18));
1237 +
1238 + if (count)
1239 + buffer_sprintf(wb, ",");
1240 +
1241 + count++;
1242 +
1243 + buffer_sprintf(
1244 + wb,
1245 + "\n\t{\n"
1246 + "\t\t\"hostname\": \"%s\",\n"
1247 + "\t\t\"utc_offset\": %d,\n"
1248 + "\t\t\"timezone\": \"%s\",\n"
1249 + "\t\t\"unique_id\": %u,\n"
1250 + "\t\t\"alarm_id\": %u,\n"
1251 + "\t\t\"alarm_event_id\": %u,\n"
1252 + "\t\t\"config_hash_id\": \"%s\",\n"
1253 + "\t\t\"name\": \"%s\",\n"
1254 + "\t\t\"chart\": \"%s\",\n"
1255 + "\t\t\"context\": \"%s\",\n"
1256 + "\t\t\"family\": \"%s\",\n"
1257 + "\t\t\"class\": \"%s\",\n"
1258 + "\t\t\"component\": \"%s\",\n"
1259 + "\t\t\"type\": \"%s\",\n"
1260 + "\t\t\"processed\": %s,\n"
1261 + "\t\t\"updated\": %s,\n"
1262 + "\t\t\"exec_run\": %lu,\n"
1263 + "\t\t\"exec_failed\": %s,\n"
1264 + "\t\t\"exec\": \"%s\",\n"
1265 + "\t\t\"recipient\": \"%s\",\n"
1266 + "\t\t\"exec_code\": %d,\n"
1267 + "\t\t\"source\": \"%s\",\n"
1268 + "\t\t\"command\": \"%s\",\n"
1269 + "\t\t\"units\": \"%s\",\n"
1270 + "\t\t\"when\": %lu,\n"
1271 + "\t\t\"duration\": %lu,\n"
1272 + "\t\t\"non_clear_duration\": %lu,\n"
1273 + "\t\t\"status\": \"%s\",\n"
1274 + "\t\t\"old_status\": \"%s\",\n"
1275 + "\t\t\"delay\": %d,\n"
1276 + "\t\t\"delay_up_to_timestamp\": %lu,\n"
1277 + "\t\t\"updated_by_id\": %u,\n"
1278 + "\t\t\"updates_id\": %u,\n"
1279 + "\t\t\"value_string\": \"%s\",\n"
1280 + "\t\t\"old_value_string\": \"%s\",\n"
1281 + "\t\t\"last_repeat\": \"%lu\",\n"
1282 + "\t\t\"silenced\": \"%s\",\n",
1283 + sqlite3_column_text(res, 0),
1284 + host->utc_offset,
1285 + rrdhost_abbrev_timezone(host),
1286 + (unsigned int) sqlite3_column_int64(res, 1),
1287 + (unsigned int) sqlite3_column_int64(res, 2),
1288 + (unsigned int) sqlite3_column_int64(res, 3),
1289 + config_hash_id,
1290 + sqlite3_column_text(res, 13),
1291 + sqlite3_column_text(res, 14),
1292 + sqlite3_column_text(res, 31),
1293 + sqlite3_column_text(res, 15),
1294 + sqlite3_column_text(res, 28) ? (const char *) sqlite3_column_text(res, 28) : (char *) "Unknown",
1295 + sqlite3_column_text(res, 29) ? (const char *) sqlite3_column_text(res, 29) : (char *) "Unknown",
1296 + sqlite3_column_text(res, 30) ? (const char *) sqlite3_column_text(res, 30) : (char *) "Unknown",
1297 + (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false",
1298 + (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false",
1299 + (long unsigned int)sqlite3_column_int64(res, 11),
1300 + (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false",
1301 + sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : string2str(host->health.health_default_exec),
1302 + sqlite3_column_text(res, 17) ? (const char *) sqlite3_column_text(res, 17) : string2str(host->health.health_default_recipient),
1303 + sqlite3_column_int(res, 21),
1304 + sqlite3_column_text(res, 18),
1305 + edit_command,
1306 + sqlite3_column_text(res, 19),
1307 + (long unsigned int)sqlite3_column_int64(res, 7),
1308 + (long unsigned int)sqlite3_column_int64(res, 8),
1309 + (long unsigned int)sqlite3_column_int64(res, 9),
1310 + rrdcalc_status2string(sqlite3_column_int(res, 22)),
1311 + rrdcalc_status2string(sqlite3_column_int(res, 23)),
1312 + sqlite3_column_int(res, 24),
1313 + (long unsigned int)sqlite3_column_int64(res, 12),
1314 + (unsigned int)sqlite3_column_int64(res, 5),
1315 + (unsigned int)sqlite3_column_int64(res, 6),
1316 + 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),
1317 + 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),
1318 + (long unsigned int)sqlite3_column_int64(res, 27),
1319 + (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false");
1320 +
1321 + health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 20), ",\n");
1322 +
1323 + if(unlikely(sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
1324 + buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
1325 + }
1326 +
1327 + buffer_strcat(wb, "\t\t\"value\":");
1328 + if (sqlite3_column_type(res, 25) == SQLITE_NULL)
1329 + buffer_strcat(wb, "null");
1330 + else
1331 + buffer_print_netdata_double(wb, sqlite3_column_double(res, 25));
1332 + buffer_strcat(wb, ",\n");
1333 +
1334 + buffer_strcat(wb, "\t\t\"old_value\":");
1335 + if (sqlite3_column_type(res, 26) == SQLITE_NULL)
1336 + buffer_strcat(wb, "null");
1337 + else
1338 + buffer_print_netdata_double(wb, sqlite3_column_double(res, 26));
1339 + buffer_strcat(wb, "\n");
1340 +
1341 + buffer_strcat(wb, "\t}");
1342 +
1343 + freez(edit_command);
1344 + }
1345 +
1346 + buffer_strcat(wb, "\n]");
1347 +
1348 + rc = sqlite3_finalize(res);
1349 + if (unlikely(rc != SQLITE_OK))
1350 + error_report("Failed to finalize statement for SQL_SELECT_HEALTH_LOG");
1351 +
1352 + buffer_free(command);
1353 +}
database/sqlite/sqlite_health.h
+2
@@ -14,4 +14,6 @@ void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae);
14 void sql_health_alarm_log_cleanup(RRDHOST *host);
15 int alert_hash_and_store_config(uuid_t hash_id, struct alert_config *cfg, int store_hash);
16 void sql_aclk_alert_clean_dead_entries(RRDHOST *host);
17 +int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status);
18 +void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart);
19 #endif //NETDATA_SQLITE_HEALTH_H
health/health.c
+47 -34
@@ -412,17 +412,13 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
412 // find the previous notification for the same alarm
413 // which we have run the exec script
414 // exception: alarms with HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION set
415 + RRDCALC_STATUS last_executed_status = -3;
416 if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
416 - uint32_t id = ae->alarm_id;
417 - ALARM_ENTRY *t;
418 - for(t = ae->next; t ; t = t->next) {
419 - if(t->alarm_id == id && t->flags & HEALTH_ENTRY_FLAG_EXEC_RUN)
420 - break;
421 - }
417 + int ret = sql_health_get_last_executed_event(host, ae, &last_executed_status);
418
423 - if(likely(t)) {
419 + if (likely(ret == 1)) {
420 // we have executed this alarm notification in the past
425 - if(t && t->new_status == ae->new_status) {
421 + if(last_executed_status == ae->new_status) {
422 // don't send the notification for the same status again
423 debug(D_HEALTH, "Health not sending again notification for alarm '%s.%s' status %s", ae_chart_name(ae), ae_name(ae)
424 , rrdcalc_status2string(ae->new_status));
@@ -561,6 +557,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
557 ae->flags |= HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS;
558 ae->exec_spawn_serial = spawn_enq_cmd(command_to_run);
559 enqueue_alarm_notify_in_progress(ae);
560 + health_alarm_log_save(host, ae);
561 } else {
562 error("Failed to format command arguments");
563 }
@@ -628,35 +625,32 @@ static inline void health_alarm_log_process(RRDHOST *host) {
625 // remember this for the next iteration
626 host->health_last_processed_id = first_waiting;
627
631 - bool cleanup_excess_log_entries = host->health_log.count > host->health_log.max;
632 -
633 - if (!cleanup_excess_log_entries)
634 - return;
635 -
636 - // cleanup excess entries in the log
628 + //delete those that are updated, no in progress execution, and is not repeating
629 netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
630
639 - ALARM_ENTRY *last = NULL;
640 - unsigned int count = host->health_log.max * 2 / 3;
641 - for(ae = host->health_log.alarms; ae && count ; count--, last = ae, ae = ae->next) ;
642 -
643 - if(ae && last && last->next == ae)
644 - last->next = NULL;
645 - else
646 - ae = NULL;
647 -
648 - while(ae) {
649 - debug(D_HEALTH, "Health removing alarm log entry with id: %u", ae->unique_id);
650 -
651 - ALARM_ENTRY *t = ae->next;
652 -
653 - if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING))) {
654 - health_alarm_wait_for_execution(ae);
631 + ALARM_ENTRY *prev = host->health_log.alarms;
632 + for(ae = host->health_log.alarms; ae ; ae = ae->next) {
633 +
634 + if((likely(!(ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING)) &&
635 + (ae->flags & HEALTH_ENTRY_FLAG_UPDATED) &&
636 + (ae->flags & HEALTH_ENTRY_FLAG_SAVED) &&
637 + !(ae->flags & HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS))
638 + ||
639 + ((ae->new_status == RRDCALC_STATUS_REMOVED) &&
640 + (ae->flags & HEALTH_ENTRY_FLAG_SAVED) &&
641 + (ae->when + 3600 < now_realtime_sec())))
642 + {
643 +
644 + if (ae == host->health_log.alarms) {
645 + host->health_log.alarms = ae->next;
646 + prev = ae->next;
647 + } else {
648 + prev->next = ae->next;
649 + }
650 health_alarm_log_free_one_nochecks_nounlink(ae);
656 - host->health_log.count--;
657 - }
658 -
659 - ae = t;
651 + ae = prev;
652 + } else
653 + prev = ae;
654 }
655
656 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
@@ -904,8 +898,24 @@ static int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
898 return 0;
899 }
900
901 +static void sql_health_postpone_queue_removed(RRDHOST *host __maybe_unused) {
902 +#ifdef ENABLE_ACLK
903 + if (netdata_cloud_setting) {
904 + struct aclk_sync_host_config *wc = (struct aclk_sync_host_config *)host->aclk_sync_host_config;
905 + if (unlikely(!wc)) {
906 + return;
907 + }
908 +
909 + if (wc->alert_queue_removed >= 1) {
910 + wc->alert_queue_removed+=6;
911 + }
912 + }
913 +#endif
914 +}
915 +
916 static void health_execute_delayed_initializations(RRDHOST *host) {
917 RRDSET *st;
918 + bool must_postpone = false;
919
920 if (!rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION)) return;
921 rrdhost_flag_clear(host, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION);
@@ -941,8 +951,11 @@ static void health_execute_delayed_initializations(RRDHOST *host) {
951 rrdvar_store_for_chart(host, st);
952 }
953 rrddim_foreach_done(rd);
954 + must_postpone = true;
955 }
956 rrdset_foreach_done(st);
957 + if (must_postpone)
958 + sql_health_postpone_queue_removed(host);
959 }
960
961 /**
health/health.h
+1 -3
@@ -41,7 +41,6 @@ void health_reload(void);
41 void health_aggregate_alarms(RRDHOST *host, BUFFER *wb, BUFFER* context, RRDCALC_STATUS status);
42 void health_alarms2json(RRDHOST *host, BUFFER *wb, int all);
43 void health_alarms_values2json(RRDHOST *host, BUFFER *wb, int all);
44 -void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart);
44
45 void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf);
46 void health_api_v1_chart_custom_variables2json(RRDSET *st, BUFFER *buf);
@@ -87,11 +86,10 @@ void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae);
86
87 void *health_cmdapi_thread(void *ptr);
88
90 -void health_label_log_save(RRDHOST *host);
91 -
89 char *health_edit_command_from_source(const char *source);
90 void sql_refresh_hashes(void);
91
92 void health_add_host_labels(void);
93 +void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix);
94
95 #endif //NETDATA_HEALTH_H
health/health_json.c
-170
@@ -13,136 +13,6 @@ void health_string2json(BUFFER *wb, const char *prefix, const char *label, const
13 buffer_sprintf(wb, "%s\"%s\":null%s", prefix, label, suffix);
14 }
15
16 -void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host) {
17 - char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
18 - char config_hash_id[GUID_LEN + 1];
19 - uuid_unparse_lower(ae->config_hash_id, config_hash_id);
20 -
21 - buffer_sprintf(wb,
22 - "\n\t{\n"
23 - "\t\t\"hostname\": \"%s\",\n"
24 - "\t\t\"utc_offset\": %d,\n"
25 - "\t\t\"timezone\": \"%s\",\n"
26 - "\t\t\"unique_id\": %u,\n"
27 - "\t\t\"alarm_id\": %u,\n"
28 - "\t\t\"alarm_event_id\": %u,\n"
29 - "\t\t\"config_hash_id\": \"%s\",\n"
30 - "\t\t\"name\": \"%s\",\n"
31 - "\t\t\"chart\": \"%s\",\n"
32 - "\t\t\"context\": \"%s\",\n"
33 - "\t\t\"family\": \"%s\",\n"
34 - "\t\t\"class\": \"%s\",\n"
35 - "\t\t\"component\": \"%s\",\n"
36 - "\t\t\"type\": \"%s\",\n"
37 - "\t\t\"processed\": %s,\n"
38 - "\t\t\"updated\": %s,\n"
39 - "\t\t\"exec_run\": %lu,\n"
40 - "\t\t\"exec_failed\": %s,\n"
41 - "\t\t\"exec\": \"%s\",\n"
42 - "\t\t\"recipient\": \"%s\",\n"
43 - "\t\t\"exec_code\": %d,\n"
44 - "\t\t\"source\": \"%s\",\n"
45 - "\t\t\"command\": \"%s\",\n"
46 - "\t\t\"units\": \"%s\",\n"
47 - "\t\t\"when\": %lu,\n"
48 - "\t\t\"duration\": %lu,\n"
49 - "\t\t\"non_clear_duration\": %lu,\n"
50 - "\t\t\"status\": \"%s\",\n"
51 - "\t\t\"old_status\": \"%s\",\n"
52 - "\t\t\"delay\": %d,\n"
53 - "\t\t\"delay_up_to_timestamp\": %lu,\n"
54 - "\t\t\"updated_by_id\": %u,\n"
55 - "\t\t\"updates_id\": %u,\n"
56 - "\t\t\"value_string\": \"%s\",\n"
57 - "\t\t\"old_value_string\": \"%s\",\n"
58 - "\t\t\"last_repeat\": \"%lu\",\n"
59 - "\t\t\"silenced\": \"%s\",\n"
60 - , rrdhost_hostname(host)
61 - , host->utc_offset
62 - , rrdhost_abbrev_timezone(host)
63 - , ae->unique_id
64 - , ae->alarm_id
65 - , ae->alarm_event_id
66 - , config_hash_id
67 - , ae_name(ae)
68 - , ae_chart_name(ae)
69 - , ae_chart_context(ae)
70 - , ae_family(ae)
71 - , ae->classification?ae_classification(ae):"Unknown"
72 - , ae->component?ae_component(ae):"Unknown"
73 - , ae->type?ae_type(ae):"Unknown"
74 - , (ae->flags & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false"
75 - , (ae->flags & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false"
76 - , (unsigned long)ae->exec_run_timestamp
77 - , (ae->flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false"
78 - , ae->exec?ae_exec(ae):string2str(host->health.health_default_exec)
79 - , ae->recipient?ae_recipient(ae):string2str(host->health.health_default_recipient)
80 - , ae->exec_code
81 - , ae_source(ae)
82 - , edit_command
83 - , ae_units(ae)
84 - , (unsigned long)ae->when
85 - , (unsigned long)ae->duration
86 - , (unsigned long)ae->non_clear_duration
87 - , rrdcalc_status2string(ae->new_status)
88 - , rrdcalc_status2string(ae->old_status)
89 - , ae->delay
90 - , (unsigned long)ae->delay_up_to_timestamp
91 - , ae->updated_by_id
92 - , ae->updates_id
93 - , ae_new_value_string(ae)
94 - , ae_old_value_string(ae)
95 - , (unsigned long)ae->last_repeat
96 - , (ae->flags & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false"
97 - );
98 -
99 - health_string2json(wb, "\t\t", "info", ae->info ? ae_info(ae) : "", ",\n");
100 -
101 - if(unlikely(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
102 - buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
103 - }
104 -
105 - buffer_strcat(wb, "\t\t\"value\":");
106 - buffer_print_netdata_double(wb, ae->new_value);
107 - buffer_strcat(wb, ",\n");
108 -
109 - buffer_strcat(wb, "\t\t\"old_value\":");
110 - buffer_print_netdata_double(wb, ae->old_value);
111 - buffer_strcat(wb, "\n");
112 -
113 - buffer_strcat(wb, "\t}");
114 -
115 - freez(edit_command);
116 -}
117 -
118 -void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart) {
119 -
120 - buffer_strcat(wb, "[");
121 -
122 - unsigned int max = host->health_log.max;
123 - unsigned int count = 0;
124 -
125 - STRING *chart_string = string_strdupz(chart);
126 -
127 - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
128 -
129 - ALARM_ENTRY *ae;
130 - for (ae = host->health_log.alarms; ae && count < max; ae = ae->next) {
131 - if ((ae->unique_id > after) && (!chart || chart_string == ae->chart)) {
132 - if (likely(count))
133 - buffer_strcat(wb, ",");
134 - health_alarm_entry2json_nolock(wb, ae, host);
135 - count++;
136 - }
137 - }
138 -
139 - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
140 -
141 - string_freez(chart_string);
142 -
143 - buffer_strcat(wb, "\n]\n");
144 -}
145 -
16 static inline void health_rrdcalc_values2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
17 (void)host;
18 buffer_sprintf(wb,
@@ -397,43 +267,3 @@ void health_alarms_values2json(RRDHOST *host, BUFFER *wb, int all) {
267 buffer_strcat(wb, "\n\t}\n}\n");
268 }
269
400 -static int have_recent_alarm(RRDHOST *host, uint32_t alarm_id, uint32_t mark)
401 -{
402 - ALARM_ENTRY *ae = host->health_log.alarms;
403 -
404 - while(ae) {
405 - if (ae->alarm_id == alarm_id && ae->unique_id > mark &&
406 - (ae->new_status != RRDCALC_STATUS_WARNING && ae->new_status != RRDCALC_STATUS_CRITICAL))
407 - return 1;
408 - ae = ae->next;
409 - }
410 - return 0;
411 -}
412 -
413 -void health_active_log_alarms_2json(RRDHOST *host, BUFFER *wb) {
414 - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
415 -
416 - buffer_sprintf(wb, "[\n");
417 -
418 - unsigned int max = host->health_log.max;
419 - unsigned int count = 0;
420 - ALARM_ENTRY *ae;
421 - for(ae = host->health_log.alarms; ae && count < max ; ae = ae->next) {
422 - if (!ae->updated_by_id &&
423 - ((ae->new_status == RRDCALC_STATUS_WARNING || ae->new_status == RRDCALC_STATUS_CRITICAL) ||
424 - ((ae->old_status == RRDCALC_STATUS_WARNING || ae->old_status == RRDCALC_STATUS_CRITICAL) &&
425 - ae->new_status == RRDCALC_STATUS_REMOVED))) {
426 -
427 - if (have_recent_alarm(host, ae->alarm_id, ae->unique_id))
428 - continue;
429 -
430 - if (likely(count))
431 - buffer_strcat(wb, ",");
432 - health_alarm_entry2json_nolock(wb, ae, host);
433 - count++;
434 - }
435 - }
436 - buffer_strcat(wb, "]");
437 -
438 - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
439 -}
web/api/web_api_v1.c
+1 -1
@@ -354,7 +354,7 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
354
355 buffer_flush(w->response.data);
356 w->response.data->content_type = CT_APPLICATION_JSON;
357 - health_alarm_log2json(host, w->response.data, after, chart);
357 + sql_health_alarm_log2json(host, w->response.data, after, chart);
358 return HTTP_RESP_OK;
359 }
360