@cryptotaxi247 / netdata-1 / commits / 6e1e97c5e

Use a single health log table (#15157)

* move old health log tables to one * change table in sqlite_health * remove check for off period of agent * changes in aclk_alert * fixes * add new field insert_mark_timestamp * cleanup * remove hostname, create the health log table during sqlite init * create the health_log during migration * move source from health_log to alert_hash. Remove class, component and type field from health_log * Register now_usec sqlite function * use global_id instead of insert_mark_timestamp. Use function now_usec to populate it * create functions earlier to have them during migration * small unit test fix * create additional health_log_detail table. Do the insert of an alert event on both * do the update on health_log_detail * change more queries * more indexes, fix inject removed * change last executed and select health log queries * random uuid for sqlite * do migration from old tables * queries to send alerts to cloud * cleanup queries * get an alarm id from db if not found in memory * small fix on query * add info when migration completes * dont pick health_log_detail during migration * check proper old health_log table * safer migration * proper log sent alerts. small fix in claimed cleanup * cleanups * extra check for cleanup * also get an alarm_event_id from sql * check for empty source * remove cleanup of main health log table --------- Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>

Emmanuel Vasilakis committed Jun 21, 2023 at 15:39 UTC 6e1e97c5e8d136162368e16d27d7aa09b047f8c6
12 files changed +906 -425
daemon/unit_test.c
+12
@@ -1662,6 +1662,18 @@ int test_sqlite(void) {
1662 return 1;
1663 }
1664
1665 + rc = sqlite3_create_function(db_meta, "now_usec", 1, SQLITE_ANY, 0, sqlite_now_usec, 0, 0);
1666 + if (unlikely(rc != SQLITE_OK)) {
1667 + fprintf(stderr, "Failed to register internal now_usec function");
1668 + return 1;
1669 + }
1670 +
1671 + rc = sqlite3_exec_monitored(db_meta, "UPDATE MINE SET id1=now_usec(0);", 0, 0, NULL);
1672 + if (rc != SQLITE_OK) {
1673 + fprintf(stderr,"Failed to test SQLite: Update with now_usec() failed\n");
1674 + return 1;
1675 + }
1676 +
1677 BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE, NULL);
1678 char *uuid_str = "0000_000";
1679
database/rrdcalc.c
+7 -3
@@ -52,10 +52,14 @@ uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint3
52 alarm_id = ae->alarm_id;
53
54 else {
55 - if (unlikely(!host->health_log.next_alarm_id))
56 - host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
55 + alarm_id = sql_get_alarm_id(host, chart, name, next_event_id);
56
58 - alarm_id = host->health_log.next_alarm_id++;
57 + if (!alarm_id) {
58 + if (unlikely(!host->health_log.next_alarm_id))
59 + host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
60 +
61 + alarm_id = host->health_log.next_alarm_id++;
62 + }
63 }
64
65 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
database/rrdcalc.h
+1
@@ -211,6 +211,7 @@ struct alert_config {
211 STRING *repeat;
212 STRING *host_labels;
213 STRING *chart_labels;
214 + STRING *source;
215
216 STRING *p_db_lookup_dimensions;
217 STRING *p_db_lookup_method;
database/sqlite/sqlite_aclk.h
+11 -1
@@ -27,12 +27,20 @@ static inline void uuid_unparse_lower_fix(uuid_t *uuid, char *out)
27 out[23] = '_';
28 }
29
30 +static inline int uuid_parse_fix(char *in, uuid_t uuid)
31 +{
32 + in[8] = '-';
33 + in[13] = '-';
34 + in[18] = '-';
35 + in[23] = '-';
36 + return uuid_parse(in, uuid);
37 +}
38 +
39 static inline int claimed()
40 {
41 return localhost->aclk_state.claimed_id != NULL;
42 }
43
35 -
44 #define TABLE_ACLK_ALERT "CREATE TABLE IF NOT EXISTS aclk_alert_%s (sequence_id INTEGER PRIMARY KEY, " \
45 "alert_unique_id, date_created, date_submitted, date_cloud_ack, filtered_alert_unique_id NOT NULL, " \
46 "unique(alert_unique_id));"
@@ -79,6 +87,8 @@ struct aclk_sync_host_config {
87 char uuid_str[UUID_STR_LEN];
88 char node_id[UUID_STR_LEN];
89 char *alerts_snapshot_uuid; // will contain the snapshot_uuid value if snapshot was requested
90 + uint64_t alerts_log_first_sequence_id;
91 + uint64_t alerts_log_last_sequence_id;
92 };
93
94 extern sqlite3 *db_meta;
database/sqlite/sqlite_aclk_alert.c
+125 -110
@@ -7,37 +7,7 @@
7 #include "../../aclk/aclk_alarm_api.h"
8 #endif
9
10 -#define SQL_GET_ALERT_REMOVE_TIME "SELECT when_key FROM health_log_%s WHERE alarm_id = %u " \
11 - "AND unique_id > %u AND unique_id < %u " \
12 - "AND new_status = -2;"
13 -
14 -time_t removed_when(uint32_t alarm_id, uint32_t before_unique_id, uint32_t after_unique_id, char *uuid_str) {
15 - sqlite3_stmt *res = NULL;
16 - time_t when = 0;
17 - char sql[ACLK_SYNC_QUERY_SIZE];
18 -
19 - snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_GET_ALERT_REMOVE_TIME, uuid_str, alarm_id, after_unique_id, before_unique_id);
20 -
21 - int rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
22 - if (rc != SQLITE_OK) {
23 - error_report("Failed to prepare statement when trying to find removed gap.");
24 - return 0;
25 - }
26 -
27 - rc = sqlite3_step_monitored(res);
28 - if (likely(rc == SQLITE_ROW)) {
29 - when = (time_t) sqlite3_column_int64(res, 0);
30 - }
31 -
32 - rc = sqlite3_finalize(res);
33 - if (unlikely(rc != SQLITE_OK))
34 - error_report("Failed to finalize statement when trying to find removed gap, rc = %d", rc);
35 -
36 - return when;
37 -}
38 -
10 #define SQL_UPDATE_FILTERED_ALERT "UPDATE aclk_alert_%s SET filtered_alert_unique_id = %u where filtered_alert_unique_id = %u"
40 -
11 void update_filtered(ALARM_ENTRY *ae, uint32_t unique_id, char *uuid_str) {
12 char sql[ACLK_SYNC_QUERY_SIZE];
13 snprintfz(sql, ACLK_SYNC_QUERY_SIZE-1, SQL_UPDATE_FILTERED_ALERT, uuid_str, ae->unique_id, unique_id);
@@ -45,17 +15,16 @@ void update_filtered(ALARM_ENTRY *ae, uint32_t unique_id, char *uuid_str) {
15 ae->flags |= HEALTH_ENTRY_FLAG_ACLK_QUEUED;
16 }
17
48 -#define SQL_SELECT_ALERT_BY_UNIQUE_ID "SELECT hl.unique_id FROM health_log_%s hl, alert_hash ah WHERE hl.unique_id = %u " \
49 - "AND hl.config_hash_id = ah.hash_id " \
18 +#define SQL_SELECT_VARIABLE_ALERT_BY_UNIQUE_ID "SELECT hld.unique_id FROM health_log hl, alert_hash ah, health_log_detail hld WHERE hld.unique_id = %u " \
19 + "AND hl.config_hash_id = ah.hash_id AND hld.health_log_id = hl.health_log_id AND host_id = @host_id " \
20 "AND ah.warn IS NULL AND ah.crit IS NULL;"
51 -
52 -static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char *uuid_str) {
21 +static inline bool is_event_from_alert_variable_config(uint32_t unique_id, uuid_t *host_id) {
22 sqlite3_stmt *res = NULL;
23 int rc = 0;
24 bool ret = false;
25
26 char sql[ACLK_SYNC_QUERY_SIZE];
58 - snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_ALERT_BY_UNIQUE_ID, uuid_str, unique_id);
27 + snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_VARIABLE_ALERT_BY_UNIQUE_ID, unique_id);
28
29 rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
30 if (rc != SQLITE_OK) {
@@ -63,6 +32,13 @@ static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char
32 return false;
33 }
34
35 + rc = sqlite3_bind_blob(res, 1, host_id, sizeof(*host_id), SQLITE_STATIC);
36 + if (unlikely(rc != SQLITE_OK)) {
37 + error_report("Failed to bind host_id for checking alert variable.");
38 + sqlite3_finalize(res);
39 + return false;
40 + }
41 +
42 rc = sqlite3_step_monitored(res);
43 if (likely(rc == SQLITE_ROW)) {
44 ret = true;
@@ -76,13 +52,12 @@ static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char
52 }
53
54 #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 " \
82 - "WHERE hl.unique_id = aa.filtered_alert_unique_id " \
83 - "AND hl.alarm_id = %u " \
84 - "ORDER BY alarm_event_id DESC LIMIT 1;"
55
56 +//decide if some events should be sent or not
57 +#define SQL_SELECT_ALERT_BY_ID "SELECT hld.new_status, hl.config_hash_id, hld.unique_id FROM health_log hl, aclk_alert_%s aa, health_log_detail hld " \
58 + "WHERE hld.unique_id = aa.filtered_alert_unique_id " \
59 + "AND hld.alarm_id = %u AND hl.host_id = @host_id AND hl.health_log_id = hld.health_log_id " \
60 + "ORDER BY hld.alarm_event_id DESC LIMIT 1;"
61 int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae)
62 {
63 sqlite3_stmt *res = NULL;
@@ -104,7 +79,7 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae)
79
80 //get the previous sent event of this alarm_id
81 //base the search on the last filtered event
107 - snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_ALERT_BY_ID, uuid_str, uuid_str, ae->alarm_id);
82 + snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_ALERT_BY_ID, uuid_str, ae->alarm_id);
83
84 int rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
85 if (rc != SQLITE_OK) {
@@ -113,6 +88,13 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae)
88 return send;
89 }
90
91 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
92 + if (unlikely(rc != SQLITE_OK)) {
93 + error_report("Failed to bind host_id for checking alert variable.");
94 + sqlite3_finalize(res);
95 + return false;
96 + }
97 +
98 rc = sqlite3_step_monitored(res);
99 if (likely(rc == SQLITE_ROW)) {
100 status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
@@ -142,20 +124,6 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae)
124 goto done;
125 }
126
145 - //detect a long off period of the agent, TODO make global
146 - if (ae->new_status == RRDCALC_STATUS_WARNING || ae->new_status == RRDCALC_STATUS_CRITICAL) {
147 - time_t when = removed_when(ae->alarm_id, ae->unique_id, unique_id, uuid_str);
148 -
149 - if (when && (when + (time_t)MAX_REMOVED_PERIOD) < ae->when) {
150 - send = 1;
151 - goto done;
152 - } else {
153 - send = 0;
154 - update_filtered(ae, unique_id, uuid_str);
155 - goto done;
156 - }
157 - }
158 -
127 done:
128 rc = sqlite3_finalize(res);
129 if (unlikely(rc != SQLITE_OK))
@@ -164,12 +132,8 @@ done:
132 return send;
133 }
134
167 -// will replace call to aclk_update_alarm in health/health_log.c
168 -// and handle both cases
169 -
135 #define SQL_QUEUE_ALERT_TO_CLOUD "INSERT INTO aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \
136 "VALUES (@alert_unique_id, unixepoch(), @alert_unique_id) ON CONFLICT (alert_unique_id) do nothing;"
172 -
137 int sql_queue_alarm_to_aclk(RRDHOST *host, ALARM_ENTRY *ae, int skip_filter)
138 {
139 if(!service_running(SERVICE_ACLK))
@@ -193,7 +157,7 @@ int sql_queue_alarm_to_aclk(RRDHOST *host, ALARM_ENTRY *ae, int skip_filter)
157 char uuid_str[UUID_STR_LEN];
158 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
159
196 - if (is_event_from_alert_variable_config(ae->unique_id, uuid_str))
160 + if (is_event_from_alert_variable_config(ae->unique_id, &host->host_uuid))
161 return 0;
162
163 sqlite3_stmt *res_alert = NULL;
@@ -305,21 +269,18 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc)
269
270 sqlite3_stmt *res = NULL;
271
308 - buffer_sprintf(sql, "select aa.sequence_id, hl.unique_id, hl.alarm_id, hl.config_hash_id, hl.updated_by_id, hl.when_key, " \
309 - " hl.duration, hl.non_clear_duration, hl.flags, hl.exec_run_timestamp, hl.delay_up_to_timestamp, hl.name, " \
310 - " hl.chart, hl.family, hl.exec, hl.recipient, hl.source, hl.units, hl.info, hl.exec_code, hl.new_status, " \
311 - " hl.old_status, hl.delay, hl.new_value, hl.old_value, hl.last_repeat, hl.chart_context, hl.transition_id, hl.alarm_event_id " \
312 - " from health_log_%s hl, aclk_alert_%s aa " \
313 - " where hl.unique_id = aa.alert_unique_id and aa.date_submitted is null " \
314 - " order by aa.sequence_id asc limit %d;", wc->uuid_str, wc->uuid_str, limit);
272 + buffer_sprintf(sql, "select aa.sequence_id, hld.unique_id, hld.alarm_id, hl.config_hash_id, hld.updated_by_id, hld.when_key, " \
273 + " hld.duration, hld.non_clear_duration, hld.flags, hld.exec_run_timestamp, hld.delay_up_to_timestamp, hl.name, " \
274 + " hl.chart, hl.family, hl.exec, hl.recipient, ha.source, hl.units, hld.info, hld.exec_code, hld.new_status, " \
275 + " hld.old_status, hld.delay, hld.new_value, hld.old_value, hld.last_repeat, hl.chart_context, hld.transition_id, hld.alarm_event_id " \
276 + " from health_log hl, aclk_alert_%s aa, alert_hash ha, health_log_detail hld " \
277 + " where hld.unique_id = aa.alert_unique_id and hl.config_hash_id = ha.hash_id and aa.date_submitted is null " \
278 + " and hl.host_id = @host_id and hl.health_log_id = hld.health_log_id " \
279 + " order by aa.sequence_id asc limit %d;", wc->uuid_str, limit);
280
281 rc = sqlite3_prepare_v2(db_meta, buffer_tostring(sql), -1, &res, 0);
282 if (rc != SQLITE_OK) {
283
319 - // Try to create tables
320 - if (wc->host)
321 - sql_create_health_log_table(wc->host);
322 -
284 BUFFER *sql_fix = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
285 buffer_sprintf(sql_fix, TABLE_ACLK_ALERT, wc->uuid_str);
286 rc = db_execute(db_meta, buffer_tostring(sql_fix));
@@ -344,10 +305,15 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc)
305 }
306 }
307
347 - uint64_t first_sequence_id = 0;
348 - uint64_t last_sequence_id = 0;
349 - static __thread uint64_t log_first_sequence_id = 0;
350 - static __thread uint64_t log_last_sequence_id = 0;
308 + rc = sqlite3_bind_blob(res, 1, &wc->host->host_uuid, sizeof(wc->host->host_uuid), SQLITE_STATIC);
309 + if (unlikely(rc != SQLITE_OK)) {
310 + error_report("Failed to bind host_id for pushing alert event.");
311 + sqlite3_finalize(res);
312 + return;
313 + }
314 +
315 + uint64_t first_sequence_id = 0;
316 + uint64_t last_sequence_id = 0;
317
318 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
319 struct alarm_log_entry alarm_log;
@@ -371,7 +337,8 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc)
337 alarm_log.timezone = strdupz(rrdhost_abbrev_timezone(wc->host));
338 alarm_log.exec_path = sqlite3_column_bytes(res, 14) > 0 ? strdupz((char *)sqlite3_column_text(res, 14)) :
339 strdupz((char *)string2str(wc->host->health.health_default_exec));
374 - alarm_log.conf_source = strdupz((char *)sqlite3_column_text(res, 16));
340 +
341 + alarm_log.conf_source = sqlite3_column_bytes(res, 16) > 0 ? strdupz((char *)sqlite3_column_text(res, 16)) : strdupz("");
342
343 char *edit_command = sqlite3_column_bytes(res, 16) > 0 ?
344 health_edit_command_from_source((char *)sqlite3_column_text(res, 16)) :
@@ -420,11 +387,11 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc)
387 if (first_sequence_id == 0)
388 first_sequence_id = (uint64_t) sqlite3_column_int64(res, 0);
389
423 - if (log_first_sequence_id == 0)
424 - log_first_sequence_id = (uint64_t) sqlite3_column_int64(res, 0);
390 + if (wc->alerts_log_first_sequence_id == 0)
391 + wc->alerts_log_first_sequence_id = (uint64_t) sqlite3_column_int64(res, 0);
392
393 last_sequence_id = (uint64_t) sqlite3_column_int64(res, 0);
427 - log_last_sequence_id = (uint64_t) sqlite3_column_int64(res, 0);
394 + wc->alerts_log_last_sequence_id = (uint64_t) sqlite3_column_int64(res, 0);
395
396 destroy_alarm_log_entry(&alarm_log);
397 freez(edit_command);
@@ -443,15 +410,15 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc)
410 rrdhost_flag_set(wc->host, RRDHOST_FLAG_ACLK_STREAM_ALERTS);
411
412 } else {
446 - if (log_first_sequence_id)
413 + if (wc->alerts_log_first_sequence_id)
414 log_access(
415 "ACLK RES [%s (%s)]: ALERTS SENT from %" PRIu64 " to %" PRIu64 "",
416 wc->node_id,
417 wc->host ? rrdhost_hostname(wc->host) : "N/A",
451 - log_first_sequence_id,
452 - log_last_sequence_id);
453 - log_first_sequence_id = 0;
454 - log_last_sequence_id = 0;
418 + wc->alerts_log_first_sequence_id,
419 + wc->alerts_log_last_sequence_id);
420 + wc->alerts_log_first_sequence_id = 0;
421 + wc->alerts_log_last_sequence_id = 0;
422 }
423
424 rc = sqlite3_finalize(res);
@@ -486,17 +453,49 @@ void sql_queue_existing_alerts_to_aclk(RRDHOST *host)
453 char uuid_str[UUID_STR_LEN];
454 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
455 BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
456 + sqlite3_stmt *res = NULL;
457 + int rc;
458
490 - buffer_sprintf(sql,"delete from aclk_alert_%s; " \
491 - "insert into aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \
492 - "select unique_id alert_unique_id, unixepoch(), unique_id alert_unique_id from health_log_%s " \
493 - "where new_status <> 0 and new_status <> -2 and config_hash_id is not null and updated_by_id = 0 " \
494 - "order by unique_id asc on conflict (alert_unique_id) do nothing;", uuid_str, uuid_str, uuid_str);
459 + netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
460
496 - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
461 + buffer_sprintf(sql, "delete from aclk_alert_%s; ", uuid_str);
462 + if (unlikely(db_execute(db_meta, buffer_tostring(sql)))) {
463 + netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
464 + buffer_free(sql);
465 + return;
466 + }
467
498 - if (unlikely(db_execute(db_meta, buffer_tostring(sql))))
499 - error_report("Failed to queue existing ACLK alert events for host %s", rrdhost_hostname(host));
468 + buffer_flush(sql);
469 + buffer_sprintf(sql, "insert into aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \
470 + "select hld.unique_id alert_unique_id, unixepoch(), hld.unique_id alert_unique_id from health_log_detail hld, health_log hl " \
471 + "where hld.new_status <> 0 and hld.new_status <> -2 and hl.health_log_id = hld.health_log_id and hl.config_hash_id is not null " \
472 + "and hld.updated_by_id = 0 and hl.host_id = @host_id order by hld.unique_id asc on conflict (alert_unique_id) do nothing;", uuid_str);
473 +
474 + rc = sqlite3_prepare_v2(db_meta, buffer_tostring(sql), -1, &res, 0);
475 + if (rc != SQLITE_OK) {
476 + error_report("Failed to prepare statement when trying to queue existing alerts.");
477 + netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
478 + buffer_free(sql);
479 + return;
480 + }
481 +
482 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
483 + if (unlikely(rc != SQLITE_OK)) {
484 + error_report("Failed to bind host_id for when trying to queue existing alerts.");
485 + sqlite3_finalize(res);
486 + netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
487 + buffer_free(sql);
488 + return;
489 + }
490 +
491 + rc = execute_insert(res);
492 + if (unlikely(rc != SQLITE_DONE)) {
493 + error_report("Failed to queue existing alerts, rc = %d", rc);
494 + }
495 +
496 + rc = sqlite3_finalize(res);
497 + if (unlikely(rc != SQLITE_OK))
498 + error_report("Failed to finalize statement to queue existing alerts, rc = %d", rc);
499
500 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
501
@@ -523,7 +522,6 @@ void aclk_send_alarm_configuration(char *config_hash)
522 "module, charts, families, lookup, every, units, green, red, calc, warn, crit, to_key, exec, delay, repeat, info," \
523 "options, host_labels, p_db_lookup_dimensions, p_db_lookup_method, p_db_lookup_options, p_db_lookup_after," \
524 "p_db_lookup_before, p_update_every FROM alert_hash WHERE hash_id = @hash_id;"
526 -
525 int aclk_push_alert_config_event(char *node_id __maybe_unused, char *config_hash __maybe_unused)
526 {
527 int rc = 0;
@@ -685,13 +683,11 @@ void aclk_start_alert_streaming(char *node_id, bool resets)
683 }
684
685 #define SQL_QUEUE_REMOVE_ALERTS "INSERT INTO aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \
688 - "SELECT unique_id alert_unique_id, UNIXEPOCH(), unique_id alert_unique_id FROM health_log_%s " \
689 - "WHERE new_status = -2 AND updated_by_id = 0 AND unique_id NOT IN " \
690 - "(SELECT alert_unique_id FROM aclk_alert_%s) " \
691 - "AND config_hash_id NOT IN (select hash_id from alert_hash where warn is null and crit is null) " \
692 - "ORDER BY unique_id ASC " \
693 - "ON CONFLICT (alert_unique_id) DO NOTHING;"
694 -
686 + "SELECT hld.unique_id alert_unique_id, UNIXEPOCH(), hld.unique_id alert_unique_id FROM health_log hl, health_log_detail hld " \
687 + "WHERE hl.host_id = @host_id AND hl.health_log_id = hld.health_log_id AND hld.new_status = -2 AND hld.updated_by_id = 0 " \
688 + "AND hld.unique_id NOT IN (SELECT alert_unique_id FROM aclk_alert_%s) " \
689 + "AND hl.config_hash_id NOT IN (select hash_id from alert_hash where warn is null and crit is null) " \
690 + "ORDER BY hld.unique_id ASC ON CONFLICT (alert_unique_id) DO NOTHING;"
691 void sql_process_queue_removed_alerts_to_aclk(char *node_id)
692 {
693 struct aclk_sync_host_config *wc;
@@ -702,15 +698,35 @@ void sql_process_queue_removed_alerts_to_aclk(char *node_id)
698 return;
699
700 char sql[ACLK_SYNC_QUERY_SIZE * 2];
701 + sqlite3_stmt *res = NULL;
702
706 - snprintfz(sql,ACLK_SYNC_QUERY_SIZE * 2 - 1, SQL_QUEUE_REMOVE_ALERTS, wc->uuid_str, wc->uuid_str, wc->uuid_str);
703 + snprintfz(sql, ACLK_SYNC_QUERY_SIZE * 2 - 1, SQL_QUEUE_REMOVE_ALERTS, wc->uuid_str, wc->uuid_str);
704
708 - if (unlikely(db_execute(db_meta, sql))) {
709 - log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS FAILED", wc->node_id, rrdhost_hostname(wc->host));
710 - error_report("Failed to queue ACLK alert removed entries for host %s", rrdhost_hostname(wc->host));
705 + int rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
706 + if (rc != SQLITE_OK) {
707 + error_report("Failed to prepare statement when trying to queue removed alerts.");
708 + return;
709 + }
710 +
711 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
712 + if (unlikely(rc != SQLITE_OK)) {
713 + error_report("Failed to bind host_id for when trying to queue remvoed alerts.");
714 + sqlite3_finalize(res);
715 + return;
716 + }
717 +
718 + rc = execute_insert(res);
719 + if (unlikely(rc != SQLITE_DONE)) {
720 + sqlite3_finalize(res);
721 + error_report("Failed to queue removed alerts, rc = %d", rc);
722 + return;
723 }
712 - else
713 - log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS", wc->node_id, rrdhost_hostname(wc->host));
724 +
725 + rc = sqlite3_finalize(res);
726 + if (unlikely(rc != SQLITE_OK))
727 + error_report("Failed to finalize statement to queue removed alerts, rc = %d", rc);
728 +
729 + log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS", wc->node_id, rrdhost_hostname(wc->host));
730
731 rrdhost_flag_set(wc->host, RRDHOST_FLAG_ACLK_STREAM_ALERTS);
732 wc->alert_queue_removed = 0;
@@ -886,7 +902,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused)
902 if (have_recent_alarm(host, ae->alarm_id, ae->unique_id))
903 continue;
904
889 - if (is_event_from_alert_variable_config(ae->unique_id, uuid_str))
905 + if (is_event_from_alert_variable_config(ae->unique_id, &host->host_uuid))
906 continue;
907
908 cnt++;
@@ -918,7 +934,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused)
934 if (have_recent_alarm(host, ae->alarm_id, ae->unique_id))
935 continue;
936
921 - if (is_event_from_alert_variable_config(ae->unique_id, uuid_str))
937 + if (is_event_from_alert_variable_config(ae->unique_id, &host->host_uuid))
938 continue;
939
940 cnt++;
@@ -984,7 +1000,6 @@ void sql_aclk_alert_clean_dead_entries(RRDHOST *host)
1000 #define SQL_GET_MIN_MAX_ALERT_SEQ "SELECT MIN(sequence_id), MAX(sequence_id), " \
1001 "(SELECT MAX(sequence_id) FROM aclk_alert_%s WHERE date_submitted IS NOT NULL) " \
1002 "FROM aclk_alert_%s WHERE date_submitted IS NULL;"
987 -
1003 int get_proto_alert_status(RRDHOST *host, struct proto_alert_status *proto_alert_status)
1004 {
1005 int rc;
database/sqlite/sqlite_db_migration.c
+72 -1
@@ -11,7 +11,6 @@ static int return_int_cb(void *data, int argc, char **argv, char **column)
11 return 0;
12 }
13
14 -
14 int table_exists_in_database(const char *table)
15 {
16 char *err_msg = NULL;
@@ -214,6 +213,77 @@ static int do_migration_v7_v8(sqlite3 *database, const char *name)
213 return 0;
214 }
215
216 +static int do_migration_v8_v9(sqlite3 *database, const char *name)
217 +{
218 + info("Running database migration %s", name);
219 +
220 + char sql[2048];
221 + int rc;
222 + sqlite3_stmt *res = NULL;
223 +
224 + //create the health_log table and it's index
225 + snprintfz(sql, 2047, "CREATE TABLE IF NOT EXISTS health_log (health_log_id INTEGER PRIMARY KEY, host_id blob, alarm_id int, " \
226 + "config_hash_id blob, name text, chart text, family text, recipient text, units text, exec text, " \
227 + "chart_context text, last_transition_id blob, UNIQUE (host_id, alarm_id)) ;");
228 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
229 +
230 + //TODO indexes
231 + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_ind_1 ON health_log (host_id);");
232 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
233 +
234 + snprintfz(sql, 2047, "CREATE TABLE IF NOT EXISTS health_log_detail (health_log_id int, unique_id int, alarm_id int, alarm_event_id int, " \
235 + "updated_by_id int, updates_id int, when_key int, duration int, non_clear_duration int, " \
236 + "flags int, exec_run_timestamp int, delay_up_to_timestamp int, " \
237 + "info text, exec_code int, new_status real, old_status real, delay int, " \
238 + "new_value double, old_value double, last_repeat int, transition_id blob, global_id int, host_id blob);");
239 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
240 +
241 + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_1 ON health_log_detail (unique_id);");
242 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
243 + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_2 ON health_log_detail (global_id);");
244 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
245 + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_3 ON health_log_detail (transition_id);");
246 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
247 +
248 + snprintfz(sql, 2047, "ALTER TABLE alert_hash ADD source text;");
249 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
250 +
251 + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS alert_hash_index ON alert_hash (hash_id);");
252 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
253 +
254 + snprintfz(sql, 2047, "SELECT name FROM sqlite_schema WHERE type ='table' AND name LIKE 'health_log_%%' AND name <> 'health_log_detail';");
255 + rc = sqlite3_prepare_v2(database, sql, -1, &res, 0);
256 + if (rc != SQLITE_OK) {
257 + error_report("Failed to prepare statement to alter health_log tables");
258 + return 1;
259 + }
260 +
261 + DICTIONARY *dict_tables = dictionary_create(DICT_OPTION_NONE);
262 +
263 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
264 + char *table = strdupz((char *) sqlite3_column_text(res, 0));
265 + if (health_migrate_old_health_log_table(table)) {
266 + dictionary_set(dict_tables, table, NULL, 0);
267 + }
268 + freez(table);
269 + }
270 +
271 + rc = sqlite3_finalize(res);
272 + if (unlikely(rc != SQLITE_OK))
273 + error_report("Failed to finalize statement when copying health_log tables, rc = %d", rc);
274 +
275 + char *table = NULL;
276 + dfe_start_read(dict_tables, table) {
277 + sql_drop_table(table_dfe.name);
278 + }
279 + dfe_done(table);
280 + dictionary_destroy(dict_tables);
281 +
282 + snprintfz(sql, 2047, "ALTER TABLE health_log_detail DROP COLUMN host_id;");
283 + sqlite3_exec_monitored(database, sql, 0, 0, NULL);
284 +
285 + return 0;
286 +}
287
288 static int do_migration_noop(sqlite3 *database, const char *name)
289 {
@@ -266,6 +336,7 @@ DATABASE_FUNC_MIGRATION_LIST migration_action[] = {
336 {.name = "v5 to v6", .func = do_migration_v5_v6},
337 {.name = "v6 to v7", .func = do_migration_v6_v7},
338 {.name = "v7 to v8", .func = do_migration_v7_v8},
339 + {.name = "v8 to v9", .func = do_migration_v8_v9},
340 // the terminator of this array
341 {.name = NULL, .func = NULL}
342 };
database/sqlite/sqlite_functions.c
+74 -5
@@ -3,7 +3,7 @@
3 #include "sqlite_functions.h"
4 #include "sqlite_db_migration.h"
5
6 -#define DB_METADATA_VERSION 8
6 +#define DB_METADATA_VERSION 9
7
8 const char *database_config[] = {
9 "CREATE TABLE IF NOT EXISTS host(host_id BLOB PRIMARY KEY, hostname TEXT NOT NULL, "
@@ -32,7 +32,9 @@ const char *database_config[] = {
32 "every text, units text, calc text, families text, plugin text, module text, charts text, green text, "
33 "red text, warn text, crit text, exec text, to_key text, info text, delay text, options text, "
34 "repeat text, host_labels text, p_db_lookup_dimensions text, p_db_lookup_method text, p_db_lookup_options int, "
35 - "p_db_lookup_after int, p_db_lookup_before int, p_update_every int);",
35 + "p_db_lookup_after int, p_db_lookup_before int, p_update_every int, source text);",
36 +
37 + "CREATE INDEX IF NOT EXISTS alert_hash_index ON alert_hash (hash_id);",
38
39 "CREATE TABLE IF NOT EXISTS host_info(host_id blob, system_key text NOT NULL, system_value text NOT NULL, "
40 "date_created INT, PRIMARY KEY(host_id, system_key));",
@@ -43,6 +45,24 @@ const char *database_config[] = {
45 "CREATE TRIGGER IF NOT EXISTS ins_host AFTER INSERT ON host BEGIN INSERT INTO node_instance (host_id, date_created)"
46 " SELECT new.host_id, unixepoch() WHERE new.host_id NOT IN (SELECT host_id FROM node_instance); END;",
47
48 + "CREATE TABLE IF NOT EXISTS health_log (health_log_id INTEGER PRIMARY KEY, host_id blob, alarm_id int, "
49 + "config_hash_id blob, name text, chart text, family text, recipient text, units text, exec text, "
50 + "chart_context text, last_transition_id blob, UNIQUE (host_id, alarm_id)) ;",
51 +
52 + //TODO indexes
53 + "CREATE INDEX IF NOT EXISTS health_log_ind_1 ON health_log (host_id);",
54 +
55 + "CREATE TABLE IF NOT EXISTS health_log_detail (health_log_id int, unique_id int, alarm_id int, alarm_event_id int, "
56 + "updated_by_id int, updates_id int, when_key int, duration int, non_clear_duration int, "
57 + "flags int, exec_run_timestamp int, delay_up_to_timestamp int, "
58 + "info text, exec_code int, new_status real, old_status real, delay int, "
59 + "new_value double, old_value double, last_repeat int, transition_id blob, global_id int);",
60 +
61 + "CREATE INDEX IF NOT EXISTS health_log_d_ind_1 ON health_log_detail (unique_id);",
62 + "CREATE INDEX IF NOT EXISTS health_log_d_ind_2 ON health_log_detail (global_id);",
63 + "CREATE INDEX IF NOT EXISTS health_log_d_ind_3 ON health_log_detail (transition_id);",
64 + //TODO more indexes
65 +
66 NULL
67 };
68
@@ -336,6 +356,30 @@ static void sqlite_uuid_parse(sqlite3_context *context, int argc, sqlite3_value
356 sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT);
357 }
358
359 +void sqlite_now_usec(sqlite3_context *context, int argc, sqlite3_value **argv)
360 +{
361 + if (argc != 1 ){
362 + sqlite3_result_null(context);
363 + return ;
364 + }
365 +
366 + if (sqlite3_value_int(argv[0]) != 0) {
367 + struct timespec req = {.tv_sec = 0, .tv_nsec = 1};
368 + nanosleep(&req, NULL);
369 + }
370 +
371 + sqlite3_result_int64(context, (sqlite_int64) now_realtime_usec());
372 +}
373 +
374 +void sqlite_uuid_random(sqlite3_context *context, int argc, sqlite3_value **argv)
375 +{
376 + (void)argc;
377 + (void)argv;
378 +
379 + uuid_t uuid;
380 + uuid_generate_random(uuid);
381 + sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT);
382 +}
383
384 /*
385 * Initialize the SQLite database
@@ -405,6 +449,18 @@ int sql_init_database(db_check_action_type_t rebuild, int memory)
449 char buf[1024 + 1] = "";
450 const char *list[2] = { buf, NULL };
451
452 + rc = sqlite3_create_function(db_meta, "u2h", 1, SQLITE_ANY | SQLITE_DETERMINISTIC, 0, sqlite_uuid_parse, 0, 0);
453 + if (unlikely(rc != SQLITE_OK))
454 + error_report("Failed to register internal u2h function");
455 +
456 + rc = sqlite3_create_function(db_meta, "now_usec", 1, SQLITE_ANY, 0, sqlite_now_usec, 0, 0);
457 + if (unlikely(rc != SQLITE_OK))
458 + error_report("Failed to register internal now_usec function");
459 +
460 + rc = sqlite3_create_function(db_meta, "uuid_random", 0, SQLITE_ANY, 0, sqlite_uuid_random, 0, 0);
461 + if (unlikely(rc != SQLITE_OK))
462 + error_report("Failed to register internal uuid_random function");
463 +
464 int target_version = DB_METADATA_VERSION;
465
466 if (likely(!memory))
@@ -454,9 +510,6 @@ int sql_init_database(db_check_action_type_t rebuild, int memory)
510
511 initialize_thread_key_pool();
512
457 - rc = sqlite3_create_function(db_meta, "u2h", 1, SQLITE_ANY | SQLITE_DETERMINISTIC, 0, sqlite_uuid_parse, 0, 0);
458 - if (unlikely(rc != SQLITE_OK))
459 - error_report("Failed to register internal u2h function");
513 return 0;
514 }
515
@@ -927,3 +980,19 @@ int sql_metadata_cache_stats(int op)
980 netdata_thread_enable_cancelability();
981 return count;
982 }
983 +
984 +#define SQL_DROP_TABLE "DROP table %s;"
985 +
986 +void sql_drop_table(const char *table)
987 +{
988 + if (!table)
989 + return;
990 +
991 + char wstr[255];
992 + snprintfz(wstr, 254, SQL_DROP_TABLE, table);
993 +
994 + int rc = sqlite3_exec_monitored(db_meta, wstr, 0, 0, NULL);
995 + if (rc != SQLITE_OK) {
996 + error_report("DES SQLite error during drop table operation for %s, rc = %d", table, rc);
997 + }
998 +}
database/sqlite/sqlite_functions.h
+2
@@ -77,4 +77,6 @@ void invalidate_node_instances(uuid_t *host_id, uuid_t *claim_id);
77 // Provide statistics
78 int sql_metadata_cache_stats(int op);
79
80 +void sql_drop_table(const char *table);
81 +void sqlite_now_usec(sqlite3_context *context, int argc, sqlite3_value **argv);
82 #endif //NETDATA_SQLITE_FUNCTIONS_H
database/sqlite/sqlite_health.c
+595 -302
@@ -7,46 +7,13 @@
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))
9
10 -/* Health related SQL queries
11 - Creates a health log table in sqlite, one per host guid
12 -*/
13 -#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, transition_id blob);", guid
14 -int sql_create_health_log_table(RRDHOST *host) {
15 - int rc;
16 - char command[MAX_HEALTH_SQL_SIZE + 1];
17 -
18 - if (unlikely(!db_meta)) {
19 - if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
20 - error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
21 - return 1;
22 - }
23 -
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));
28 -
29 - rc = db_execute(db_meta, command);
30 - if (unlikely(rc))
31 - error_report("HEALTH [%s]: SQLite error during creation of health log table", rrdhost_hostname(host));
32 - else {
33 - 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);
34 - rc = db_execute(db_meta, command);
35 - if (unlikely(unlikely(rc)))
36 - error_report("HEALTH [%s]: SQLite error during creation of health log table index", rrdhost_hostname(host));
37 - }
38 -
39 - return rc;
40 -}
41 -
10 /* Health related SQL queries
11 Updates an entry in the table
12 */
45 -#define SQL_UPDATE_HEALTH_LOG(guid) "UPDATE health_log_%s set updated_by_id = ?, flags = ?, exec_run_timestamp = ?, exec_code = ? where unique_id = ?;", guid
13 +#define SQL_UPDATE_HEALTH_LOG "UPDATE health_log_detail set updated_by_id = ?, flags = ?, exec_run_timestamp = ?, exec_code = ? where unique_id = ? AND alarm_id = ? and transition_id = ?;"
14 void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
15 sqlite3_stmt *res = NULL;
16 int rc;
49 - char command[MAX_HEALTH_SQL_SIZE + 1];
17
18 if (unlikely(!db_meta)) {
19 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
@@ -54,19 +21,10 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
21 return;
22 }
23
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));
61 -
62 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
24 + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG, -1, &res, 0);
25 if (unlikely(rc != SQLITE_OK)) {
64 - sql_create_health_log_table(host);
65 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
66 - if (unlikely(rc != SQLITE_OK)) {
67 - error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host));
68 - return;
69 - }
26 + error_report("HEALTH [%s]: Failed to prepare statement for SQL_UPDATE_HEALTH_LOG", rrdhost_hostname(host));
27 + return;
28 }
29
30 rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) ae->updated_by_id);
@@ -99,6 +57,18 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
57 goto failed;
58 }
59
60 + rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->alarm_id);
61 + if (unlikely(rc != SQLITE_OK)) {
62 + error_report("Failed to bind unique_id parameter for SQL_UPDATE_HEALTH_LOG");
63 + goto failed;
64 + }
65 +
66 + rc = sqlite3_bind_blob(res, 7, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC);
67 + if (unlikely(rc != SQLITE_OK)) {
68 + error_report("Failed to bind host_id for SQL_UPDATE_HEALTH_LOG.");
69 + goto failed;
70 + }
71 +
72 rc = execute_insert(res);
73 if (unlikely(rc != SQLITE_DONE)) {
74 error_report("HEALTH [%s]: Failed to update health log, rc = %d", rrdhost_hostname(host), rc);
@@ -112,16 +82,19 @@ failed:
82 /* Health related SQL queries
83 Inserts an entry in the table
84 */
115 -#define SQL_INSERT_HEALTH_LOG(guid) "INSERT INTO health_log_%s(hostname, unique_id, alarm_id, alarm_event_id, " \
116 - "config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, " \
117 - "exec_run_timestamp, delay_up_to_timestamp, name, chart, family, exec, recipient, source, " \
118 - "units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, " \
119 - "class, component, type, chart_context, transition_id) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", guid
120 -
85 +#define SQL_INSERT_HEALTH_LOG "INSERT INTO health_log (host_id, alarm_id, " \
86 + "config_hash_id, name, chart, family, exec, recipient, units, chart_context, last_transition_id) " \
87 + "VALUES (?,?,?,?,?,?,?,?,?,?,?) " \
88 + "ON CONFLICT (host_id, alarm_id) DO UPDATE SET last_transition_id = excluded.last_transition_id RETURNING health_log_id; "
89 +
90 +#define SQL_INSERT_HEALTH_LOG_DETAIL "INSERT INTO health_log_detail (health_log_id, unique_id, alarm_id, alarm_event_id, " \
91 + "updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, " \
92 + "info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, global_id) " \
93 + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,now_usec(0)); "
94 void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
95 sqlite3_stmt *res = NULL;
96 int rc;
124 - char command[MAX_HEALTH_SQL_SIZE + 1];
97 + uint64_t health_log_id = 0;
98
99 if (unlikely(!db_meta)) {
100 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
@@ -129,222 +102,225 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
102 return;
103 }
104
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));
136 -
137 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
105 + rc = sqlite3_prepare_v2(db_meta, SQL_INSERT_HEALTH_LOG, -1, &res, 0);
106 if (unlikely(rc != SQLITE_OK)) {
139 - sql_create_health_log_table(host);
140 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
141 - if (unlikely(rc != SQLITE_OK)) {
142 - error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host));
143 - return;
144 - }
107 + error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host));
108 + return;
109 }
110
147 - rc = sqlite3_bind_text(res, 1, rrdhost_hostname(host), -1, SQLITE_STATIC);
111 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
112 if (unlikely(rc != SQLITE_OK)) {
149 - error_report("Failed to bind hostname parameter for SQL_INSERT_HEALTH_LOG");
113 + error_report("Failed to bind host_id for SQL_INSERT_HEALTH_LOG.");
114 goto failed;
115 }
116
153 - rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->unique_id);
117 + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->alarm_id);
118 if (unlikely(rc != SQLITE_OK)) {
155 - error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG");
119 + error_report("Failed to bind alarm_id parameter for SQL_INSERT_HEALTH_LOG");
120 goto failed;
121 }
122
159 - rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) ae->alarm_id);
123 + rc = sqlite3_bind_blob(res, 3, &ae->config_hash_id, sizeof(ae->config_hash_id), SQLITE_STATIC);
124 if (unlikely(rc != SQLITE_OK)) {
161 - error_report("Failed to bind alarm_id parameter for SQL_INSERT_HEALTH_LOG");
125 + error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG");
126 goto failed;
127 }
128
165 - rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) ae->alarm_event_id);
129 + rc = sqlite3_bind_string_or_null(res, ae->name, 4);
130 if (unlikely(rc != SQLITE_OK)) {
167 - error_report("Failed to bind alarm_event_id parameter for SQL_INSERT_HEALTH_LOG");
131 + error_report("Failed to bind name parameter for SQL_INSERT_HEALTH_LOG");
132 goto failed;
133 }
134
171 - rc = sqlite3_bind_blob(res, 5, &ae->config_hash_id, sizeof(ae->config_hash_id), SQLITE_STATIC);
135 + rc = sqlite3_bind_string_or_null(res, ae->chart, 5);
136 if (unlikely(rc != SQLITE_OK)) {
173 - error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG");
137 + error_report("Failed to bind chart parameter for SQL_INSERT_HEALTH_LOG");
138 goto failed;
139 }
140
177 - rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->updated_by_id);
141 + rc = sqlite3_bind_string_or_null(res, ae->family, 6);
142 if (unlikely(rc != SQLITE_OK)) {
179 - error_report("Failed to bind updated_by_id parameter for SQL_INSERT_HEALTH_LOG");
143 + error_report("Failed to bind family parameter for SQL_INSERT_HEALTH_LOG");
144 goto failed;
145 }
146
183 - rc = sqlite3_bind_int64(res, 7, (sqlite3_int64) ae->updates_id);
147 + rc = sqlite3_bind_string_or_null(res, ae->exec, 7);
148 if (unlikely(rc != SQLITE_OK)) {
185 - error_report("Failed to bind updates_id parameter for SQL_INSERT_HEALTH_LOG");
149 + error_report("Failed to bind exec parameter for SQL_INSERT_HEALTH_LOG");
150 goto failed;
151 }
152
189 - rc = sqlite3_bind_int64(res, 8, (sqlite3_int64) ae->when);
153 + rc = sqlite3_bind_string_or_null(res, ae->recipient, 8);
154 if (unlikely(rc != SQLITE_OK)) {
191 - error_report("Failed to bind when parameter for SQL_INSERT_HEALTH_LOG");
155 + error_report("Failed to bind recipient parameter for SQL_INSERT_HEALTH_LOG");
156 goto failed;
157 }
158
195 - rc = sqlite3_bind_int64(res, 9, (sqlite3_int64) ae->duration);
159 + rc = sqlite3_bind_string_or_null(res, ae->units, 9);
160 if (unlikely(rc != SQLITE_OK)) {
197 - error_report("Failed to bind duration parameter for SQL_INSERT_HEALTH_LOG");
161 + error_report("Failed to bind host_id parameter to store node instance information");
162 goto failed;
163 }
164
201 - rc = sqlite3_bind_int64(res, 10, (sqlite3_int64) ae->non_clear_duration);
165 + rc = sqlite3_bind_string_or_null(res, ae->chart_context, 10);
166 if (unlikely(rc != SQLITE_OK)) {
203 - error_report("Failed to bind non_clear_duration parameter for SQL_INSERT_HEALTH_LOG");
167 + error_report("Failed to bind chart_context parameter for SQL_INSERT_HEALTH_LOG");
168 goto failed;
169 }
170
207 - rc = sqlite3_bind_int64(res, 11, (sqlite3_int64) ae->flags);
171 + rc = sqlite3_bind_blob(res, 11, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC);
172 if (unlikely(rc != SQLITE_OK)) {
209 - error_report("Failed to bind flags parameter for SQL_INSERT_HEALTH_LOG");
173 + error_report("Failed to bind transition_id parameter for SQL_INSERT_HEALTH_LOG");
174 goto failed;
175 }
176
213 - rc = sqlite3_bind_int64(res, 12, (sqlite3_int64) ae->exec_run_timestamp);
214 - if (unlikely(rc != SQLITE_OK)) {
215 - error_report("Failed to bind exec_run_timestamp parameter for SQL_INSERT_HEALTH_LOG");
177 + rc = sqlite3_step_monitored(res);
178 + if (likely(rc == SQLITE_ROW))
179 + health_log_id = (size_t) sqlite3_column_int64(res, 0);
180 + else {
181 + error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc);
182 goto failed;
183 }
184
219 - rc = sqlite3_bind_int64(res, 13, (sqlite3_int64) ae->delay_up_to_timestamp);
185 + rc = sqlite3_finalize(res);
186 + if (unlikely(rc != SQLITE_OK))
187 + error_report("HEALTH [%s]: Failed to finalize the prepared statement for inserting to health log.", rrdhost_hostname(host));
188 +
189 + rc = sqlite3_prepare_v2(db_meta, SQL_INSERT_HEALTH_LOG_DETAIL, -1, &res, 0);
190 if (unlikely(rc != SQLITE_OK)) {
221 - error_report("Failed to bind delay_up_to_timestamp parameter for SQL_INSERT_HEALTH_LOG");
191 + error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG_DETAIL", rrdhost_hostname(host));
192 + return;
193 + }
194 +
195 + rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) health_log_id);
196 + if (unlikely(rc != SQLITE_OK)) {
197 + error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
198 goto failed;
199 }
200
225 - rc = sqlite3_bind_string_or_null(res, ae->name, 14);
201 + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->unique_id);
202 if (unlikely(rc != SQLITE_OK)) {
227 - error_report("Failed to bind name parameter for SQL_INSERT_HEALTH_LOG");
203 + error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
204 goto failed;
205 }
206
231 - rc = sqlite3_bind_string_or_null(res, ae->chart, 15);
207 + rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) ae->alarm_id);
208 if (unlikely(rc != SQLITE_OK)) {
233 - error_report("Failed to bind chart parameter for SQL_INSERT_HEALTH_LOG");
209 + error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
210 goto failed;
211 }
212
237 - rc = sqlite3_bind_string_or_null(res, ae->family, 16);
213 + rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) ae->alarm_event_id);
214 if (unlikely(rc != SQLITE_OK)) {
239 - error_report("Failed to bind family parameter for SQL_INSERT_HEALTH_LOG");
215 + error_report("Failed to bind alarm_event_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
216 goto failed;
217 }
218
243 - rc = sqlite3_bind_string_or_null(res, ae->exec, 17);
219 + rc = sqlite3_bind_int64(res, 5, (sqlite3_int64) ae->updated_by_id);
220 if (unlikely(rc != SQLITE_OK)) {
245 - error_report("Failed to bind exec parameter for SQL_INSERT_HEALTH_LOG");
221 + error_report("Failed to bind updated_by_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
222 goto failed;
223 }
224
249 - rc = sqlite3_bind_string_or_null(res, ae->recipient, 18);
225 + rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->updates_id);
226 if (unlikely(rc != SQLITE_OK)) {
251 - error_report("Failed to bind recipient parameter for SQL_INSERT_HEALTH_LOG");
227 + error_report("Failed to bind updates_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
228 goto failed;
229 }
230
255 - rc = sqlite3_bind_string_or_null(res, ae->source, 19);
231 + rc = sqlite3_bind_int64(res, 7, (sqlite3_int64) ae->when);
232 if (unlikely(rc != SQLITE_OK)) {
257 - error_report("Failed to bind source parameter for SQL_INSERT_HEALTH_LOG");
233 + error_report("Failed to bind when parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
234 goto failed;
235 }
236
261 - rc = sqlite3_bind_string_or_null(res, ae->units, 20);
237 + rc = sqlite3_bind_int64(res, 8, (sqlite3_int64) ae->duration);
238 if (unlikely(rc != SQLITE_OK)) {
263 - error_report("Failed to bind host_id parameter to store node instance information");
239 + error_report("Failed to bind duration parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
240 goto failed;
241 }
242
267 - rc = sqlite3_bind_string_or_null(res, ae->info, 21);
243 + rc = sqlite3_bind_int64(res, 9, (sqlite3_int64) ae->non_clear_duration);
244 if (unlikely(rc != SQLITE_OK)) {
269 - error_report("Failed to bind info parameter for SQL_INSERT_HEALTH_LOG");
245 + error_report("Failed to bind non_clear_duration parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
246 goto failed;
247 }
248
273 - rc = sqlite3_bind_int(res, 22, ae->exec_code);
249 + rc = sqlite3_bind_int64(res, 10, (sqlite3_int64) ae->flags);
250 if (unlikely(rc != SQLITE_OK)) {
275 - error_report("Failed to bind exec_code parameter for SQL_INSERT_HEALTH_LOG");
251 + error_report("Failed to bind flags parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
252 goto failed;
253 }
254
279 - rc = sqlite3_bind_int(res, 23, ae->new_status);
255 + rc = sqlite3_bind_int64(res, 11, (sqlite3_int64) ae->exec_run_timestamp);
256 if (unlikely(rc != SQLITE_OK)) {
281 - error_report("Failed to bind new_status parameter for SQL_INSERT_HEALTH_LOG");
257 + error_report("Failed to bind exec_run_timestamp parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
258 goto failed;
259 }
260
285 - rc = sqlite3_bind_int(res, 24, ae->old_status);
261 + rc = sqlite3_bind_int64(res, 12, (sqlite3_int64) ae->delay_up_to_timestamp);
262 if (unlikely(rc != SQLITE_OK)) {
287 - error_report("Failed to bind old_status parameter for SQL_INSERT_HEALTH_LOG");
263 + error_report("Failed to bind delay_up_to_timestamp parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
264 goto failed;
265 }
266
291 - rc = sqlite3_bind_int(res, 25, ae->delay);
267 + rc = sqlite3_bind_string_or_null(res, ae->info, 13);
268 if (unlikely(rc != SQLITE_OK)) {
293 - error_report("Failed to bind delay parameter for SQL_INSERT_HEALTH_LOG");
269 + error_report("Failed to bind info parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
270 goto failed;
271 }
272
297 - rc = sqlite3_bind_double(res, 26, ae->new_value);
273 + rc = sqlite3_bind_int(res, 14, ae->exec_code);
274 if (unlikely(rc != SQLITE_OK)) {
299 - error_report("Failed to bind new_value parameter for SQL_INSERT_HEALTH_LOG");
275 + error_report("Failed to bind exec_code parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
276 goto failed;
277 }
278
303 - rc = sqlite3_bind_double(res, 27, ae->old_value);
279 + rc = sqlite3_bind_int(res, 15, ae->new_status);
280 if (unlikely(rc != SQLITE_OK)) {
305 - error_report("Failed to bind old_value parameter for SQL_INSERT_HEALTH_LOG");
281 + error_report("Failed to bind new_status parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
282 goto failed;
283 }
284
309 - rc = sqlite3_bind_int64(res, 28, (sqlite3_int64) ae->last_repeat);
285 + rc = sqlite3_bind_int(res, 16, ae->old_status);
286 if (unlikely(rc != SQLITE_OK)) {
311 - error_report("Failed to bind last_repeat parameter for SQL_INSERT_HEALTH_LOG");
287 + error_report("Failed to bind old_status parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
288 goto failed;
289 }
290
315 - rc = sqlite3_bind_string_or_null(res, ae->classification, 29);
291 + rc = sqlite3_bind_int(res, 17, ae->delay);
292 if (unlikely(rc != SQLITE_OK)) {
317 - error_report("Failed to bind classification parameter for SQL_INSERT_HEALTH_LOG");
293 + error_report("Failed to bind delay parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
294 goto failed;
295 }
296
321 - rc = sqlite3_bind_string_or_null(res, ae->component, 30);
297 + rc = sqlite3_bind_double(res, 18, ae->new_value);
298 if (unlikely(rc != SQLITE_OK)) {
323 - error_report("Failed to bind component parameter for SQL_INSERT_HEALTH_LOG");
299 + error_report("Failed to bind new_value parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
300 goto failed;
301 }
302
327 - rc = sqlite3_bind_string_or_null(res, ae->type, 31);
303 + rc = sqlite3_bind_double(res, 19, ae->old_value);
304 if (unlikely(rc != SQLITE_OK)) {
329 - error_report("Failed to bind type parameter for SQL_INSERT_HEALTH_LOG");
305 + error_report("Failed to bind old_value parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
306 goto failed;
307 }
308
333 - rc = sqlite3_bind_string_or_null(res, ae->chart_context, 32);
309 + rc = sqlite3_bind_int64(res, 20, (sqlite3_int64) ae->last_repeat);
310 if (unlikely(rc != SQLITE_OK)) {
335 - error_report("Failed to bind chart_context parameter for SQL_INSERT_HEALTH_LOG");
311 + error_report("Failed to bind last_repeat parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
312 goto failed;
313 }
314
339 - rc = sqlite3_bind_blob(res, 33, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC);
315 + rc = sqlite3_bind_blob(res, 21, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC);
316 if (unlikely(rc != SQLITE_OK)) {
341 - error_report("Failed to bind transition_id parameter for SQL_INSERT_HEALTH_LOG");
317 + error_report("Failed to bind transition_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL");
318 goto failed;
319 }
320
321 rc = execute_insert(res);
322 if (unlikely(rc != SQLITE_DONE)) {
347 - error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc);
323 + error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG_DETAIL, rc = %d", rrdhost_hostname(host), rc);
324 goto failed;
325 }
326
@@ -373,11 +349,10 @@ void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae)
349 /* Health related SQL queries
350 Get a count of rows from health log table
351 */
376 -#define SQL_COUNT_HEALTH_LOG(guid) "SELECT count(1) FROM health_log_%s;", guid
352 +#define SQL_COUNT_HEALTH_LOG_DETAIL "SELECT count(1) FROM health_log_detail hld, health_log hl where hl.host_id = @host_id and hl.health_log_id = hld.health_log_id;"
353 void sql_health_alarm_log_count(RRDHOST *host) {
354 sqlite3_stmt *res = NULL;
355 int rc;
380 - char command[MAX_HEALTH_SQL_SIZE + 1];
356
357 if (unlikely(!db_meta)) {
358 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
@@ -385,17 +360,19 @@ void sql_health_alarm_log_count(RRDHOST *host) {
360 return;
361 }
362
388 - char uuid_str[UUID_STR_LEN];
389 - uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
390 -
391 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COUNT_HEALTH_LOG(uuid_str));
392 -
393 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
363 + rc = sqlite3_prepare_v2(db_meta, SQL_COUNT_HEALTH_LOG_DETAIL, -1, &res, 0);
364 if (unlikely(rc != SQLITE_OK)) {
365 error_report("Failed to prepare statement to count health log entries from db");
366 return;
367 }
368
369 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
370 + if (unlikely(rc != SQLITE_OK)) {
371 + error_report("Failed to bind host_id for SQL_COUNT_HEALTH_LOG.");
372 + sqlite3_finalize(res);
373 + return;
374 + }
375 +
376 rc = sqlite3_step_monitored(res);
377 if (likely(rc == SQLITE_ROW))
378 host->health.health_log_entries_written = (size_t) sqlite3_column_int64(res, 0);
@@ -404,13 +381,13 @@ void sql_health_alarm_log_count(RRDHOST *host) {
381 if (unlikely(rc != SQLITE_OK))
382 error_report("Failed to finalize the prepared statement to count health log entries from db");
383
407 - info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", rrdhost_hostname(host), uuid_str, (unsigned long int) host->health.health_log_entries_written);
384 + info("HEALTH [%s]: Table health_log_detail contains %lu entries.", rrdhost_hostname(host), (unsigned long int) host->health.health_log_entries_written);
385 }
386
387 /* Health related SQL queries
411 - Cleans up the health_log table on a non-claimed host
388 + Cleans up the health_log_detail table on a non-claimed host
389 */
413 -#define SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED(guid,limit) "DELETE FROM health_log_%s ORDER BY unique_id ASC LIMIT %lu;", guid, limit
390 +#define SQL_CLEANUP_HEALTH_LOG_DETAIL_NOT_CLAIMED(limit) "DELETE FROM health_log_detail where health_log_id in (select health_log_id from health_log where host_id = @host_id) ORDER BY unique_id ASC LIMIT %lu;", limit
391 void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every) {
392 sqlite3_stmt *res = NULL;
393 int rc;
@@ -425,11 +402,18 @@ void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every
402 char uuid_str[UUID_STR_LEN];
403 uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
404
428 - 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)));
405 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG_DETAIL_NOT_CLAIMED((unsigned long int) (host->health.health_log_entries_written - rotate_every)));
406
407 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
408 if (unlikely(rc != SQLITE_OK)) {
432 - error_report("Failed to prepare statement to cleanup health log table");
409 + error_report("Failed to prepare statement to cleanup health log detail table (un-claimed)");
410 + return;
411 + }
412 +
413 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
414 + if (unlikely(rc != SQLITE_OK)) {
415 + error_report("Failed to bind host_id for SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED.");
416 + sqlite3_finalize(res);
417 return;
418 }
419
@@ -439,7 +423,7 @@ void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every
423
424 rc = sqlite3_finalize(res);
425 if (unlikely(rc != SQLITE_OK))
442 - error_report("Failed to finalize the prepared statement to cleanup health log table");
426 + error_report("Failed to finalize the prepared statement to cleanup health log detail table (un-claimed)");
427
428 host->health.health_log_entries_written = rotate_every;
429
@@ -450,9 +434,9 @@ void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every
434 }
435
436 /* Health related SQL queries
453 - Cleans up the health_log table on a claimed host
437 + Cleans up the health_log_detail table on a claimed host
438 */
455 -#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
439 +#define SQL_CLEANUP_HEALTH_LOG_DETAIL_CLAIMED(guid, limit) "DELETE from health_log_detail WHERE unique_id NOT IN (SELECT filtered_alert_unique_id FROM aclk_alert_%s) AND unique_id IN (SELECT hld.unique_id FROM health_log hl, health_log_detail hld WHERE hl.host_id = ?1 AND hl.health_log_id = hld.health_log_id) and health_log_id in (SELECT health_log_id FROM health_log WHERE host_id = ?2) ORDER BY unique_id asc LIMIT %lu;", guid, limit
440 void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) {
441 sqlite3_stmt *res = NULL;
442 int rc;
@@ -473,11 +457,25 @@ void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) {
457 return;
458 }
459
476 - 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)));
460 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG_DETAIL_CLAIMED(uuid_str, (unsigned long int) (host->health.health_log_entries_written - rotate_every)));
461
462 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
463 if (unlikely(rc != SQLITE_OK)) {
480 - error_report("Failed to prepare statement to cleanup health log table");
464 + error_report("Failed to prepare statement to cleanup health log detail table (claimed)");
465 + return;
466 + }
467 +
468 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
469 + if (unlikely(rc != SQLITE_OK)) {
470 + error_report("Failed to bind first host_id for SQL_CLEANUP_HEALTH_LOG_CLAIMED.");
471 + sqlite3_finalize(res);
472 + return;
473 + }
474 +
475 + rc = sqlite3_bind_blob(res, 2, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
476 + if (unlikely(rc != SQLITE_OK)) {
477 + error_report("Failed to bind second host_id for SQL_CLEANUP_HEALTH_LOG_CLAIMED.");
478 + sqlite3_finalize(res);
479 return;
480 }
481
@@ -487,7 +485,7 @@ void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) {
485
486 rc = sqlite3_finalize(res);
487 if (unlikely(rc != SQLITE_OK))
490 - error_report("Failed to finalize the prepared statement to cleanup health log table");
488 + error_report("Failed to finalize the prepared statement to cleanup health log detail table (claimed)");
489
490 sql_health_alarm_log_count(host);
491
@@ -515,24 +513,19 @@ void sql_health_alarm_log_cleanup(RRDHOST *host) {
513 sql_health_alarm_log_cleanup_claimed(host, rotate_every);
514 }
515
518 -#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, " \
519 -"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, transition_id) " \
520 -"select hostname, ?1, ?2, ?3, config_hash_id, 0, ?4, unixepoch(), 0, 0, flags, exec_run_timestamp, " \
521 -"unixepoch(), name, chart, family, exec, recipient, source, units, info, exec_code, -2, new_status, delay, NULL, new_value, 0, class, component, type, chart_context, ?5 " \
522 -"from health_log_%s where unique_id = ?6", guid, guid2
523 -#define SQL_INJECT_REMOVED_UPDATE(guid) "update health_log_%s set flags = flags | ?1, updated_by_id = ?2 where unique_id = ?3; ", guid
524 -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)
516 +#define SQL_INJECT_REMOVED "insert into health_log_detail (health_log_id, unique_id, alarm_id, alarm_event_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, global_id) select health_log_id, ?1, ?2, ?3, 0, ?4, unixepoch(), 0, 0, flags, exec_run_timestamp, unixepoch(), info, exec_code, -2, new_status, delay, NULL, new_value, 0, ?5, now_usec(0) from health_log_detail where unique_id = ?6 and transition_id = ?7;"
517 +#define SQL_INJECT_REMOVED_UPDATE_DETAIL "update health_log_detail set flags = flags | ?1, updated_by_id = ?2 where unique_id = ?3 and transition_id = ?4;"
518 +#define SQL_INJECT_REMOVED_UPDATE_LOG "update health_log set last_transition_id = ?1 where alarm_id = ?2 and last_transition_id = ?3 and host_id = ?4;"
519 +void sql_inject_removed_status(RRDHOST *host, uint32_t alarm_id, uint32_t alarm_event_id, uint32_t unique_id, uint32_t max_unique_id, uuid_t *prev_transition_id)
520 {
521 int rc;
527 - char command[MAX_HEALTH_SQL_SIZE + 1];
522
523 if (!alarm_id || !alarm_event_id || !unique_id || !max_unique_id)
524 return;
525
526 sqlite3_stmt *res = NULL;
527
534 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED(uuid_str, uuid_str));
535 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
528 + rc = sqlite3_prepare_v2(db_meta, SQL_INJECT_REMOVED, -1, &res, 0);
529 if (rc != SQLITE_OK) {
530 error_report("Failed to prepare statement when trying to inject removed event");
531 return;
@@ -566,7 +559,7 @@ void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm
559 uuid_generate_random(transition_id);
560 rc = sqlite3_bind_blob(res, 5, &transition_id, sizeof(transition_id), SQLITE_STATIC);
561 if (unlikely(rc != SQLITE_OK)) {
569 - error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG");
562 + error_report("Failed to bind config_hash_id parameter for SQL_INJECT_REMOVED");
563 goto failed;
564 }
565
@@ -576,6 +569,12 @@ void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm
569 goto failed;
570 }
571
572 + rc = sqlite3_bind_blob(res, 7, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC);
573 + if (unlikely(rc != SQLITE_OK)) {
574 + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED.");
575 + goto failed;
576 + }
577 +
578 rc = execute_insert(res);
579 if (unlikely(rc != SQLITE_DONE)) {
580 error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED, rc = %d", rc);
@@ -585,35 +584,77 @@ void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm
584 if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
585 error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event.");
586
588 - //update the old entry
589 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED_UPDATE(uuid_str));
590 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
587 + //update the old entry in health_log_detail
588 + rc = sqlite3_prepare_v2(db_meta, SQL_INJECT_REMOVED_UPDATE_DETAIL, -1, &res, 0);
589 if (rc != SQLITE_OK) {
592 - error_report("Failed to prepare statement when trying to update during inject removed event");
590 + error_report("Failed to prepare statement when trying to update health_log_detail during inject removed event");
591 return;
592 }
593
594 rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) HEALTH_ENTRY_FLAG_UPDATED);
595 if (unlikely(rc != SQLITE_OK)) {
598 - error_report("Failed to bind flags parameter for SQL_INJECT_REMOVED (update)");
596 + error_report("Failed to bind flags parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL");
597 goto failed;
598 }
599
600 rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) max_unique_id);
601 if (unlikely(rc != SQLITE_OK)) {
604 - error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED (update)");
602 + error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL");
603 goto failed;
604 }
605
606 rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) unique_id);
607 if (unlikely(rc != SQLITE_OK)) {
610 - error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED (update)");
608 + error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL");
609 + goto failed;
610 + }
611 +
612 + rc = sqlite3_bind_blob(res, 4, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC);
613 + if (unlikely(rc != SQLITE_OK)) {
614 + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL");
615 + goto failed;
616 + }
617 +
618 + rc = execute_insert(res);
619 + if (unlikely(rc != SQLITE_DONE)) {
620 + error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE_DETAIL, rc = %d", rc);
621 + goto failed;
622 + }
623 +
624 + //update the health_log_table
625 + rc = sqlite3_prepare_v2(db_meta, SQL_INJECT_REMOVED_UPDATE_LOG, -1, &res, 0);
626 + if (rc != SQLITE_OK) {
627 + error_report("Failed to prepare statement when trying to update health_log during inject removed event");
628 + return;
629 + }
630 +
631 + rc = sqlite3_bind_blob(res, 1, &transition_id, sizeof(transition_id), SQLITE_STATIC);
632 + if (unlikely(rc != SQLITE_OK)) {
633 + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_LOG");
634 + goto failed;
635 + }
636 +
637 + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) alarm_id);
638 + if (unlikely(rc != SQLITE_OK)) {
639 + error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL");
640 + goto failed;
641 + }
642 +
643 + rc = sqlite3_bind_blob(res, 3, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC);
644 + if (unlikely(rc != SQLITE_OK)) {
645 + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_LOG");
646 + goto failed;
647 + }
648 +
649 + rc = sqlite3_bind_blob(res, 4, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
650 + if (unlikely(rc != SQLITE_OK)) {
651 + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL");
652 goto failed;
653 }
654
655 rc = execute_insert(res);
656 if (unlikely(rc != SQLITE_DONE)) {
616 - error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE, rc = %d", rc);
657 + error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE_DETAIL, rc = %d", rc);
658 goto failed;
659 }
660
@@ -622,22 +663,27 @@ failed:
663 error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event.");
664 }
665
625 -#define SQL_SELECT_MAX_UNIQUE_ID(guid) "SELECT MAX(unique_id) from health_log_%s", guid
626 -uint32_t sql_get_max_unique_id (char *uuid_str)
666 +#define SQL_SELECT_MAX_UNIQUE_ID "SELECT MAX(hld.unique_id) from health_log_detail hld, health_log hl where hl.host_id = @host_id; and hl.health_log_id = hld.health_log_id"
667 +uint32_t sql_get_max_unique_id (RRDHOST *host)
668 {
669 int rc;
629 - char command[MAX_HEALTH_SQL_SIZE + 1];
670 uint32_t max_unique_id = 0;
671
672 sqlite3_stmt *res = NULL;
673
634 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_MAX_UNIQUE_ID(uuid_str));
635 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
674 + rc = sqlite3_prepare_v2(db_meta, SQL_SELECT_MAX_UNIQUE_ID, -1, &res, 0);
675 if (rc != SQLITE_OK) {
676 error_report("Failed to prepare statement when trying to get max unique id");
677 return 0;
678 }
679
680 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
681 + if (unlikely(rc != SQLITE_OK)) {
682 + error_report("Failed to bind host_id parameter for SQL_SELECT_MAX_UNIQUE_ID.");
683 + sqlite3_finalize(res);
684 + return 0;
685 + }
686 +
687 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
688 max_unique_id = (uint32_t) sqlite3_column_int64(res, 0);
689 }
@@ -649,36 +695,42 @@ uint32_t sql_get_max_unique_id (char *uuid_str)
695 return max_unique_id;
696 }
697
652 -#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
653 -void sql_check_removed_alerts_state(char *uuid_str)
698 +#define SQL_SELECT_LAST_STATUSES "SELECT hld.new_status, hld.unique_id, hld.alarm_id, hld.alarm_event_id, hld.transition_id from health_log hl, health_log_detail hld where hl.host_id = @host_id and hl.last_transition_id = hld.transition_id;"
699 +void sql_check_removed_alerts_state(RRDHOST *host)
700 {
701 int rc;
656 - char command[MAX_HEALTH_SQL_SIZE + 1];
702 uint32_t max_unique_id = 0;
658 -
703 sqlite3_stmt *res = NULL;
704 + uuid_t transition_id;
705
661 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_LAST_STATUSES(uuid_str));
662 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
706 + rc = sqlite3_prepare_v2(db_meta, SQL_SELECT_LAST_STATUSES, -1, &res, 0);
707 if (rc != SQLITE_OK) {
708 error_report("Failed to prepare statement when trying to check removed statuses");
709 return;
710 }
711
668 - while (sqlite3_step_monitored(res) == SQLITE_ROW) {
669 - uint32_t alarm_id, alarm_event_id, unique_id;
670 - RRDCALC_STATUS status;
671 -
672 - status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
673 - unique_id = (uint32_t) sqlite3_column_int64(res, 1);
674 - alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
675 - alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3);
676 - if (unlikely(status != RRDCALC_STATUS_REMOVED)) {
677 - if (unlikely(!max_unique_id))
678 - max_unique_id = sql_get_max_unique_id (uuid_str);
679 - sql_inject_removed_status (uuid_str, alarm_id, alarm_event_id, unique_id, ++max_unique_id);
680 - }
681 - }
712 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
713 + if (unlikely(rc != SQLITE_OK)) {
714 + error_report("Failed to bind host_id parameter for SQL_SELECT_LAST_STATUSES.");
715 + sqlite3_finalize(res);
716 + return;
717 + }
718 +
719 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
720 + uint32_t alarm_id, alarm_event_id, unique_id;
721 + RRDCALC_STATUS status;
722 +
723 + status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
724 + unique_id = (uint32_t) sqlite3_column_int64(res, 1);
725 + alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
726 + alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3);
727 + uuid_copy(transition_id, *((uuid_t *) sqlite3_column_blob(res, 4)));
728 + if (unlikely(status != RRDCALC_STATUS_REMOVED)) {
729 + if (unlikely(!max_unique_id))
730 + max_unique_id = sql_get_max_unique_id (host);
731 + sql_inject_removed_status (host, alarm_id, alarm_event_id, unique_id, ++max_unique_id, &transition_id);
732 + }
733 + }
734
735 rc = sqlite3_finalize(res);
736 if (unlikely(rc != SQLITE_OK))
@@ -688,12 +740,11 @@ void sql_check_removed_alerts_state(char *uuid_str)
740 /* Health related SQL queries
741 Load from the health log table
742 */
691 -#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, transition_id FROM health_log_%s group by alarm_id having max(alarm_event_id);", guid
743 +#define SQL_LOAD_HEALTH_LOG "SELECT hld.unique_id, hld.alarm_id, hld.alarm_event_id, hl.config_hash_id, hld.updated_by_id, hld.updates_id, hld.when_key, hld.duration, hld.non_clear_duration, hld.flags, hld.exec_run_timestamp, hld.delay_up_to_timestamp, hl.name, hl.chart, hl.family, hl.exec, hl.recipient, ah.source, hl.units, hld.info, hld.exec_code, hld.new_status, hld.old_status, hld.delay, hld.new_value, hld.old_value, hld.last_repeat, ah.class, ah.component, ah.type, hl.chart_context, hld.transition_id FROM health_log hl, alert_hash ah, health_log_detail hld where hl.config_hash_id = ah.hash_id and hl.host_id = @host_id and hl.last_transition_id = hld.transition_id;"
744 void sql_health_alarm_log_load(RRDHOST *host) {
745 sqlite3_stmt *res = NULL;
746 int ret;
747 ssize_t errored = 0, loaded = 0;
696 - char command[MAX_HEALTH_SQL_SIZE + 1];
748
749 host->health.health_log_entries_written = 0;
750
@@ -703,19 +754,21 @@ void sql_health_alarm_log_load(RRDHOST *host) {
754 return;
755 }
756
706 - char uuid_str[UUID_STR_LEN];
707 - uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
708 -
709 - sql_check_removed_alerts_state(uuid_str);
710 -
711 - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str));
757 + sql_check_removed_alerts_state(host);
758
713 - ret = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
759 + ret = sqlite3_prepare_v2(db_meta, SQL_LOAD_HEALTH_LOG, -1, &res, 0);
760 if (unlikely(ret != SQLITE_OK)) {
761 error_report("HEALTH [%s]: Failed to prepare sql statement to load health log.", rrdhost_hostname(host));
762 return;
763 }
764
765 + ret = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
766 + if (unlikely(ret != SQLITE_OK)) {
767 + error_report("Failed to bind host_id parameter for SQL_LOAD_HEALTH_LOG.");
768 + sqlite3_finalize(res);
769 + return;
770 + }
771 +
772 DICTIONARY *all_rrdcalcs = dictionary_create(
773 DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
774 RRDCALC *rc;
@@ -730,14 +783,14 @@ void sql_health_alarm_log_load(RRDHOST *host) {
783 ALARM_ENTRY *ae = NULL;
784
785 // check that we have valid ids
733 - uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 1);
786 + uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 0);
787 if(!unique_id) {
788 error_report("HEALTH [%s]: Got invalid unique id. Ignoring it.", rrdhost_hostname(host));
789 errored++;
790 continue;
791 }
792
740 - uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
793 + uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 1);
794 if(!alarm_id) {
795 error_report("HEALTH [%s]: Got invalid alarm id. Ignoring it.", rrdhost_hostname(host));
796 errored++;
@@ -745,28 +798,28 @@ void sql_health_alarm_log_load(RRDHOST *host) {
798 }
799
800 //need name, chart and family
748 - if (sqlite3_column_type(res, 13) == SQLITE_NULL) {
801 + if (sqlite3_column_type(res, 12) == SQLITE_NULL) {
802 error_report("HEALTH [%s]: Got null name field. Ignoring it.", rrdhost_hostname(host));
803 errored++;
804 continue;
805 }
806
754 - if (sqlite3_column_type(res, 14) == SQLITE_NULL) {
807 + if (sqlite3_column_type(res, 13) == SQLITE_NULL) {
808 error_report("HEALTH [%s]: Got null chart field. Ignoring it.", rrdhost_hostname(host));
809 errored++;
810 continue;
811 }
812
760 - if (sqlite3_column_type(res, 15) == SQLITE_NULL) {
813 + if (sqlite3_column_type(res, 14) == SQLITE_NULL) {
814 error_report("HEALTH [%s]: Got null family field. Ignoring it.", rrdhost_hostname(host));
815 errored++;
816 continue;
817 }
818
819 // Check if we got last_repeat field
767 - time_t last_repeat = (time_t)sqlite3_column_int64(res, 27);
820 + time_t last_repeat = (time_t)sqlite3_column_int64(res, 26);
821
769 - rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 14));
822 + rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 13));
823 if(unlikely(rc)) {
824 if (rrdcalc_isrepeating(rc)) {
825 rc->last_repeat = last_repeat;
@@ -782,84 +835,84 @@ void sql_health_alarm_log_load(RRDHOST *host) {
835 ae->unique_id = unique_id;
836 ae->alarm_id = alarm_id;
837
785 - if (sqlite3_column_type(res, 4) != SQLITE_NULL)
786 - uuid_copy(ae->config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 4)));
838 + if (sqlite3_column_type(res, 3) != SQLITE_NULL)
839 + uuid_copy(ae->config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 3)));
840
788 - ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3);
789 - ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 5);
790 - ae->updates_id = (uint32_t) sqlite3_column_int64(res, 6);
841 + ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 2);
842 + ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 4);
843 + ae->updates_id = (uint32_t) sqlite3_column_int64(res, 5);
844
792 - ae->when = (time_t) sqlite3_column_int64(res, 7);
793 - ae->duration = (time_t) sqlite3_column_int64(res, 8);
794 - ae->non_clear_duration = (time_t) sqlite3_column_int64(res, 9);
845 + ae->when = (time_t) sqlite3_column_int64(res, 6);
846 + ae->duration = (time_t) sqlite3_column_int64(res, 7);
847 + ae->non_clear_duration = (time_t) sqlite3_column_int64(res, 8);
848
796 - ae->flags = (uint32_t) sqlite3_column_int64(res, 10);
849 + ae->flags = (uint32_t) sqlite3_column_int64(res, 9);
850 ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
851
799 - ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 11);
800 - ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 12);
852 + ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 10);
853 + ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 11);
854
802 - ae->name = string_strdupz((char *) sqlite3_column_text(res, 13));
803 - ae->chart = string_strdupz((char *) sqlite3_column_text(res, 14));
804 - ae->family = string_strdupz((char *) sqlite3_column_text(res, 15));
855 + ae->name = string_strdupz((char *) sqlite3_column_text(res, 12));
856 + ae->chart = string_strdupz((char *) sqlite3_column_text(res, 13));
857 + ae->family = string_strdupz((char *) sqlite3_column_text(res, 14));
858
806 - if (sqlite3_column_type(res, 16) != SQLITE_NULL)
807 - ae->exec = string_strdupz((char *) sqlite3_column_text(res, 16));
859 + if (sqlite3_column_type(res, 15) != SQLITE_NULL)
860 + ae->exec = string_strdupz((char *) sqlite3_column_text(res, 15));
861 else
862 ae->exec = NULL;
863
811 - if (sqlite3_column_type(res, 17) != SQLITE_NULL)
812 - ae->recipient = string_strdupz((char *) sqlite3_column_text(res, 17));
864 + if (sqlite3_column_type(res, 16) != SQLITE_NULL)
865 + ae->recipient = string_strdupz((char *) sqlite3_column_text(res, 16));
866 else
867 ae->recipient = NULL;
868
816 - if (sqlite3_column_type(res, 18) != SQLITE_NULL)
817 - ae->source = string_strdupz((char *) sqlite3_column_text(res, 18));
869 + if (sqlite3_column_type(res, 17) != SQLITE_NULL)
870 + ae->source = string_strdupz((char *) sqlite3_column_text(res, 17));
871 else
872 ae->source = NULL;
873
821 - if (sqlite3_column_type(res, 19) != SQLITE_NULL)
822 - ae->units = string_strdupz((char *) sqlite3_column_text(res, 19));
874 + if (sqlite3_column_type(res, 18) != SQLITE_NULL)
875 + ae->units = string_strdupz((char *) sqlite3_column_text(res, 18));
876 else
877 ae->units = NULL;
878
826 - if (sqlite3_column_type(res, 20) != SQLITE_NULL)
827 - ae->info = string_strdupz((char *) sqlite3_column_text(res, 20));
879 + if (sqlite3_column_type(res, 19) != SQLITE_NULL)
880 + ae->info = string_strdupz((char *) sqlite3_column_text(res, 19));
881 else
882 ae->info = NULL;
883
831 - ae->exec_code = (int) sqlite3_column_int(res, 21);
832 - ae->new_status = (RRDCALC_STATUS) sqlite3_column_int(res, 22);
833 - ae->old_status = (RRDCALC_STATUS)sqlite3_column_int(res, 23);
834 - ae->delay = (int) sqlite3_column_int(res, 24);
884 + ae->exec_code = (int) sqlite3_column_int(res, 20);
885 + ae->new_status = (RRDCALC_STATUS) sqlite3_column_int(res, 21);
886 + ae->old_status = (RRDCALC_STATUS)sqlite3_column_int(res, 22);
887 + ae->delay = (int) sqlite3_column_int(res, 23);
888
836 - ae->new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 25);
837 - ae->old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 26);
889 + ae->new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 24);
890 + ae->old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 25);
891
892 ae->last_repeat = last_repeat;
893
841 - if (sqlite3_column_type(res, 28) != SQLITE_NULL)
842 - ae->classification = string_strdupz((char *) sqlite3_column_text(res, 28));
894 + if (sqlite3_column_type(res, 27) != SQLITE_NULL)
895 + ae->classification = string_strdupz((char *) sqlite3_column_text(res, 27));
896 else
897 ae->classification = NULL;
898
846 - if (sqlite3_column_type(res, 29) != SQLITE_NULL)
847 - ae->component = string_strdupz((char *) sqlite3_column_text(res, 29));
899 + if (sqlite3_column_type(res, 28) != SQLITE_NULL)
900 + ae->component = string_strdupz((char *) sqlite3_column_text(res, 28));
901 else
902 ae->component = NULL;
903
851 - if (sqlite3_column_type(res, 30) != SQLITE_NULL)
852 - ae->type = string_strdupz((char *) sqlite3_column_text(res, 30));
904 + if (sqlite3_column_type(res, 29) != SQLITE_NULL)
905 + ae->type = string_strdupz((char *) sqlite3_column_text(res, 29));
906 else
907 ae->type = NULL;
908
856 - if (sqlite3_column_type(res, 31) != SQLITE_NULL)
857 - ae->chart_context = string_strdupz((char *) sqlite3_column_text(res, 31));
909 + if (sqlite3_column_type(res, 30) != SQLITE_NULL)
910 + ae->chart_context = string_strdupz((char *) sqlite3_column_text(res, 30));
911 else
912 ae->chart_context = NULL;
913
861 - if (sqlite3_column_type(res, 32) != SQLITE_NULL)
862 - uuid_copy(ae->transition_id, *((uuid_t *) sqlite3_column_blob(res, 32)));
914 + if (sqlite3_column_type(res, 31) != SQLITE_NULL)
915 + uuid_copy(ae->transition_id, *((uuid_t *) sqlite3_column_blob(res, 31)));
916
917 char value_string[100 + 1];
918 string_freez(ae->old_value_string);
@@ -891,7 +944,7 @@ void sql_health_alarm_log_load(RRDHOST *host) {
944 if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id))
945 host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
946
894 - log_health("[%s]: Table health_log_%s, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), uuid_str, loaded, errored);
947 + log_health("[%s]: Table health_log, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), loaded, errored);
948
949 ret = sqlite3_finalize(res);
950 if (unlikely(ret != SQLITE_OK))
@@ -907,8 +960,8 @@ void sql_health_alarm_log_load(RRDHOST *host) {
960 "on_key, class, component, type, os, hosts, lookup, every, units, calc, families, plugin, module, " \
961 "charts, green, red, warn, crit, exec, to_key, info, delay, options, repeat, host_labels, " \
962 "p_db_lookup_dimensions, p_db_lookup_method, p_db_lookup_options, p_db_lookup_after, " \
910 - "p_db_lookup_before, p_update_every) values (?1,unixepoch(),?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12," \
911 - "?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34);"
963 + "p_db_lookup_before, p_update_every, source) values (?1,unixepoch(),?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12," \
964 + "?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34,?35);"
965
966 int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg)
967 {
@@ -1088,6 +1141,10 @@ int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg)
1141 if (unlikely(rc != SQLITE_OK))
1142 goto bind_fail;
1143
1144 + rc = sqlite3_bind_string_or_null(res, cfg->source, ++param);
1145 + if (unlikely(rc != SQLITE_OK))
1146 + goto bind_fail;
1147 +
1148 rc = execute_insert(res);
1149 if (unlikely(rc != SQLITE_DONE))
1150 error_report("Failed to store alert config, rc = %d", rc);
@@ -1175,18 +1232,14 @@ int alert_hash_and_store_config(
1232 return 1;
1233 }
1234
1178 -#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"
1235 +#define SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT "SELECT hld.new_status FROM health_log hl, health_log_detail hld WHERE hl.alarm_id = %u AND hld.unique_id != %u AND hld.flags & %d AND hl.host_id = @host_id and hl.health_log_id = hld.health_log_id ORDER BY hld.unique_id DESC LIMIT 1;"
1236 int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status)
1237 {
1238 int rc = 0, ret = -1;
1239 char command[MAX_HEALTH_SQL_SIZE + 1];
1183 -
1184 - char uuid_str[UUID_STR_LEN];
1185 - uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
1186 -
1240 sqlite3_stmt *res = NULL;
1241
1189 - 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);
1242 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT, ae->alarm_id, ae->unique_id, HEALTH_ENTRY_FLAG_EXEC_RUN);
1243
1244 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
1245 if (rc != SQLITE_OK) {
@@ -1194,6 +1247,13 @@ int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_S
1247 return ret;
1248 }
1249
1250 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
1251 + if (unlikely(rc != SQLITE_OK)) {
1252 + error_report("Failed to bind host_id parameter for SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT.");
1253 + sqlite3_finalize(res);
1254 + return ret;
1255 + }
1256 +
1257 ret = 0;
1258 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
1259 *last_executed_status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
@@ -1207,7 +1267,7 @@ int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_S
1267 return ret;
1268 }
1269
1210 -#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, transition_id FROM health_log_%s WHERE 1=1 ", guid
1270 +#define SQL_SELECT_HEALTH_LOG "SELECT hld.unique_id, hld.alarm_id, hld.alarm_event_id, hl.config_hash_id, hld.updated_by_id, hld.updates_id, hld.when_key, hld.duration, hld.non_clear_duration, hld.flags, hld.exec_run_timestamp, hld.delay_up_to_timestamp, hl.name, hl.chart, hl.family, hl.exec, hl.recipient, ah.source, hl.units, hld.info, hld.exec_code, hld.new_status, hld.old_status, hld.delay, hld.new_value, hld.old_value, hld.last_repeat, ah.class, ah.component, ah.type, hl.chart_context, hld.transition_id FROM health_log hl, alert_hash ah, health_log_detail hld WHERE hl.config_hash_id = ah.hash_id and hl.health_log_id = hld.health_log_id and hl.host_id = @host_id "
1271 void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart) {
1272
1273 buffer_strcat(wb, "[");
@@ -1219,26 +1279,23 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *
1279 int rc;
1280
1281 BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
1222 - char uuid_str[UUID_STR_LEN];
1223 - uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
1224 -
1225 - buffer_sprintf(command, SQL_SELECT_HEALTH_LOG(uuid_str));
1282 + buffer_sprintf(command, SQL_SELECT_HEALTH_LOG);
1283
1284 if (chart) {
1285 char chart_sql[MAX_HEALTH_SQL_SIZE + 1];
1229 - snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND chart = '%s' ", chart);
1286 + snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND hl.chart = '%s' ", chart);
1287 buffer_strcat(command, chart_sql);
1288 }
1289
1290 if (after) {
1291 char after_sql[MAX_HEALTH_SQL_SIZE + 1];
1235 - snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND unique_id > %u ", after);
1292 + snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND hld.unique_id > %u ", after);
1293 buffer_strcat(command, after_sql);
1294 }
1295
1296 {
1297 char limit_sql[MAX_HEALTH_SQL_SIZE + 1];
1241 - snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY unique_id DESC LIMIT %u ", max);
1298 + snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY hld.unique_id DESC LIMIT %u ", max);
1299 buffer_strcat(command, limit_sql);
1300 }
1301
@@ -1249,19 +1306,27 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *
1306 return;
1307 }
1308
1309 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
1310 + if (unlikely(rc != SQLITE_OK)) {
1311 + error_report("Failed to bind host_id for SQL_SELECT_HEALTH_LOG.");
1312 + sqlite3_finalize(res);
1313 + buffer_free(command);
1314 + return;
1315 + }
1316 +
1317 while (sqlite3_step(res) == SQLITE_ROW) {
1318
1319 char old_value_string[100 + 1];
1320 char new_value_string[100 + 1];
1321
1322 char config_hash_id[UUID_STR_LEN];
1258 - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 4)), config_hash_id);
1323 + uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 3)), config_hash_id);
1324
1325 char transition_id[UUID_STR_LEN] = {0};
1261 - if (sqlite3_column_type(res, 32) != SQLITE_NULL)
1262 - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 32)), transition_id);
1326 + if (sqlite3_column_type(res, 31) != SQLITE_NULL)
1327 + uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 31)), transition_id);
1328
1264 - char *edit_command = health_edit_command_from_source((char *)sqlite3_column_text(res, 18));
1329 + char *edit_command = health_edit_command_from_source((char *)sqlite3_column_text(res, 17));
1330
1331 if (count)
1332 buffer_sprintf(wb, ",");
@@ -1309,63 +1374,63 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *
1374 "\t\t\"old_value_string\": \"%s\",\n"
1375 "\t\t\"last_repeat\": \"%lu\",\n"
1376 "\t\t\"silenced\": \"%s\",\n",
1312 - sqlite3_column_text(res, 0),
1377 + rrdhost_hostname(host),
1378 host->utc_offset,
1379 rrdhost_abbrev_timezone(host),
1380 + (unsigned int) sqlite3_column_int64(res, 0),
1381 (unsigned int) sqlite3_column_int64(res, 1),
1382 (unsigned int) sqlite3_column_int64(res, 2),
1317 - (unsigned int) sqlite3_column_int64(res, 3),
1383 config_hash_id,
1384 transition_id,
1385 + sqlite3_column_text(res, 12),
1386 sqlite3_column_text(res, 13),
1387 + sqlite3_column_text(res, 30),
1388 sqlite3_column_text(res, 14),
1322 - sqlite3_column_text(res, 31),
1323 - sqlite3_column_text(res, 15),
1389 + sqlite3_column_text(res, 27) ? (const char *) sqlite3_column_text(res, 27) : (char *) "Unknown",
1390 sqlite3_column_text(res, 28) ? (const char *) sqlite3_column_text(res, 28) : (char *) "Unknown",
1391 sqlite3_column_text(res, 29) ? (const char *) sqlite3_column_text(res, 29) : (char *) "Unknown",
1326 - sqlite3_column_text(res, 30) ? (const char *) sqlite3_column_text(res, 30) : (char *) "Unknown",
1327 - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false",
1328 - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false",
1329 - (long unsigned int)sqlite3_column_int64(res, 11),
1330 - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false",
1331 - sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : string2str(host->health.health_default_exec),
1332 - sqlite3_column_text(res, 17) ? (const char *) sqlite3_column_text(res, 17) : string2str(host->health.health_default_recipient),
1333 - sqlite3_column_int(res, 21),
1334 - sqlite3_column_text(res, 18),
1392 + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false",
1393 + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false",
1394 + (long unsigned int)sqlite3_column_int64(res, 10),
1395 + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false",
1396 + sqlite3_column_text(res, 15) ? (const char *) sqlite3_column_text(res, 15) : string2str(host->health.health_default_exec),
1397 + sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : string2str(host->health.health_default_recipient),
1398 + sqlite3_column_int(res, 20),
1399 + sqlite3_column_text(res, 17),
1400 edit_command,
1336 - sqlite3_column_text(res, 19),
1401 + sqlite3_column_text(res, 18),
1402 + (long unsigned int)sqlite3_column_int64(res, 6),
1403 (long unsigned int)sqlite3_column_int64(res, 7),
1404 (long unsigned int)sqlite3_column_int64(res, 8),
1339 - (long unsigned int)sqlite3_column_int64(res, 9),
1405 + rrdcalc_status2string(sqlite3_column_int(res, 21)),
1406 rrdcalc_status2string(sqlite3_column_int(res, 22)),
1341 - rrdcalc_status2string(sqlite3_column_int(res, 23)),
1342 - sqlite3_column_int(res, 24),
1343 - (long unsigned int)sqlite3_column_int64(res, 12),
1407 + sqlite3_column_int(res, 23),
1408 + (long unsigned int)sqlite3_column_int64(res, 11),
1409 + (unsigned int)sqlite3_column_int64(res, 4),
1410 (unsigned int)sqlite3_column_int64(res, 5),
1345 - (unsigned int)sqlite3_column_int64(res, 6),
1346 - 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),
1347 - 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),
1348 - (long unsigned int)sqlite3_column_int64(res, 27),
1349 - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false");
1411 + sqlite3_column_type(res, 24) == SQLITE_NULL ? "-" : format_value_and_unit(new_value_string, 100, sqlite3_column_double(res, 24), (char *) sqlite3_column_text(res, 18), -1),
1412 + sqlite3_column_type(res, 25) == SQLITE_NULL ? "-" : format_value_and_unit(old_value_string, 100, sqlite3_column_double(res, 25), (char *) sqlite3_column_text(res, 18), -1),
1413 + (long unsigned int)sqlite3_column_int64(res, 26),
1414 + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false");
1415
1351 - health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 20), ",\n");
1416 + health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 19), ",\n");
1417
1353 - if(unlikely(sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
1418 + if(unlikely(sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
1419 buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
1420 }
1421
1422 buffer_strcat(wb, "\t\t\"value\":");
1358 - if (sqlite3_column_type(res, 25) == SQLITE_NULL)
1423 + if (sqlite3_column_type(res, 24) == SQLITE_NULL)
1424 buffer_strcat(wb, "null");
1425 else
1361 - buffer_print_netdata_double(wb, sqlite3_column_double(res, 25));
1426 + buffer_print_netdata_double(wb, sqlite3_column_double(res, 24));
1427 buffer_strcat(wb, ",\n");
1428
1429 buffer_strcat(wb, "\t\t\"old_value\":");
1365 - if (sqlite3_column_type(res, 26) == SQLITE_NULL)
1430 + if (sqlite3_column_type(res, 25) == SQLITE_NULL)
1431 buffer_strcat(wb, "null");
1432 else
1368 - buffer_print_netdata_double(wb, sqlite3_column_double(res, 26));
1433 + buffer_print_netdata_double(wb, sqlite3_column_double(res, 25));
1434 buffer_strcat(wb, "\n");
1435
1436 buffer_strcat(wb, "\t}");
@@ -1381,3 +1446,231 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *
1446
1447 buffer_free(command);
1448 }
1449 +
1450 +#define SQL_COPY_HEALTH_LOG(table) "INSERT OR IGNORE INTO health_log (host_id, alarm_id, config_hash_id, name, chart, family, exec, recipient, units, chart_context) SELECT ?1, alarm_id, config_hash_id, name, chart, family, exec, recipient, units, chart_context from %s;", table
1451 +#define SQL_COPY_HEALTH_LOG_DETAIL(table) "INSERT INTO health_log_detail (unique_id, alarm_id, alarm_event_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, global_id, host_id) SELECT unique_id, alarm_id, alarm_event_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, now_usec(1), ?1 from %s;", table
1452 +#define SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID "update health_log_detail set transition_id = uuid_random() where transition_id is null;"
1453 +#define SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID "update health_log_detail set health_log_id = (select health_log_id from health_log where host_id = ?1 and alarm_id = health_log_detail.alarm_id) where health_log_id is null and host_id = ?2;"
1454 +#define SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID "update health_log set last_transition_id = (select transition_id from health_log_detail where health_log_id = health_log.health_log_id and alarm_id = health_log.alarm_id group by (alarm_id) having max(alarm_event_id)) where host_id = ?1;"
1455 +int health_migrate_old_health_log_table(char *table) {
1456 + if (!table)
1457 + return 0;
1458 +
1459 + //table should contain guid. We need to
1460 + //keep it in the new table along with it's data
1461 + //health_log_XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX
1462 + if (strnlen(table, 46) != 46) {
1463 + return 0;
1464 + }
1465 +
1466 + char *uuid_from_table = strdupz(table + 11);
1467 + uuid_t uuid;
1468 + if (uuid_parse_fix(uuid_from_table, uuid)) {
1469 + freez(uuid_from_table);
1470 + return 0;
1471 + }
1472 +
1473 + int rc;
1474 + char command[MAX_HEALTH_SQL_SIZE + 1];
1475 + sqlite3_stmt *res = NULL;
1476 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COPY_HEALTH_LOG(table));
1477 + rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
1478 + if (unlikely(rc != SQLITE_OK)) {
1479 + error_report("Failed to prepare statement to copy health log, rc = %d", rc);
1480 + freez(uuid_from_table);
1481 + return 0;
1482 + }
1483 +
1484 + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
1485 + if (unlikely(rc != SQLITE_OK)) {
1486 + rc = sqlite3_finalize(res);
1487 + if (unlikely(rc != SQLITE_OK))
1488 + error_report("Failed to reset statement to copy health log table, rc = %d", rc);
1489 + freez(uuid_from_table);
1490 + return 0;
1491 + }
1492 +
1493 + rc = execute_insert(res);
1494 + if (unlikely(rc != SQLITE_DONE)) {
1495 + error_report("Failed to execute SQL_COPY_HEALTH_LOG, rc = %d", rc);
1496 + rc = sqlite3_finalize(res);
1497 + if (unlikely(rc != SQLITE_OK))
1498 + error_report("Failed to reset statement to copy health log table, rc = %d", rc);
1499 + freez(uuid_from_table);
1500 + }
1501 +
1502 + //detail
1503 + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COPY_HEALTH_LOG_DETAIL(table));
1504 + rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
1505 + if (unlikely(rc != SQLITE_OK)) {
1506 + error_report("Failed to prepare statement to copy health log detail, rc = %d", rc);
1507 + return 0;
1508 + }
1509 +
1510 + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
1511 + if (unlikely(rc != SQLITE_OK)) {
1512 + rc = sqlite3_finalize(res);
1513 + if (unlikely(rc != SQLITE_OK))
1514 + error_report("Failed to reset statement to copy health log detail, rc = %d", rc);
1515 + return 0;
1516 + }
1517 +
1518 + rc = execute_insert(res);
1519 + if (unlikely(rc != SQLITE_DONE)) {
1520 + error_report("Failed to execute SQL_COPY_HEALTH_LOG_DETAIL, rc = %d", rc);
1521 + rc = sqlite3_finalize(res);
1522 + if (unlikely(rc != SQLITE_OK))
1523 + error_report("Failed to reset statement to copy health log detail table, rc = %d", rc);
1524 + return 0;
1525 + }
1526 +
1527 + //update transition ids
1528 + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID, -1, &res, 0);
1529 + if (unlikely(rc != SQLITE_OK)) {
1530 + error_report("Failed to prepare statement to update health log detail with transition ids, rc = %d", rc);
1531 + return 0;
1532 + }
1533 +
1534 + rc = execute_insert(res);
1535 + if (unlikely(rc != SQLITE_DONE)) {
1536 + error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID, rc = %d", rc);
1537 + rc = sqlite3_finalize(res);
1538 + if (unlikely(rc != SQLITE_OK))
1539 + error_report("Failed to reset statement to update health log detail table with transition ids, rc = %d", rc);
1540 + return 0;
1541 + }
1542 +
1543 + //update health_log_id
1544 + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID, -1, &res, 0);
1545 + if (unlikely(rc != SQLITE_OK)) {
1546 + error_report("Failed to prepare statement to update health log detail with health log ids, rc = %d", rc);
1547 + return 0;
1548 + }
1549 +
1550 + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
1551 + if (unlikely(rc != SQLITE_OK)) {
1552 + rc = sqlite3_finalize(res);
1553 + if (unlikely(rc != SQLITE_OK))
1554 + error_report("Failed to reset statement to update health log detail with health log ids, rc = %d", rc);
1555 + return 0;
1556 + }
1557 +
1558 + rc = sqlite3_bind_blob(res, 2, &uuid, sizeof(uuid), SQLITE_STATIC);
1559 + if (unlikely(rc != SQLITE_OK)) {
1560 + rc = sqlite3_finalize(res);
1561 + if (unlikely(rc != SQLITE_OK))
1562 + error_report("Failed to reset statement to update health log detail with health log ids, rc = %d", rc);
1563 + return 0;
1564 + }
1565 +
1566 + rc = execute_insert(res);
1567 + if (unlikely(rc != SQLITE_DONE)) {
1568 + error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID, rc = %d", rc);
1569 + rc = sqlite3_finalize(res);
1570 + if (unlikely(rc != SQLITE_OK))
1571 + error_report("Failed to reset statement to update health log detail table with health log ids, rc = %d", rc);
1572 + }
1573 +
1574 + //update last transition id
1575 + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID, -1, &res, 0);
1576 + if (unlikely(rc != SQLITE_OK)) {
1577 + error_report("Failed to prepare statement to update health log with last transition id, rc = %d", rc);
1578 + return 0;
1579 + }
1580 +
1581 + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
1582 + if (unlikely(rc != SQLITE_OK)) {
1583 + rc = sqlite3_finalize(res);
1584 + if (unlikely(rc != SQLITE_OK))
1585 + error_report("Failed to reset statement to update health log with last transition id, rc = %d", rc);
1586 + return 0;
1587 + }
1588 +
1589 + rc = execute_insert(res);
1590 + if (unlikely(rc != SQLITE_DONE)) {
1591 + error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID, rc = %d", rc);
1592 + rc = sqlite3_finalize(res);
1593 + if (unlikely(rc != SQLITE_OK))
1594 + error_report("Failed to reset statement to update health log table with last transition id, rc = %d", rc);
1595 + }
1596 +
1597 + return 1;
1598 +}
1599 +
1600 +#define SQL_GET_ALARM_ID "select alarm_id, health_log_id from health_log where host_id = @host_id and chart = @chart and name = @name"
1601 +#define SQL_GET_EVENT_ID "select max(alarm_event_id) + 1 from health_log_detail where health_log_id = @health_log_id and alarm_id = @alarm_id"
1602 +uint32_t sql_get_alarm_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id)
1603 +{
1604 + int rc = 0;
1605 + sqlite3_stmt *res = NULL;
1606 + uint32_t alarm_id = 0;
1607 + uint64_t health_log_id = 0;
1608 +
1609 + rc = sqlite3_prepare_v2(db_meta, SQL_GET_ALARM_ID, -1, &res, 0);
1610 + if (rc != SQLITE_OK) {
1611 + error_report("Failed to prepare statement when trying to get an alarm id");
1612 + return alarm_id;
1613 + }
1614 +
1615 + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
1616 + if (unlikely(rc != SQLITE_OK)) {
1617 + error_report("Failed to bind host_id parameter for SQL_GET_ALARM_ID.");
1618 + sqlite3_finalize(res);
1619 + return alarm_id;
1620 + }
1621 +
1622 + rc = sqlite3_bind_string_or_null(res, chart, 2);
1623 + if (unlikely(rc != SQLITE_OK)) {
1624 + error_report("Failed to bind char parameter for SQL_GET_ALARM_ID.");
1625 + sqlite3_finalize(res);
1626 + return alarm_id;
1627 + }
1628 +
1629 + rc = sqlite3_bind_string_or_null(res, name, 3);
1630 + if (unlikely(rc != SQLITE_OK)) {
1631 + error_report("Failed to bind name parameter for SQL_GET_ALARM_ID.");
1632 + sqlite3_finalize(res);
1633 + return alarm_id;
1634 + }
1635 +
1636 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
1637 + alarm_id = (uint32_t) sqlite3_column_int64(res, 0);
1638 + health_log_id = (uint64_t) sqlite3_column_int64(res, 1);
1639 + }
1640 +
1641 + rc = sqlite3_finalize(res);
1642 + if (unlikely(rc != SQLITE_OK))
1643 + error_report("Failed to finalize the statement while getting an alarm id.");
1644 +
1645 + if (alarm_id) {
1646 + rc = sqlite3_prepare_v2(db_meta, SQL_GET_EVENT_ID, -1, &res, 0);
1647 + if (rc != SQLITE_OK) {
1648 + error_report("Failed to prepare statement when trying to get an event id");
1649 + return alarm_id;
1650 + }
1651 +
1652 + rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) health_log_id);
1653 + if (unlikely(rc != SQLITE_OK)) {
1654 + error_report("Failed to bind host_id parameter for SQL_GET_EVENT_ID.");
1655 + sqlite3_finalize(res);
1656 + return alarm_id;
1657 + }
1658 +
1659 + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) alarm_id);
1660 + if (unlikely(rc != SQLITE_OK)) {
1661 + error_report("Failed to bind char parameter for SQL_GET_EVENT_ID.");
1662 + sqlite3_finalize(res);
1663 + return alarm_id;
1664 + }
1665 +
1666 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
1667 + *next_event_id = (uint32_t) sqlite3_column_int64(res, 0);
1668 + }
1669 +
1670 + rc = sqlite3_finalize(res);
1671 + if (unlikely(rc != SQLITE_OK))
1672 + error_report("Failed to finalize the statement while getting an alarm id.");
1673 + }
1674 +
1675 + return alarm_id;
1676 +}
database/sqlite/sqlite_health.h
+3 -1
@@ -7,7 +7,7 @@
7
8 extern sqlite3 *db_meta;
9 void sql_health_alarm_log_load(RRDHOST *host);
10 -int sql_create_health_log_table(RRDHOST *host);
10 +int sql_create_health_log_table(void);
11 void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae);
12 void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae);
13 void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae);
@@ -16,4 +16,6 @@ int alert_hash_and_store_config(uuid_t hash_id, struct alert_config *cfg, int st
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 +int health_migrate_old_health_log_table(char *table);
20 +uint32_t sql_get_alarm_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id);
21 #endif //NETDATA_SQLITE_HEALTH_H
health/health.c
+1 -2
@@ -639,7 +639,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
639 ||
640 ((ae->new_status == RRDCALC_STATUS_REMOVED) &&
641 (ae->flags & HEALTH_ENTRY_FLAG_SAVED) &&
642 - (ae->when + 3600 < now_realtime_sec())))
642 + (ae->when + 86400 < now_realtime_sec())))
643 {
644
645 if(host->health_log.alarms == ae) {
@@ -794,7 +794,6 @@ static void initialize_health(RRDHOST *host)
794
795 // TODO: This needs to go to the metadata thread
796 // Health should wait before accessing the table (needs to be created by the metadata thread)
797 - sql_create_health_log_table(host);
797 sql_health_alarm_log_load(host);
798
799 // ------------------------------------------------------------------------
health/health_config.c
+3
@@ -499,6 +499,7 @@ static inline void alert_config_free(struct alert_config *cfg)
499 string_freez(cfg->p_db_lookup_dimensions);
500 string_freez(cfg->p_db_lookup_method);
501 string_freez(cfg->chart_labels);
502 + string_freez(cfg->source);
503 freez(cfg);
504 }
505
@@ -673,6 +674,7 @@ static int health_readfile(const char *filename, void *data) {
674 alert_cfg = callocz(1, sizeof(struct alert_config));
675
676 alert_cfg->alarm = string_dup(rc->name);
677 + alert_cfg->source = health_source_file(line, filename);
678 ignore_this = 0;
679 } else {
680 rc = NULL;
@@ -719,6 +721,7 @@ static int health_readfile(const char *filename, void *data) {
721 alert_cfg = callocz(1, sizeof(struct alert_config));
722
723 alert_cfg->template_key = string_dup(rt->name);
724 + alert_cfg->source = health_source_file(line, filename);
725 ignore_this = 0;
726 } else {
727 rt = NULL;