From cd4377fab21e0f500bef7f06543fa848a039c1e0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 20 Jul 2023 06:50:01 +0200 Subject: Merging upstream version 1.41.0. Signed-off-by: Daniel Baumann --- database/sqlite/sqlite_aclk.c | 28 +- database/sqlite/sqlite_aclk.h | 12 +- database/sqlite/sqlite_aclk_alert.c | 297 ++++---- database/sqlite/sqlite_aclk_node.c | 6 +- database/sqlite/sqlite_context.c | 44 +- database/sqlite/sqlite_db_migration.c | 116 ++- database/sqlite/sqlite_functions.c | 118 ++- database/sqlite/sqlite_functions.h | 2 + database/sqlite/sqlite_health.c | 1354 +++++++++++++++++++++++++-------- database/sqlite/sqlite_health.h | 23 +- database/sqlite/sqlite_metadata.c | 185 +++-- 11 files changed, 1557 insertions(+), 628 deletions(-) (limited to 'database/sqlite') diff --git a/database/sqlite/sqlite_aclk.c b/database/sqlite/sqlite_aclk.c index a33e09f5d..fedce50eb 100644 --- a/database/sqlite/sqlite_aclk.c +++ b/database/sqlite/sqlite_aclk.c @@ -67,7 +67,7 @@ static void aclk_database_enq_cmd(struct aclk_database_cmd *cmd) /* wake up event loop */ int rc = uv_async_send(&aclk_sync_config.async); if (unlikely(rc)) - debug(D_ACLK_SYNC, "Failed to wake up event loop"); + netdata_log_debug(D_ACLK_SYNC, "Failed to wake up event loop"); } enum { @@ -226,14 +226,14 @@ static void sql_delete_aclk_table_list(char *host_guid) uuid_unparse_lower(host_uuid, host_str); uuid_unparse_lower_fix(&host_uuid, uuid_str); - debug(D_ACLK_SYNC, "Checking if I should delete aclk tables for node %s", host_str); + netdata_log_debug(D_ACLK_SYNC, "Checking if I should delete aclk tables for node %s", host_str); if (is_host_available(&host_uuid)) { - debug(D_ACLK_SYNC, "Host %s exists, not deleting aclk sync tables", host_str); + netdata_log_debug(D_ACLK_SYNC, "Host %s exists, not deleting aclk sync tables", host_str); return; } - debug(D_ACLK_SYNC, "Host %s does NOT exist, can delete aclk sync tables", host_str); + netdata_log_debug(D_ACLK_SYNC, "Host %s does NOT exist, can delete aclk sync tables", host_str); sqlite3_stmt *res = NULL; BUFFER *sql = buffer_create(ACLK_SYNC_QUERY_SIZE, &netdata_buffers_statistics.buffers_sqlite); @@ -257,7 +257,7 @@ static void sql_delete_aclk_table_list(char *host_guid) rc = db_execute(db_meta, buffer_tostring(sql)); if (unlikely(rc)) - error("Failed to drop unused ACLK tables"); + netdata_log_error("Failed to drop unused ACLK tables"); fail: buffer_free(sql); @@ -265,7 +265,7 @@ fail: static int sql_check_aclk_table(void *data __maybe_unused, int argc __maybe_unused, char **argv __maybe_unused, char **column __maybe_unused) { - debug(D_ACLK_SYNC,"Scheduling aclk sync table check for node %s", (char *) argv[0]); + netdata_log_debug(D_ACLK_SYNC,"Scheduling aclk sync table check for node %s", (char *) argv[0]); struct aclk_database_cmd cmd; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACLK_DATABASE_DELETE_HOST; @@ -280,7 +280,7 @@ static int sql_check_aclk_table(void *data __maybe_unused, int argc __maybe_unus static void sql_check_aclk_table_list(void) { char *err_msg = NULL; - debug(D_ACLK_SYNC,"Cleaning tables for nodes that do not exist"); + netdata_log_debug(D_ACLK_SYNC,"Cleaning tables for nodes that do not exist"); int rc = sqlite3_exec_monitored(db_meta, SQL_SELECT_ACLK_ACTIVE_LIST, sql_check_aclk_table, NULL, &err_msg); if (rc != SQLITE_OK) { error_report("Query failed when trying to check for obsolete ACLK sync tables, %s", err_msg); @@ -305,7 +305,7 @@ static int sql_maint_aclk_sync_database(void *data __maybe_unused, int argc __ma static void sql_maint_aclk_sync_database_all(void) { char *err_msg = NULL; - debug(D_ACLK_SYNC,"Cleaning tables for nodes that do not exist"); + netdata_log_debug(D_ACLK_SYNC,"Cleaning tables for nodes that do not exist"); int rc = sqlite3_exec_monitored(db_meta, SQL_SELECT_ACLK_ALERT_LIST, sql_maint_aclk_sync_database, NULL, &err_msg); if (rc != SQLITE_OK) { error_report("Query failed when trying to check for obsolete ACLK sync tables, %s", err_msg); @@ -385,7 +385,7 @@ static void aclk_synchronization(void *arg __maybe_unused) config->timer_req.data = config; fatal_assert(0 == uv_timer_start(&config->timer_req, timer_cb, TIMER_PERIOD_MS, TIMER_PERIOD_MS)); - info("Starting ACLK synchronization thread"); + netdata_log_info("Starting ACLK synchronization thread"); config->cleanup_after = now_realtime_sec() + ACLK_DATABASE_CLEANUP_FIRST; config->initialized = true; @@ -444,7 +444,7 @@ static void aclk_synchronization(void *arg __maybe_unused) sql_process_queue_removed_alerts_to_aclk(cmd.param[0]); break; default: - debug(D_ACLK_SYNC, "%s: default.", __func__); + netdata_log_debug(D_ACLK_SYNC, "%s: default.", __func__); break; } if (cmd.completion) @@ -462,7 +462,7 @@ static void aclk_synchronization(void *arg __maybe_unused) worker_unregister(); service_exits(); - info("ACLK SYNC: Shutting down ACLK synchronization event loop"); + netdata_log_info("ACLK SYNC: Shutting down ACLK synchronization event loop"); } static void aclk_synchronization_init(void) @@ -543,7 +543,7 @@ void sql_aclk_sync_init(void) return; } - info("Creating archived hosts"); + netdata_log_info("Creating archived hosts"); int number_of_children = 0; rc = sqlite3_exec_monitored(db_meta, SQL_FETCH_ALL_HOSTS, create_host_callback, &number_of_children, &err_msg); @@ -552,7 +552,7 @@ void sql_aclk_sync_init(void) sqlite3_free(err_msg); } - info("Created %d archived hosts", number_of_children); + netdata_log_info("Created %d archived hosts", number_of_children); // Trigger host context load for hosts that have been created metadata_queue_load_host_context(NULL); @@ -568,7 +568,7 @@ void sql_aclk_sync_init(void) } aclk_synchronization_init(); - info("ACLK sync initialization completed"); + netdata_log_info("ACLK sync initialization completed"); #endif } diff --git a/database/sqlite/sqlite_aclk.h b/database/sqlite/sqlite_aclk.h index d555a0cef..705102d74 100644 --- a/database/sqlite/sqlite_aclk.h +++ b/database/sqlite/sqlite_aclk.h @@ -27,12 +27,20 @@ static inline void uuid_unparse_lower_fix(uuid_t *uuid, char *out) out[23] = '_'; } +static inline int uuid_parse_fix(char *in, uuid_t uuid) +{ + in[8] = '-'; + in[13] = '-'; + in[18] = '-'; + in[23] = '-'; + return uuid_parse(in, uuid); +} + static inline int claimed() { return localhost->aclk_state.claimed_id != NULL; } - #define TABLE_ACLK_ALERT "CREATE TABLE IF NOT EXISTS aclk_alert_%s (sequence_id INTEGER PRIMARY KEY, " \ "alert_unique_id, date_created, date_submitted, date_cloud_ack, filtered_alert_unique_id NOT NULL, " \ "unique(alert_unique_id));" @@ -79,6 +87,8 @@ struct aclk_sync_host_config { char uuid_str[UUID_STR_LEN]; char node_id[UUID_STR_LEN]; char *alerts_snapshot_uuid; // will contain the snapshot_uuid value if snapshot was requested + uint64_t alerts_log_first_sequence_id; + uint64_t alerts_log_last_sequence_id; }; extern sqlite3 *db_meta; diff --git a/database/sqlite/sqlite_aclk_alert.c b/database/sqlite/sqlite_aclk_alert.c index 52d343acb..d57ae043f 100644 --- a/database/sqlite/sqlite_aclk_alert.c +++ b/database/sqlite/sqlite_aclk_alert.c @@ -7,37 +7,7 @@ #include "../../aclk/aclk_alarm_api.h" #endif -#define SQL_GET_ALERT_REMOVE_TIME "SELECT when_key FROM health_log_%s WHERE alarm_id = %u " \ - "AND unique_id > %u AND unique_id < %u " \ - "AND new_status = -2;" - -time_t removed_when(uint32_t alarm_id, uint32_t before_unique_id, uint32_t after_unique_id, char *uuid_str) { - sqlite3_stmt *res = NULL; - time_t when = 0; - char sql[ACLK_SYNC_QUERY_SIZE]; - - snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_GET_ALERT_REMOVE_TIME, uuid_str, alarm_id, after_unique_id, before_unique_id); - - int rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); - if (rc != SQLITE_OK) { - error_report("Failed to prepare statement when trying to find removed gap."); - return 0; - } - - rc = sqlite3_step_monitored(res); - if (likely(rc == SQLITE_ROW)) { - when = (time_t) sqlite3_column_int64(res, 0); - } - - rc = sqlite3_finalize(res); - if (unlikely(rc != SQLITE_OK)) - error_report("Failed to finalize statement when trying to find removed gap, rc = %d", rc); - - return when; -} - #define SQL_UPDATE_FILTERED_ALERT "UPDATE aclk_alert_%s SET filtered_alert_unique_id = %u where filtered_alert_unique_id = %u" - void update_filtered(ALARM_ENTRY *ae, uint32_t unique_id, char *uuid_str) { char sql[ACLK_SYNC_QUERY_SIZE]; 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) { ae->flags |= HEALTH_ENTRY_FLAG_ACLK_QUEUED; } -#define SQL_SELECT_ALERT_BY_UNIQUE_ID "SELECT hl.unique_id FROM health_log_%s hl, alert_hash ah WHERE hl.unique_id = %u " \ - "AND hl.config_hash_id = ah.hash_id " \ +#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 " \ + "AND hl.config_hash_id = ah.hash_id AND hld.health_log_id = hl.health_log_id AND host_id = @host_id " \ "AND ah.warn IS NULL AND ah.crit IS NULL;" - -static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char *uuid_str) { +static inline bool is_event_from_alert_variable_config(uint32_t unique_id, uuid_t *host_id) { sqlite3_stmt *res = NULL; int rc = 0; bool ret = false; char sql[ACLK_SYNC_QUERY_SIZE]; - snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_ALERT_BY_UNIQUE_ID, uuid_str, unique_id); + snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_VARIABLE_ALERT_BY_UNIQUE_ID, unique_id); rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); if (rc != SQLITE_OK) { @@ -63,6 +32,13 @@ static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char return false; } + rc = sqlite3_bind_blob(res, 1, host_id, sizeof(*host_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for checking alert variable."); + sqlite3_finalize(res); + return false; + } + rc = sqlite3_step_monitored(res); if (likely(rc == SQLITE_ROW)) { ret = true; @@ -76,13 +52,12 @@ static inline bool is_event_from_alert_variable_config(uint32_t unique_id, char } #define MAX_REMOVED_PERIOD 604800 //a week -//decide if some events should be sent or not - -#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 " \ - "WHERE hl.unique_id = aa.filtered_alert_unique_id " \ - "AND hl.alarm_id = %u " \ - "ORDER BY alarm_event_id DESC LIMIT 1;" +//decide if some events should be sent or not +#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 " \ + "WHERE hld.unique_id = aa.filtered_alert_unique_id " \ + "AND hld.alarm_id = %u AND hl.host_id = @host_id AND hl.health_log_id = hld.health_log_id " \ + "ORDER BY hld.alarm_event_id DESC LIMIT 1;" int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae) { sqlite3_stmt *res = NULL; @@ -94,7 +69,7 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae) return 0; } - if (unlikely(uuid_is_null(ae->config_hash_id))) + if (unlikely(uuid_is_null(ae->config_hash_id))) return 0; char sql[ACLK_SYNC_QUERY_SIZE]; @@ -104,7 +79,7 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae) //get the previous sent event of this alarm_id //base the search on the last filtered event - snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_ALERT_BY_ID, uuid_str, uuid_str, ae->alarm_id); + snprintfz(sql,ACLK_SYNC_QUERY_SIZE-1, SQL_SELECT_ALERT_BY_ID, uuid_str, ae->alarm_id); int rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); if (rc != SQLITE_OK) { @@ -113,13 +88,19 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae) return send; } + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for checking alert variable."); + sqlite3_finalize(res); + return false; + } + rc = sqlite3_step_monitored(res); if (likely(rc == SQLITE_ROW)) { status = (RRDCALC_STATUS) sqlite3_column_int(res, 0); if (sqlite3_column_type(res, 1) != SQLITE_NULL) uuid_copy(config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 1))); unique_id = (uint32_t) sqlite3_column_int64(res, 2); - } else { send = 1; goto done; @@ -136,26 +117,9 @@ int should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae) } //same status, same config - if (ae->new_status == RRDCALC_STATUS_CLEAR || ae->new_status == RRDCALC_STATUS_UNDEFINED) { - send = 0; - update_filtered(ae, unique_id, uuid_str); - goto done; - } + send = 0; + update_filtered(ae, unique_id, uuid_str); - //detect a long off period of the agent, TODO make global - if (ae->new_status == RRDCALC_STATUS_WARNING || ae->new_status == RRDCALC_STATUS_CRITICAL) { - time_t when = removed_when(ae->alarm_id, ae->unique_id, unique_id, uuid_str); - - if (when && (when + (time_t)MAX_REMOVED_PERIOD) < ae->when) { - send = 1; - goto done; - } else { - send = 0; - update_filtered(ae, unique_id, uuid_str); - goto done; - } - } - done: rc = sqlite3_finalize(res); if (unlikely(rc != SQLITE_OK)) @@ -164,12 +128,8 @@ done: return send; } -// will replace call to aclk_update_alarm in health/health_log.c -// and handle both cases - #define SQL_QUEUE_ALERT_TO_CLOUD "INSERT INTO aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \ "VALUES (@alert_unique_id, unixepoch(), @alert_unique_id) ON CONFLICT (alert_unique_id) do nothing;" - int sql_queue_alarm_to_aclk(RRDHOST *host, ALARM_ENTRY *ae, int skip_filter) { if(!service_running(SERVICE_ACLK)) @@ -193,7 +153,7 @@ int sql_queue_alarm_to_aclk(RRDHOST *host, ALARM_ENTRY *ae, int skip_filter) char uuid_str[UUID_STR_LEN]; uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - if (is_event_from_alert_variable_config(ae->unique_id, uuid_str)) + if (is_event_from_alert_variable_config(ae->unique_id, &host->host_uuid)) return 0; sqlite3_stmt *res_alert = NULL; @@ -286,7 +246,7 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc) int rc; if (unlikely(!wc->alert_updates)) { - log_access("ACLK STA [%s (%s)]: Ignoring alert push event, updates have been turned off for this node.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); + netdata_log_access("ACLK STA [%s (%s)]: Ignoring alert push event, updates have been turned off for this node.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); return; } @@ -305,21 +265,18 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc) sqlite3_stmt *res = NULL; - buffer_sprintf(sql, "select aa.sequence_id, hl.unique_id, hl.alarm_id, hl.config_hash_id, hl.updated_by_id, hl.when_key, " \ - " hl.duration, hl.non_clear_duration, hl.flags, hl.exec_run_timestamp, hl.delay_up_to_timestamp, hl.name, " \ - " hl.chart, hl.family, hl.exec, hl.recipient, hl.source, hl.units, hl.info, hl.exec_code, hl.new_status, " \ - " hl.old_status, hl.delay, hl.new_value, hl.old_value, hl.last_repeat, hl.chart_context, hl.transition_id, hl.alarm_event_id " \ - " from health_log_%s hl, aclk_alert_%s aa " \ - " where hl.unique_id = aa.alert_unique_id and aa.date_submitted is null " \ - " order by aa.sequence_id asc limit %d;", wc->uuid_str, wc->uuid_str, limit); + buffer_sprintf(sql, "select aa.sequence_id, hld.unique_id, hld.alarm_id, hl.config_hash_id, hld.updated_by_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, ha.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, hl.chart_context, hld.transition_id, hld.alarm_event_id " \ + " from health_log hl, aclk_alert_%s aa, alert_hash ha, health_log_detail hld " \ + " where hld.unique_id = aa.alert_unique_id and hl.config_hash_id = ha.hash_id and aa.date_submitted is null " \ + " and hl.host_id = @host_id and hl.health_log_id = hld.health_log_id " \ + " order by aa.sequence_id asc limit %d;", wc->uuid_str, limit); rc = sqlite3_prepare_v2(db_meta, buffer_tostring(sql), -1, &res, 0); if (rc != SQLITE_OK) { - // Try to create tables - if (wc->host) - sql_create_health_log_table(wc->host); - BUFFER *sql_fix = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite); buffer_sprintf(sql_fix, TABLE_ACLK_ALERT, wc->uuid_str); rc = db_execute(db_meta, buffer_tostring(sql_fix)); @@ -344,10 +301,17 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc) } } - uint64_t first_sequence_id = 0; - uint64_t last_sequence_id = 0; - static __thread uint64_t log_first_sequence_id = 0; - static __thread uint64_t log_last_sequence_id = 0; + rc = sqlite3_bind_blob(res, 1, &wc->host->host_uuid, sizeof(wc->host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for pushing alert event."); + sqlite3_finalize(res); + buffer_free(sql); + freez(claim_id); + return; + } + + uint64_t first_sequence_id = 0; + uint64_t last_sequence_id = 0; while (sqlite3_step_monitored(res) == SQLITE_ROW) { struct alarm_log_entry alarm_log; @@ -371,7 +335,8 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc) alarm_log.timezone = strdupz(rrdhost_abbrev_timezone(wc->host)); alarm_log.exec_path = sqlite3_column_bytes(res, 14) > 0 ? strdupz((char *)sqlite3_column_text(res, 14)) : strdupz((char *)string2str(wc->host->health.health_default_exec)); - alarm_log.conf_source = strdupz((char *)sqlite3_column_text(res, 16)); + + alarm_log.conf_source = sqlite3_column_bytes(res, 16) > 0 ? strdupz((char *)sqlite3_column_text(res, 16)) : strdupz(""); char *edit_command = sqlite3_column_bytes(res, 16) > 0 ? health_edit_command_from_source((char *)sqlite3_column_text(res, 16)) : @@ -420,11 +385,11 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc) if (first_sequence_id == 0) first_sequence_id = (uint64_t) sqlite3_column_int64(res, 0); - if (log_first_sequence_id == 0) - log_first_sequence_id = (uint64_t) sqlite3_column_int64(res, 0); + if (wc->alerts_log_first_sequence_id == 0) + wc->alerts_log_first_sequence_id = (uint64_t) sqlite3_column_int64(res, 0); last_sequence_id = (uint64_t) sqlite3_column_int64(res, 0); - log_last_sequence_id = (uint64_t) sqlite3_column_int64(res, 0); + wc->alerts_log_last_sequence_id = (uint64_t) sqlite3_column_int64(res, 0); destroy_alarm_log_entry(&alarm_log); freez(edit_command); @@ -443,15 +408,15 @@ void aclk_push_alert_event(struct aclk_sync_host_config *wc) rrdhost_flag_set(wc->host, RRDHOST_FLAG_ACLK_STREAM_ALERTS); } else { - if (log_first_sequence_id) - log_access( + if (wc->alerts_log_first_sequence_id) + netdata_log_access( "ACLK RES [%s (%s)]: ALERTS SENT from %" PRIu64 " to %" PRIu64 "", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", - log_first_sequence_id, - log_last_sequence_id); - log_first_sequence_id = 0; - log_last_sequence_id = 0; + wc->alerts_log_first_sequence_id, + wc->alerts_log_last_sequence_id); + wc->alerts_log_first_sequence_id = 0; + wc->alerts_log_last_sequence_id = 0; } rc = sqlite3_finalize(res); @@ -486,19 +451,51 @@ void sql_queue_existing_alerts_to_aclk(RRDHOST *host) char uuid_str[UUID_STR_LEN]; uuid_unparse_lower_fix(&host->host_uuid, uuid_str); BUFFER *sql = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite); + sqlite3_stmt *res = NULL; + int rc; - buffer_sprintf(sql,"delete from aclk_alert_%s; " \ - "insert into aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \ - "select unique_id alert_unique_id, unixepoch(), unique_id alert_unique_id from health_log_%s " \ - "where new_status <> 0 and new_status <> -2 and config_hash_id is not null and updated_by_id = 0 " \ - "order by unique_id asc on conflict (alert_unique_id) do nothing;", uuid_str, uuid_str, uuid_str); + rw_spinlock_write_lock(&host->health_log.spinlock); - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock); + buffer_sprintf(sql, "delete from aclk_alert_%s; ", uuid_str); + if (unlikely(db_execute(db_meta, buffer_tostring(sql)))) { + rw_spinlock_write_unlock(&host->health_log.spinlock); + buffer_free(sql); + return; + } - if (unlikely(db_execute(db_meta, buffer_tostring(sql)))) - error_report("Failed to queue existing ACLK alert events for host %s", rrdhost_hostname(host)); + buffer_flush(sql); + buffer_sprintf(sql, "insert into aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \ + "select hld.unique_id alert_unique_id, unixepoch(), hld.unique_id alert_unique_id from health_log_detail hld, health_log hl " \ + "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 " \ + "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); + + rc = sqlite3_prepare_v2(db_meta, buffer_tostring(sql), -1, &res, 0); + if (rc != SQLITE_OK) { + error_report("Failed to prepare statement when trying to queue existing alerts."); + rw_spinlock_write_unlock(&host->health_log.spinlock); + buffer_free(sql); + return; + } + + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for when trying to queue existing alerts."); + sqlite3_finalize(res); + rw_spinlock_write_unlock(&host->health_log.spinlock); + buffer_free(sql); + return; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to queue existing alerts, rc = %d", rc); + } + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize statement to queue existing alerts, rc = %d", rc); - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock); + rw_spinlock_write_unlock(&host->health_log.spinlock); buffer_free(sql); rrdhost_flag_set(host, RRDHOST_FLAG_ACLK_STREAM_ALERTS); @@ -514,7 +511,7 @@ void aclk_send_alarm_configuration(char *config_hash) if (unlikely(!wc)) return; - log_access("ACLK REQ [%s (%s)]: Request to send alert config %s.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash); + netdata_log_access("ACLK REQ [%s (%s)]: Request to send alert config %s.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash); aclk_push_alert_config(wc->node_id, config_hash); } @@ -522,8 +519,7 @@ void aclk_send_alarm_configuration(char *config_hash) #define SQL_SELECT_ALERT_CONFIG "SELECT alarm, template, on_key, class, type, component, os, hosts, plugin," \ "module, charts, families, lookup, every, units, green, red, calc, warn, crit, to_key, exec, delay, repeat, info," \ "options, host_labels, p_db_lookup_dimensions, p_db_lookup_method, p_db_lookup_options, p_db_lookup_after," \ - "p_db_lookup_before, p_update_every FROM alert_hash WHERE hash_id = @hash_id;" - + "p_db_lookup_before, p_update_every, chart_labels FROM alert_hash WHERE hash_id = @hash_id;" int aclk_push_alert_config_event(char *node_id __maybe_unused, char *config_hash __maybe_unused) { int rc = 0; @@ -624,18 +620,20 @@ int aclk_push_alert_config_event(char *node_id __maybe_unused, char *config_hash alarm_config.p_update_every = sqlite3_column_int(res, 32); + alarm_config.chart_labels = sqlite3_column_bytes(res, 33) > 0 ? strdupz((char *)sqlite3_column_text(res, 33)) : NULL; + p_alarm_config.cfg_hash = strdupz((char *) config_hash); p_alarm_config.cfg = alarm_config; } if (likely(p_alarm_config.cfg_hash)) { - log_access("ACLK RES [%s (%s)]: Sent alert config %s.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash); + netdata_log_access("ACLK RES [%s (%s)]: Sent alert config %s.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash); aclk_send_provide_alarm_cfg(&p_alarm_config); freez(p_alarm_config.cfg_hash); destroy_aclk_alarm_configuration(&alarm_config); } else - log_access("ACLK STA [%s (%s)]: Alert config for %s not found.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash); + netdata_log_access("ACLK STA [%s (%s)]: Alert config for %s not found.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash); bind_fail: rc = sqlite3_finalize(res); @@ -670,28 +668,26 @@ void aclk_start_alert_streaming(char *node_id, bool resets) return; if (unlikely(!host->health.health_enabled)) { - log_access("ACLK STA [%s (N/A)]: Ignoring request to stream alert state changes, health is disabled.", node_id); + netdata_log_access("ACLK STA [%s (N/A)]: Ignoring request to stream alert state changes, health is disabled.", node_id); return; } if (resets) { - log_access("ACLK REQ [%s (%s)]: STREAM ALERTS ENABLED (RESET REQUESTED)", node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); + netdata_log_access("ACLK REQ [%s (%s)]: STREAM ALERTS ENABLED (RESET REQUESTED)", node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); sql_queue_existing_alerts_to_aclk(host); } else - log_access("ACLK REQ [%s (%s)]: STREAM ALERTS ENABLED", node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); + netdata_log_access("ACLK REQ [%s (%s)]: STREAM ALERTS ENABLED", node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); wc->alert_updates = 1; wc->alert_queue_removed = SEND_REMOVED_AFTER_HEALTH_LOOPS; } #define SQL_QUEUE_REMOVE_ALERTS "INSERT INTO aclk_alert_%s (alert_unique_id, date_created, filtered_alert_unique_id) " \ - "SELECT unique_id alert_unique_id, UNIXEPOCH(), unique_id alert_unique_id FROM health_log_%s " \ - "WHERE new_status = -2 AND updated_by_id = 0 AND unique_id NOT IN " \ - "(SELECT alert_unique_id FROM aclk_alert_%s) " \ - "AND config_hash_id NOT IN (select hash_id from alert_hash where warn is null and crit is null) " \ - "ORDER BY unique_id ASC " \ - "ON CONFLICT (alert_unique_id) DO NOTHING;" - + "SELECT hld.unique_id alert_unique_id, UNIXEPOCH(), hld.unique_id alert_unique_id FROM health_log hl, health_log_detail hld " \ + "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 " \ + "AND hld.unique_id NOT IN (SELECT alert_unique_id FROM aclk_alert_%s) " \ + "AND hl.config_hash_id NOT IN (select hash_id from alert_hash where warn is null and crit is null) " \ + "ORDER BY hld.unique_id ASC ON CONFLICT (alert_unique_id) DO NOTHING;" void sql_process_queue_removed_alerts_to_aclk(char *node_id) { struct aclk_sync_host_config *wc; @@ -702,15 +698,35 @@ void sql_process_queue_removed_alerts_to_aclk(char *node_id) return; char sql[ACLK_SYNC_QUERY_SIZE * 2]; + sqlite3_stmt *res = NULL; - snprintfz(sql,ACLK_SYNC_QUERY_SIZE * 2 - 1, SQL_QUEUE_REMOVE_ALERTS, wc->uuid_str, wc->uuid_str, wc->uuid_str); + snprintfz(sql, ACLK_SYNC_QUERY_SIZE * 2 - 1, SQL_QUEUE_REMOVE_ALERTS, wc->uuid_str, wc->uuid_str); - if (unlikely(db_execute(db_meta, sql))) { - log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS FAILED", wc->node_id, rrdhost_hostname(wc->host)); - error_report("Failed to queue ACLK alert removed entries for host %s", rrdhost_hostname(wc->host)); + int rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); + if (rc != SQLITE_OK) { + error_report("Failed to prepare statement when trying to queue removed alerts."); + return; } - else - log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS", wc->node_id, rrdhost_hostname(wc->host)); + + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for when trying to queue remvoed alerts."); + sqlite3_finalize(res); + return; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + sqlite3_finalize(res); + error_report("Failed to queue removed alerts, rc = %d", rc); + return; + } + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize statement to queue removed alerts, rc = %d", rc); + + netdata_log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS", wc->node_id, rrdhost_hostname(wc->host)); rrdhost_flag_set(wc->host, RRDHOST_FLAG_ACLK_STREAM_ALERTS); wc->alert_queue_removed = 0; @@ -738,18 +754,18 @@ void aclk_process_send_alarm_snapshot(char *node_id, char *claim_id __maybe_unus RRDHOST *host = find_host_by_node_id(node_id); if (unlikely(!host)) { - log_access("ACLK STA [%s (N/A)]: ACLK node id does not exist", node_id); + netdata_log_access("ACLK STA [%s (N/A)]: ACLK node id does not exist", node_id); return; } struct aclk_sync_host_config *wc = (struct aclk_sync_host_config *)host->aclk_sync_host_config; if (unlikely(!wc)) { - log_access("ACLK STA [%s (N/A)]: ACLK node id does not exist", node_id); + netdata_log_access("ACLK STA [%s (N/A)]: ACLK node id does not exist", node_id); return; } - log_access( + netdata_log_access( "IN [%s (%s)]: Request to send alerts snapshot, snapshot_uuid %s", node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", @@ -842,7 +858,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused) RRDHOST *host = find_host_by_node_id(node_id); if (unlikely(!host)) { - log_access("AC [%s (N/A)]: Node id not found", node_id); + netdata_log_access("AC [%s (N/A)]: Node id not found", node_id); freez(node_id); return; } @@ -852,7 +868,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused) // we perhaps we don't need this for snapshots if (unlikely(!wc->alert_updates)) { - log_access( + netdata_log_access( "ACLK STA [%s (%s)]: Ignoring alert snapshot event, updates have been turned off for this node.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A"); @@ -866,13 +882,13 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused) if (unlikely(!claim_id)) return; - log_access("ACLK REQ [%s (%s)]: Sending alerts snapshot, snapshot_uuid %s", wc->node_id, rrdhost_hostname(wc->host), wc->alerts_snapshot_uuid); + netdata_log_access("ACLK REQ [%s (%s)]: Sending alerts snapshot, snapshot_uuid %s", wc->node_id, rrdhost_hostname(wc->host), wc->alerts_snapshot_uuid); uint32_t cnt = 0; char uuid_str[UUID_STR_LEN]; uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock); + rw_spinlock_read_lock(&host->health_log.spinlock); ALARM_ENTRY *ae = host->health_log.alarms; @@ -886,7 +902,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused) if (have_recent_alarm(host, ae->alarm_id, ae->unique_id)) continue; - if (is_event_from_alert_variable_config(ae->unique_id, uuid_str)) + if (is_event_from_alert_variable_config(ae->unique_id, &host->host_uuid)) continue; cnt++; @@ -918,7 +934,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused) if (have_recent_alarm(host, ae->alarm_id, ae->unique_id)) continue; - if (is_event_from_alert_variable_config(ae->unique_id, uuid_str)) + if (is_event_from_alert_variable_config(ae->unique_id, &host->host_uuid)) continue; cnt++; @@ -957,7 +973,7 @@ void aclk_push_alert_snapshot_event(char *node_id __maybe_unused) aclk_send_alarm_snapshot(snapshot_proto); } - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock); + rw_spinlock_read_unlock(&host->health_log.spinlock); wc->alerts_snapshot_uuid = NULL; freez(claim_id); @@ -984,7 +1000,6 @@ void sql_aclk_alert_clean_dead_entries(RRDHOST *host) #define SQL_GET_MIN_MAX_ALERT_SEQ "SELECT MIN(sequence_id), MAX(sequence_id), " \ "(SELECT MAX(sequence_id) FROM aclk_alert_%s WHERE date_submitted IS NOT NULL) " \ "FROM aclk_alert_%s WHERE date_submitted IS NULL;" - int get_proto_alert_status(RRDHOST *host, struct proto_alert_status *proto_alert_status) { int rc; @@ -1032,11 +1047,11 @@ void aclk_send_alarm_checkpoint(char *node_id, char *claim_id __maybe_unused) wc = (struct aclk_sync_host_config *)host->aclk_sync_host_config; if (unlikely(!wc)) { - log_access("ACLK REQ [%s (N/A)]: ALERTS CHECKPOINT REQUEST RECEIVED FOR INVALID NODE", node_id); + netdata_log_access("ACLK REQ [%s (N/A)]: ALERTS CHECKPOINT REQUEST RECEIVED FOR INVALID NODE", node_id); return; } - log_access("ACLK REQ [%s (%s)]: ALERTS CHECKPOINT REQUEST RECEIVED", node_id, rrdhost_hostname(host)); + netdata_log_access("ACLK REQ [%s (%s)]: ALERTS CHECKPOINT REQUEST RECEIVED", node_id, rrdhost_hostname(host)); wc->alert_checkpoint_req = SEND_CHECKPOINT_AFTER_HEALTH_LOOPS; } @@ -1065,14 +1080,14 @@ void aclk_push_alarm_checkpoint(RRDHOST *host __maybe_unused) #ifdef ENABLE_ACLK struct aclk_sync_host_config *wc = host->aclk_sync_host_config; if (unlikely(!wc)) { - log_access("ACLK REQ [%s (N/A)]: ALERTS CHECKPOINT REQUEST RECEIVED FOR INVALID NODE", rrdhost_hostname(host)); + netdata_log_access("ACLK REQ [%s (N/A)]: ALERTS CHECKPOINT REQUEST RECEIVED FOR INVALID NODE", rrdhost_hostname(host)); return; } if (rrdhost_flag_check(host, RRDHOST_FLAG_ACLK_STREAM_ALERTS)) { //postpone checkpoint send wc->alert_checkpoint_req+=3; - log_access("ACLK REQ [%s (N/A)]: ALERTS CHECKPOINT POSTPONED", rrdhost_hostname(host)); + netdata_log_access("ACLK REQ [%s (N/A)]: ALERTS CHECKPOINT POSTPONED", rrdhost_hostname(host)); return; } @@ -1135,9 +1150,9 @@ void aclk_push_alarm_checkpoint(RRDHOST *host __maybe_unused) aclk_send_provide_alarm_checkpoint(&alarm_checkpoint); freez(claim_id); - log_access("ACLK RES [%s (%s)]: ALERTS CHECKPOINT SENT", wc->node_id, rrdhost_hostname(host)); + netdata_log_access("ACLK RES [%s (%s)]: ALERTS CHECKPOINT SENT", wc->node_id, rrdhost_hostname(host)); } else { - log_access("ACLK RES [%s (%s)]: FAILED TO CREATE ALERTS CHECKPOINT HASH", wc->node_id, rrdhost_hostname(host)); + netdata_log_access("ACLK RES [%s (%s)]: FAILED TO CREATE ALERTS CHECKPOINT HASH", wc->node_id, rrdhost_hostname(host)); } wc->alert_checkpoint_req = 0; buffer_free(alarms_to_hash); diff --git a/database/sqlite/sqlite_aclk_node.c b/database/sqlite/sqlite_aclk_node.c index 3817296da..82927854a 100644 --- a/database/sqlite/sqlite_aclk_node.c +++ b/database/sqlite/sqlite_aclk_node.c @@ -50,7 +50,7 @@ static void build_node_collectors(char *node_id __maybe_unused) dictionary_destroy(dict); freez(upd_node_collectors.claim_id); - log_access("ACLK RES [%s (%s)]: NODE COLLECTORS SENT", node_id, rrdhost_hostname(host)); + netdata_log_access("ACLK RES [%s (%s)]: NODE COLLECTORS SENT", node_id, rrdhost_hostname(host)); freez(node_id); } @@ -124,7 +124,7 @@ static void build_node_info(char *node_id __maybe_unused) node_info.data.host_labels_ptr = host->rrdlabels; aclk_update_node_info(&node_info); - log_access("ACLK RES [%s (%s)]: NODE INFO SENT for guid [%s] (%s)", wc->node_id, rrdhost_hostname(wc->host), host->machine_guid, wc->host == localhost ? "parent" : "child"); + netdata_log_access("ACLK RES [%s (%s)]: NODE INFO SENT for guid [%s] (%s)", wc->node_id, rrdhost_hostname(wc->host), host->machine_guid, wc->host == localhost ? "parent" : "child"); rrd_unlock(); freez(node_info.claim_id); @@ -172,7 +172,7 @@ void aclk_check_node_info_and_collectors(void) dfe_done(host); if(pending) - info("ACLK: %zu nodes are pending for contexts to load, skipped sending node info for them", pending); + netdata_log_info("ACLK: %zu nodes are pending for contexts to load, skipped sending node info for them", pending); } #endif diff --git a/database/sqlite/sqlite_context.c b/database/sqlite/sqlite_context.c index b72726dc2..f29fe51e3 100644 --- a/database/sqlite/sqlite_context.c +++ b/database/sqlite/sqlite_context.c @@ -43,7 +43,7 @@ int sql_init_context_database(int memory) return 1; } - info("SQLite database %s initialization", sqlite_database); + netdata_log_info("SQLite database %s initialization", sqlite_database); char buf[1024 + 1] = ""; const char *list[2] = { buf, NULL }; @@ -112,7 +112,7 @@ void sql_close_context_database(void) if (unlikely(!db_context_meta)) return; - info("Closing context SQLite database"); + netdata_log_info("Closing context SQLite database"); rc = sqlite3_close_v2(db_context_meta); if (unlikely(rc != SQLITE_OK)) @@ -431,7 +431,7 @@ int ctx_delete_context(uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data) else { char host_uuid_str[UUID_STR_LEN]; uuid_unparse_lower(*host_uuid, host_uuid_str); - info("%s: Deleted context %s under host %s", __FUNCTION__, context_data->id, host_uuid_str); + netdata_log_info("%s: Deleted context %s under host %s", __FUNCTION__, context_data->id, host_uuid_str); } #endif @@ -463,7 +463,7 @@ int sql_context_cache_stats(int op) static void dict_ctx_get_context_list_cb(VERSIONED_CONTEXT_DATA *context_data, void *data) { (void)data; - info(" Context id = %s " + netdata_log_info(" Context id = %s " "version = %"PRIu64" " "title = %s " "chart_type = %s " @@ -512,48 +512,48 @@ int ctx_unittest(void) context_data.version = now_realtime_usec(); if (likely(!ctx_store_context(&host_uuid, &context_data))) - info("Entry %s inserted", context_data.id); + netdata_log_info("Entry %s inserted", context_data.id); else - info("Entry %s not inserted", context_data.id); + netdata_log_info("Entry %s not inserted", context_data.id); if (likely(!ctx_store_context(&host_uuid, &context_data))) - info("Entry %s inserted", context_data.id); + netdata_log_info("Entry %s inserted", context_data.id); else - info("Entry %s not inserted", context_data.id); + netdata_log_info("Entry %s not inserted", context_data.id); // This will change end time context_data.first_time_s = 1657781000; context_data.last_time_s = 1657782001; if (likely(!ctx_update_context(&host_uuid, &context_data))) - info("Entry %s updated", context_data.id); + netdata_log_info("Entry %s updated", context_data.id); else - info("Entry %s not updated", context_data.id); - info("List context start after insert"); + netdata_log_info("Entry %s not updated", context_data.id); + netdata_log_info("List context start after insert"); ctx_get_context_list(&host_uuid, dict_ctx_get_context_list_cb, NULL); - info("List context end after insert"); + netdata_log_info("List context end after insert"); // This will change start time context_data.first_time_s = 1657782000; context_data.last_time_s = 1657782001; if (likely(!ctx_update_context(&host_uuid, &context_data))) - info("Entry %s updated", context_data.id); + netdata_log_info("Entry %s updated", context_data.id); else - info("Entry %s not updated", context_data.id); + netdata_log_info("Entry %s not updated", context_data.id); // This will list one entry - info("List context start after insert"); + netdata_log_info("List context start after insert"); ctx_get_context_list(&host_uuid, dict_ctx_get_context_list_cb, NULL); - info("List context end after insert"); + netdata_log_info("List context end after insert"); - info("List context start after insert"); + netdata_log_info("List context start after insert"); ctx_get_context_list(&host_uuid, dict_ctx_get_context_list_cb, NULL); - info("List context end after insert"); + netdata_log_info("List context end after insert"); // This will delete the entry if (likely(!ctx_delete_context(&host_uuid, &context_data))) - info("Entry %s deleted", context_data.id); + netdata_log_info("Entry %s deleted", context_data.id); else - info("Entry %s not deleted", context_data.id); + netdata_log_info("Entry %s not deleted", context_data.id); freez((void *)context_data.id); freez((void *)context_data.title); @@ -562,9 +562,9 @@ int ctx_unittest(void) freez((void *)context_data.units); // The list should be empty - info("List context start after delete"); + netdata_log_info("List context start after delete"); ctx_get_context_list(&host_uuid, dict_ctx_get_context_list_cb, NULL); - info("List context end after delete"); + netdata_log_info("List context end after delete"); sql_close_context_database(); diff --git a/database/sqlite/sqlite_db_migration.c b/database/sqlite/sqlite_db_migration.c index 9c7235fdb..1a6233fce 100644 --- a/database/sqlite/sqlite_db_migration.c +++ b/database/sqlite/sqlite_db_migration.c @@ -11,7 +11,6 @@ static int return_int_cb(void *data, int argc, char **argv, char **column) return 0; } - int table_exists_in_database(const char *table) { char *err_msg = NULL; @@ -23,7 +22,7 @@ int table_exists_in_database(const char *table) int rc = sqlite3_exec_monitored(db_meta, sql, return_int_cb, (void *) &exists, &err_msg); if (rc != SQLITE_OK) { - info("Error checking table existence; %s", err_msg); + netdata_log_info("Error checking table existence; %s", err_msg); sqlite3_free(err_msg); } @@ -41,7 +40,7 @@ static int column_exists_in_table(const char *table, const char *column) int rc = sqlite3_exec_monitored(db_meta, sql, return_int_cb, (void *) &exists, &err_msg); if (rc != SQLITE_OK) { - info("Error checking column existence; %s", err_msg); + netdata_log_info("Error checking column existence; %s", err_msg); sqlite3_free(err_msg); } @@ -79,11 +78,15 @@ const char *database_migrate_v5_v6[] = { NULL }; +const char *database_migrate_v9_v10[] = { + "ALTER TABLE alert_hash ADD chart_labels TEXT;", + NULL +}; static int do_migration_v1_v2(sqlite3 *database, const char *name) { UNUSED(name); - info("Running \"%s\" database migration", name); + netdata_log_info("Running \"%s\" database migration", name); if (table_exists_in_database("host") && !column_exists_in_table("host", "hops")) return init_database_batch(database, DB_CHECK_NONE, 0, &database_migrate_v1_v2[0]); @@ -93,7 +96,7 @@ static int do_migration_v1_v2(sqlite3 *database, const char *name) static int do_migration_v2_v3(sqlite3 *database, const char *name) { UNUSED(name); - info("Running \"%s\" database migration", name); + netdata_log_info("Running \"%s\" database migration", name); if (table_exists_in_database("host") && !column_exists_in_table("host", "memory_mode")) return init_database_batch(database, DB_CHECK_NONE, 0, &database_migrate_v2_v3[0]); @@ -103,7 +106,7 @@ static int do_migration_v2_v3(sqlite3 *database, const char *name) static int do_migration_v3_v4(sqlite3 *database, const char *name) { UNUSED(name); - info("Running database migration %s", name); + netdata_log_info("Running database migration %s", name); char sql[256]; @@ -135,7 +138,7 @@ static int do_migration_v3_v4(sqlite3 *database, const char *name) static int do_migration_v4_v5(sqlite3 *database, const char *name) { UNUSED(name); - info("Running \"%s\" database migration", name); + netdata_log_info("Running \"%s\" database migration", name); return init_database_batch(database, DB_CHECK_NONE, 0, &database_migrate_v4_v5[0]); } @@ -143,7 +146,7 @@ static int do_migration_v4_v5(sqlite3 *database, const char *name) static int do_migration_v5_v6(sqlite3 *database, const char *name) { UNUSED(name); - info("Running \"%s\" database migration", name); + netdata_log_info("Running \"%s\" database migration", name); return init_database_batch(database, DB_CHECK_NONE, 0, &database_migrate_v5_v6[0]); } @@ -151,7 +154,7 @@ static int do_migration_v5_v6(sqlite3 *database, const char *name) static int do_migration_v6_v7(sqlite3 *database, const char *name) { UNUSED(name); - info("Running \"%s\" database migration", name); + netdata_log_info("Running \"%s\" database migration", name); char sql[256]; @@ -185,7 +188,7 @@ static int do_migration_v6_v7(sqlite3 *database, const char *name) static int do_migration_v7_v8(sqlite3 *database, const char *name) { UNUSED(name); - info("Running database migration %s", name); + netdata_log_info("Running database migration %s", name); char sql[256]; @@ -214,12 +217,95 @@ static int do_migration_v7_v8(sqlite3 *database, const char *name) return 0; } +static int do_migration_v8_v9(sqlite3 *database, const char *name) +{ + netdata_log_info("Running database migration %s", name); + + char sql[2048]; + int rc; + sqlite3_stmt *res = NULL; + + //create the health_log table and it's index + snprintfz(sql, 2047, "CREATE TABLE IF NOT EXISTS health_log (health_log_id INTEGER PRIMARY KEY, host_id blob, alarm_id int, " \ + "config_hash_id blob, name text, chart text, family text, recipient text, units text, exec text, " \ + "chart_context text, last_transition_id blob, UNIQUE (host_id, alarm_id)) ;"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + //TODO indexes + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_ind_1 ON health_log (host_id);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + 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, " \ + "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, " \ + "info text, exec_code int, new_status real, old_status real, delay int, " \ + "new_value double, old_value double, last_repeat int, transition_id blob, global_id int, host_id blob);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_1 ON health_log_detail (unique_id);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_2 ON health_log_detail (global_id);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_3 ON health_log_detail (transition_id);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS health_log_d_ind_4 ON health_log_detail (health_log_id);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + snprintfz(sql, 2047, "ALTER TABLE alert_hash ADD source text;"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + snprintfz(sql, 2047, "CREATE INDEX IF NOT EXISTS alert_hash_index ON alert_hash (hash_id);"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + snprintfz(sql, 2047, "SELECT name FROM sqlite_schema WHERE type ='table' AND name LIKE 'health_log_%%' AND name <> 'health_log_detail';"); + rc = sqlite3_prepare_v2(database, sql, -1, &res, 0); + if (rc != SQLITE_OK) { + error_report("Failed to prepare statement to alter health_log tables"); + return 1; + } + + DICTIONARY *dict_tables = dictionary_create(DICT_OPTION_NONE); + + while (sqlite3_step_monitored(res) == SQLITE_ROW) { + char *table = strdupz((char *) sqlite3_column_text(res, 0)); + if (health_migrate_old_health_log_table(table)) { + dictionary_set(dict_tables, table, NULL, 0); + } + freez(table); + } + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize statement when copying health_log tables, rc = %d", rc); + + char *table = NULL; + dfe_start_read(dict_tables, table) { + sql_drop_table(table_dfe.name); + } + dfe_done(table); + dictionary_destroy(dict_tables); + + snprintfz(sql, 2047, "ALTER TABLE health_log_detail DROP COLUMN host_id;"); + sqlite3_exec_monitored(database, sql, 0, 0, NULL); + + return 0; +} + +static int do_migration_v9_v10(sqlite3 *database, const char *name) +{ + UNUSED(name); + netdata_log_info("Running \"%s\" database migration", name); + + if (table_exists_in_database("alert_hash") && !column_exists_in_table("alert_hash", "chart_labels")) + return init_database_batch(database, DB_CHECK_NONE, 0, &database_migrate_v9_v10[0]); + return 0; +} static int do_migration_noop(sqlite3 *database, const char *name) { UNUSED(database); UNUSED(name); - info("Running database migration %s", name); + netdata_log_info("Running database migration %s", name); return 0; } @@ -236,16 +322,16 @@ static int migrate_database(sqlite3 *database, int target_version, char *db_name int rc = sqlite3_exec_monitored(database, "PRAGMA user_version;", return_int_cb, (void *) &user_version, &err_msg); if (rc != SQLITE_OK) { - info("Error checking the %s database version; %s", db_name, err_msg); + netdata_log_info("Error checking the %s database version; %s", db_name, err_msg); sqlite3_free(err_msg); } if (likely(user_version == target_version)) { - info("%s database version is %d (no migration needed)", db_name, target_version); + netdata_log_info("%s database version is %d (no migration needed)", db_name, target_version); return target_version; } - info("Database version is %d, current version is %d. Running migration for %s ...", user_version, target_version, db_name); + netdata_log_info("Database version is %d, current version is %d. Running migration for %s ...", user_version, target_version, db_name); for (int i = user_version; i < target_version && migration_list[i].func; i++) { rc = (migration_list[i].func)(database, migration_list[i].name); if (unlikely(rc)) { @@ -266,6 +352,8 @@ DATABASE_FUNC_MIGRATION_LIST migration_action[] = { {.name = "v5 to v6", .func = do_migration_v5_v6}, {.name = "v6 to v7", .func = do_migration_v6_v7}, {.name = "v7 to v8", .func = do_migration_v7_v8}, + {.name = "v8 to v9", .func = do_migration_v8_v9}, + {.name = "v9 to v10", .func = do_migration_v9_v10}, // the terminator of this array {.name = NULL, .func = NULL} }; diff --git a/database/sqlite/sqlite_functions.c b/database/sqlite/sqlite_functions.c index 555db1011..4200c1590 100644 --- a/database/sqlite/sqlite_functions.c +++ b/database/sqlite/sqlite_functions.c @@ -3,7 +3,7 @@ #include "sqlite_functions.h" #include "sqlite_db_migration.h" -#define DB_METADATA_VERSION 8 +#define DB_METADATA_VERSION 10 const char *database_config[] = { "CREATE TABLE IF NOT EXISTS host(host_id BLOB PRIMARY KEY, hostname TEXT NOT NULL, " @@ -32,7 +32,9 @@ const char *database_config[] = { "every text, units text, calc text, families text, plugin text, module text, charts text, green text, " "red text, warn text, crit text, exec text, to_key text, info text, delay text, options text, " "repeat text, host_labels text, p_db_lookup_dimensions text, p_db_lookup_method text, p_db_lookup_options int, " - "p_db_lookup_after int, p_db_lookup_before int, p_update_every int);", + "p_db_lookup_after int, p_db_lookup_before int, p_update_every int, source text, chart_labels text);", + + "CREATE INDEX IF NOT EXISTS alert_hash_index ON alert_hash (hash_id);", "CREATE TABLE IF NOT EXISTS host_info(host_id blob, system_key text NOT NULL, system_value text NOT NULL, " "date_created INT, PRIMARY KEY(host_id, system_key));", @@ -43,6 +45,23 @@ const char *database_config[] = { "CREATE TRIGGER IF NOT EXISTS ins_host AFTER INSERT ON host BEGIN INSERT INTO node_instance (host_id, date_created)" " SELECT new.host_id, unixepoch() WHERE new.host_id NOT IN (SELECT host_id FROM node_instance); END;", + "CREATE TABLE IF NOT EXISTS health_log (health_log_id INTEGER PRIMARY KEY, host_id blob, alarm_id int, " + "config_hash_id blob, name text, chart text, family text, recipient text, units text, exec text, " + "chart_context text, last_transition_id blob, UNIQUE (host_id, alarm_id)) ;", + + "CREATE INDEX IF NOT EXISTS health_log_ind_1 ON health_log (host_id);", + + "CREATE TABLE IF NOT EXISTS health_log_detail (health_log_id int, unique_id int, alarm_id int, alarm_event_id int, " + "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, " + "info text, exec_code int, new_status real, old_status real, delay int, " + "new_value double, old_value double, last_repeat int, transition_id blob, global_id int);", + + "CREATE INDEX IF NOT EXISTS health_log_d_ind_1 ON health_log_detail (unique_id);", + "CREATE INDEX IF NOT EXISTS health_log_d_ind_2 ON health_log_detail (global_id);", + "CREATE INDEX IF NOT EXISTS health_log_d_ind_3 ON health_log_detail (transition_id);", + "CREATE INDEX IF NOT EXISTS health_log_d_ind_4 ON health_log_detail (health_log_id);", + NULL }; @@ -128,9 +147,9 @@ static void add_stmt_to_list(sqlite3_stmt *res) if (unlikely(!res)) { if (idx) - info("Finilizing %d statements", idx); + netdata_log_info("Finilizing %d statements", idx); else - info("No statements pending to finalize"); + netdata_log_info("No statements pending to finalize"); while (idx > 0) { int rc; rc = sqlite3_finalize(statements[--idx]); @@ -148,7 +167,7 @@ static void release_statement(void *statement) { int rc; #ifdef NETDATA_DEV_MODE - info("Thread %d: Cleaning prepared statement on %p", gettid(), statement); + netdata_log_info("Thread %d: Cleaning prepared statement on %p", gettid(), statement); #endif if (unlikely(rc = sqlite3_finalize((sqlite3_stmt *) statement) != SQLITE_OK)) error_report("Failed to finalize statement, rc = %d", rc); @@ -175,7 +194,7 @@ int prepare_statement(sqlite3 *database, const char *query, sqlite3_stmt **state if (likely(key)) { ret = pthread_setspecific(*key, *statement); #ifdef NETDATA_DEV_MODE - info("Thread %d: Using key %u on statement %p", gettid(), keys_used, *statement); + netdata_log_info("Thread %d: Using key %u on statement %p", gettid(), keys_used, *statement); #endif } if (ret) @@ -189,7 +208,7 @@ static int check_table_integrity_cb(void *data, int argc, char **argv, char **co int *status = data; UNUSED(argc); UNUSED(column); - info("---> %s", argv[0]); + netdata_log_info("---> %s", argv[0]); *status = (strcmp(argv[0], "ok") != 0); return 0; } @@ -202,11 +221,11 @@ static int check_table_integrity(char *table) char wstr[255]; if (table) { - info("Checking table %s", table); + netdata_log_info("Checking table %s", table); snprintfz(wstr, 254, "PRAGMA integrity_check(%s);", table); } else { - info("Checking entire database"); + netdata_log_info("Checking entire database"); strcpy(wstr,"PRAGMA integrity_check;"); } @@ -240,9 +259,9 @@ static void rebuild_chart() { int rc; char *err_msg = NULL; - info("Rebuilding chart table"); + netdata_log_info("Rebuilding chart table"); for (int i = 0; rebuild_chart_commands[i]; i++) { - info("Executing %s", rebuild_chart_commands[i]); + netdata_log_info("Executing %s", rebuild_chart_commands[i]); rc = sqlite3_exec_monitored(db_meta, rebuild_chart_commands[i], 0, 0, &err_msg); if (rc != SQLITE_OK) { error_report("SQLite error during database setup, rc = %d (%s)", rc, err_msg); @@ -272,9 +291,9 @@ void rebuild_dimension() int rc; char *err_msg = NULL; - info("Rebuilding dimension table"); + netdata_log_info("Rebuilding dimension table"); for (int i = 0; rebuild_dimension_commands[i]; i++) { - info("Executing %s", rebuild_dimension_commands[i]); + netdata_log_info("Executing %s", rebuild_dimension_commands[i]); rc = sqlite3_exec_monitored(db_meta, rebuild_dimension_commands[i], 0, 0, &err_msg); if (rc != SQLITE_OK) { error_report("SQLite error during database setup, rc = %d (%s)", rc, err_msg); @@ -286,11 +305,11 @@ void rebuild_dimension() static int attempt_database_fix() { - info("Closing database and attempting to fix it"); + netdata_log_info("Closing database and attempting to fix it"); int rc = sqlite3_close(db_meta); if (rc != SQLITE_OK) error_report("Failed to close database, rc = %d", rc); - info("Attempting to fix database"); + netdata_log_info("Attempting to fix database"); db_meta = NULL; return sql_init_database(DB_CHECK_FIX_DB | DB_CHECK_CONT, 0); } @@ -300,7 +319,7 @@ int init_database_batch(sqlite3 *database, int rebuild, int init_type, const cha int rc; char *err_msg = NULL; for (int i = 0; batch[i]; i++) { - debug(D_METADATALOG, "Executing %s", batch[i]); + netdata_log_debug(D_METADATALOG, "Executing %s", batch[i]); rc = sqlite3_exec_monitored(database, batch[i], 0, 0, &err_msg); if (rc != SQLITE_OK) { error_report("SQLite error during database %s, rc = %d (%s)", init_type ? "cleanup" : "setup", rc, err_msg); @@ -336,6 +355,30 @@ static void sqlite_uuid_parse(sqlite3_context *context, int argc, sqlite3_value sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT); } +void sqlite_now_usec(sqlite3_context *context, int argc, sqlite3_value **argv) +{ + if (argc != 1 ){ + sqlite3_result_null(context); + return ; + } + + if (sqlite3_value_int(argv[0]) != 0) { + struct timespec req = {.tv_sec = 0, .tv_nsec = 1}; + nanosleep(&req, NULL); + } + + sqlite3_result_int64(context, (sqlite_int64) now_realtime_usec()); +} + +void sqlite_uuid_random(sqlite3_context *context, int argc, sqlite3_value **argv) +{ + (void)argc; + (void)argv; + + uuid_t uuid; + uuid_generate_random(uuid); + sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT); +} /* * Initialize the SQLite database @@ -363,7 +406,7 @@ int sql_init_database(db_check_action_type_t rebuild, int memory) if (rebuild & (DB_CHECK_INTEGRITY | DB_CHECK_FIX_DB)) { int errors_detected = 0; if (!(rebuild & DB_CHECK_CONT)) - info("Running database check on %s", sqlite_database); + netdata_log_info("Running database check on %s", sqlite_database); if (check_table_integrity("chart")) { errors_detected++; @@ -389,7 +432,7 @@ int sql_init_database(db_check_action_type_t rebuild, int memory) if (rebuild & DB_CHECK_RECLAIM_SPACE) { if (!(rebuild & DB_CHECK_CONT)) - info("Reclaiming space of %s", sqlite_database); + netdata_log_info("Reclaiming space of %s", sqlite_database); rc = sqlite3_exec_monitored(db_meta, "VACUUM;", 0, 0, &err_msg); if (rc != SQLITE_OK) { error_report("Failed to execute VACUUM rc = %d (%s)", rc, err_msg); @@ -400,11 +443,23 @@ int sql_init_database(db_check_action_type_t rebuild, int memory) if (rebuild && !(rebuild & DB_CHECK_CONT)) return 1; - info("SQLite database %s initialization", sqlite_database); + netdata_log_info("SQLite database %s initialization", sqlite_database); char buf[1024 + 1] = ""; const char *list[2] = { buf, NULL }; + rc = sqlite3_create_function(db_meta, "u2h", 1, SQLITE_ANY | SQLITE_DETERMINISTIC, 0, sqlite_uuid_parse, 0, 0); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to register internal u2h function"); + + rc = sqlite3_create_function(db_meta, "now_usec", 1, SQLITE_ANY, 0, sqlite_now_usec, 0, 0); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to register internal now_usec function"); + + rc = sqlite3_create_function(db_meta, "uuid_random", 0, SQLITE_ANY, 0, sqlite_uuid_random, 0, 0); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to register internal uuid_random function"); + int target_version = DB_METADATA_VERSION; if (likely(!memory)) @@ -450,13 +505,10 @@ int sql_init_database(db_check_action_type_t rebuild, int memory) if (init_database_batch(db_meta, rebuild, 0, &database_cleanup[0])) return 1; - info("SQLite database initialization completed"); + netdata_log_info("SQLite database initialization completed"); initialize_thread_key_pool(); - rc = sqlite3_create_function(db_meta, "u2h", 1, SQLITE_ANY | SQLITE_DETERMINISTIC, 0, sqlite_uuid_parse, 0, 0); - if (unlikely(rc != SQLITE_OK)) - error_report("Failed to register internal u2h function"); return 0; } @@ -470,7 +522,7 @@ void sql_close_database(void) if (unlikely(!db_meta)) return; - info("Closing SQLite database"); + netdata_log_info("Closing SQLite database"); add_stmt_to_list(NULL); @@ -771,7 +823,7 @@ struct node_instance_list *get_node_list(void) uuid_unparse_lower(*host_id, host_guid); RRDHOST *host = rrdhost_find_by_guid(host_guid); if (rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_CONTEXT_LOAD)) { - info("ACLK: 'host:%s' skipping get node list because context is initializing", rrdhost_hostname(host)); + netdata_log_info("ACLK: 'host:%s' skipping get node list because context is initializing", rrdhost_hostname(host)); continue; } uuid_copy(node_list[row].host_id, *host_id); @@ -927,3 +979,19 @@ int sql_metadata_cache_stats(int op) netdata_thread_enable_cancelability(); return count; } + +#define SQL_DROP_TABLE "DROP table %s;" + +void sql_drop_table(const char *table) +{ + if (!table) + return; + + char wstr[255]; + snprintfz(wstr, 254, SQL_DROP_TABLE, table); + + int rc = sqlite3_exec_monitored(db_meta, wstr, 0, 0, NULL); + if (rc != SQLITE_OK) { + error_report("DES SQLite error during drop table operation for %s, rc = %d", table, rc); + } +} diff --git a/database/sqlite/sqlite_functions.h b/database/sqlite/sqlite_functions.h index ee63a397c..407ed1eff 100644 --- a/database/sqlite/sqlite_functions.h +++ b/database/sqlite/sqlite_functions.h @@ -77,4 +77,6 @@ void invalidate_node_instances(uuid_t *host_id, uuid_t *claim_id); // Provide statistics int sql_metadata_cache_stats(int op); +void sql_drop_table(const char *table); +void sqlite_now_usec(sqlite3_context *context, int argc, sqlite3_value **argv); #endif //NETDATA_SQLITE_FUNCTIONS_H diff --git a/database/sqlite/sqlite_health.c b/database/sqlite/sqlite_health.c index 5c4cdbbd3..3ecd783dc 100644 --- a/database/sqlite/sqlite_health.c +++ b/database/sqlite/sqlite_health.c @@ -7,46 +7,13 @@ #define MAX_HEALTH_SQL_SIZE 2048 #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)) -/* Health related SQL queries - Creates a health log table in sqlite, one per host guid -*/ -#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 -int sql_create_health_log_table(RRDHOST *host) { - int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; - - if (unlikely(!db_meta)) { - if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) - error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host)); - return 1; - } - - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CREATE_HEALTH_LOG_TABLE(uuid_str)); - - rc = db_execute(db_meta, command); - if (unlikely(rc)) - error_report("HEALTH [%s]: SQLite error during creation of health log table", rrdhost_hostname(host)); - else { - 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); - rc = db_execute(db_meta, command); - if (unlikely(unlikely(rc))) - error_report("HEALTH [%s]: SQLite error during creation of health log table index", rrdhost_hostname(host)); - } - - return rc; -} - /* Health related SQL queries Updates an entry in the table */ -#define SQL_UPDATE_HEALTH_LOG(guid) "UPDATE health_log_%s set updated_by_id = ?, flags = ?, exec_run_timestamp = ?, exec_code = ? where unique_id = ?;", guid +#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 = ?;" void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) { sqlite3_stmt *res = NULL; int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; if (unlikely(!db_meta)) { if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) @@ -54,19 +21,10 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) { return; } - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_UPDATE_HEALTH_LOG(uuid_str)); - - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG, -1, &res, 0); if (unlikely(rc != SQLITE_OK)) { - sql_create_health_log_table(host); - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); - if (unlikely(rc != SQLITE_OK)) { - error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host)); - return; - } + error_report("HEALTH [%s]: Failed to prepare statement for SQL_UPDATE_HEALTH_LOG", rrdhost_hostname(host)); + return; } 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) { goto failed; } + rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->alarm_id); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind unique_id parameter for SQL_UPDATE_HEALTH_LOG"); + goto failed; + } + + rc = sqlite3_bind_blob(res, 7, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for SQL_UPDATE_HEALTH_LOG."); + goto failed; + } + rc = execute_insert(res); if (unlikely(rc != SQLITE_DONE)) { error_report("HEALTH [%s]: Failed to update health log, rc = %d", rrdhost_hostname(host), rc); @@ -112,16 +82,19 @@ failed: /* Health related SQL queries Inserts an entry in the table */ -#define SQL_INSERT_HEALTH_LOG(guid) "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, 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) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", guid - +#define SQL_INSERT_HEALTH_LOG "INSERT INTO health_log (host_id, alarm_id, " \ + "config_hash_id, name, chart, family, exec, recipient, units, chart_context, last_transition_id) " \ + "VALUES (?,?,?,?,?,?,?,?,?,?,?) " \ + "ON CONFLICT (host_id, alarm_id) DO UPDATE SET last_transition_id = excluded.last_transition_id RETURNING health_log_id; " + +#define SQL_INSERT_HEALTH_LOG_DETAIL "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) " \ + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,@global_id); " void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) { sqlite3_stmt *res = NULL; int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; + uint64_t health_log_id = 0; if (unlikely(!db_meta)) { if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) @@ -129,222 +102,231 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) { return; } - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INSERT_HEALTH_LOG(uuid_str)); - - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_prepare_v2(db_meta, SQL_INSERT_HEALTH_LOG, -1, &res, 0); if (unlikely(rc != SQLITE_OK)) { - sql_create_health_log_table(host); - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); - if (unlikely(rc != SQLITE_OK)) { - error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host)); - return; - } + error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host)); + return; } - rc = sqlite3_bind_text(res, 1, rrdhost_hostname(host), -1, SQLITE_STATIC); + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind hostname parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind host_id for SQL_INSERT_HEALTH_LOG."); goto failed; } - rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->unique_id); + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->alarm_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind alarm_id parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) ae->alarm_id); + rc = sqlite3_bind_blob(res, 3, &ae->config_hash_id, sizeof(ae->config_hash_id), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind alarm_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) ae->alarm_event_id); + rc = sqlite3_bind_string_or_null(res, ae->name, 4); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind alarm_event_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind name parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_blob(res, 5, &ae->config_hash_id, sizeof(ae->config_hash_id), SQLITE_STATIC); + rc = sqlite3_bind_string_or_null(res, ae->chart, 5); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind chart parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->updated_by_id); + rc = sqlite3_bind_string_or_null(res, ae->family, 6); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind updated_by_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind family parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 7, (sqlite3_int64) ae->updates_id); + rc = sqlite3_bind_string_or_null(res, ae->exec, 7); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind updates_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind exec parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 8, (sqlite3_int64) ae->when); + rc = sqlite3_bind_string_or_null(res, ae->recipient, 8); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind when parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind recipient parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 9, (sqlite3_int64) ae->duration); + rc = sqlite3_bind_string_or_null(res, ae->units, 9); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind duration parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind host_id parameter to store node instance information"); goto failed; } - rc = sqlite3_bind_int64(res, 10, (sqlite3_int64) ae->non_clear_duration); + rc = sqlite3_bind_string_or_null(res, ae->chart_context, 10); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind non_clear_duration parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind chart_context parameter for SQL_INSERT_HEALTH_LOG"); goto failed; } - rc = sqlite3_bind_int64(res, 11, (sqlite3_int64) ae->flags); + rc = sqlite3_bind_blob(res, 11, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind flags parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind transition_id parameter for SQL_INSERT_HEALTH_LOG"); + goto failed; + } + + rc = sqlite3_step_monitored(res); + if (likely(rc == SQLITE_ROW)) + health_log_id = (size_t) sqlite3_column_int64(res, 0); + else { + error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc); goto failed; } - rc = sqlite3_bind_int64(res, 12, (sqlite3_int64) ae->exec_run_timestamp); + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("HEALTH [%s]: Failed to finalize the prepared statement for inserting to health log.", rrdhost_hostname(host)); + + rc = sqlite3_prepare_v2(db_meta, SQL_INSERT_HEALTH_LOG_DETAIL, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG_DETAIL", rrdhost_hostname(host)); + return; + } + + rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) health_log_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind exec_run_timestamp parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_int64(res, 13, (sqlite3_int64) ae->delay_up_to_timestamp); + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) ae->unique_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind delay_up_to_timestamp parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->name, 14); + rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) ae->alarm_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind name parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind unique_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->chart, 15); + rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) ae->alarm_event_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind chart parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind alarm_event_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->family, 16); + rc = sqlite3_bind_int64(res, 5, (sqlite3_int64) ae->updated_by_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind family parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind updated_by_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->exec, 17); + rc = sqlite3_bind_int64(res, 6, (sqlite3_int64) ae->updates_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind exec parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind updates_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->recipient, 18); + rc = sqlite3_bind_int64(res, 7, (sqlite3_int64) ae->when); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind recipient parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind when parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->source, 19); + rc = sqlite3_bind_int64(res, 8, (sqlite3_int64) ae->duration); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind source parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind duration parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->units, 20); + rc = sqlite3_bind_int64(res, 9, (sqlite3_int64) ae->non_clear_duration); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind host_id parameter to store node instance information"); + error_report("Failed to bind non_clear_duration parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->info, 21); + rc = sqlite3_bind_int64(res, 10, (sqlite3_int64) ae->flags); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind info parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind flags parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_int(res, 22, ae->exec_code); + rc = sqlite3_bind_int64(res, 11, (sqlite3_int64) ae->exec_run_timestamp); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind exec_code parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind exec_run_timestamp parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_int(res, 23, ae->new_status); + rc = sqlite3_bind_int64(res, 12, (sqlite3_int64) ae->delay_up_to_timestamp); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind new_status parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind delay_up_to_timestamp parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_int(res, 24, ae->old_status); + rc = sqlite3_bind_string_or_null(res, ae->info, 13); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind old_status parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind info parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_int(res, 25, ae->delay); + rc = sqlite3_bind_int(res, 14, ae->exec_code); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind delay parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind exec_code parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_double(res, 26, ae->new_value); + rc = sqlite3_bind_int(res, 15, ae->new_status); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind new_value parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind new_status parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_double(res, 27, ae->old_value); + rc = sqlite3_bind_int(res, 16, ae->old_status); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind old_value parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind old_status parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_int64(res, 28, (sqlite3_int64) ae->last_repeat); + rc = sqlite3_bind_int(res, 17, ae->delay); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind last_repeat parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind delay parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->classification, 29); + rc = sqlite3_bind_double(res, 18, ae->new_value); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind classification parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind new_value parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->component, 30); + rc = sqlite3_bind_double(res, 19, ae->old_value); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind component parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind old_value parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->type, 31); + rc = sqlite3_bind_int64(res, 20, (sqlite3_int64) ae->last_repeat); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind type parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind last_repeat parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_string_or_null(res, ae->chart_context, 32); + rc = sqlite3_bind_blob(res, 21, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind chart_context parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind transition_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } - rc = sqlite3_bind_blob(res, 33, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC); + rc = sqlite3_bind_int64(res, 22, (sqlite3_int64) ae->global_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind transition_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind global_id parameter for SQL_INSERT_HEALTH_LOG_DETAIL"); goto failed; } rc = execute_insert(res); if (unlikely(rc != SQLITE_DONE)) { - error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc); + error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG_DETAIL, rc = %d", rrdhost_hostname(host), rc); goto failed; } @@ -363,7 +345,7 @@ void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) else { sql_health_alarm_log_insert(host, ae); #ifdef ENABLE_ACLK - if (netdata_cloud_setting) { + if (netdata_cloud_enabled) { sql_queue_alarm_to_aclk(host, ae, 0); } #endif @@ -373,11 +355,10 @@ void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) /* Health related SQL queries Get a count of rows from health log table */ -#define SQL_COUNT_HEALTH_LOG(guid) "SELECT count(1) FROM health_log_%s;", guid +#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;" void sql_health_alarm_log_count(RRDHOST *host) { sqlite3_stmt *res = NULL; int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; if (unlikely(!db_meta)) { if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) @@ -385,17 +366,19 @@ void sql_health_alarm_log_count(RRDHOST *host) { return; } - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COUNT_HEALTH_LOG(uuid_str)); - - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_prepare_v2(db_meta, SQL_COUNT_HEALTH_LOG_DETAIL, -1, &res, 0); if (unlikely(rc != SQLITE_OK)) { error_report("Failed to prepare statement to count health log entries from db"); return; } + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for SQL_COUNT_HEALTH_LOG."); + sqlite3_finalize(res); + return; + } + rc = sqlite3_step_monitored(res); if (likely(rc == SQLITE_ROW)) host->health.health_log_entries_written = (size_t) sqlite3_column_int64(res, 0); @@ -404,14 +387,14 @@ void sql_health_alarm_log_count(RRDHOST *host) { if (unlikely(rc != SQLITE_OK)) error_report("Failed to finalize the prepared statement to count health log entries from db"); - info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", rrdhost_hostname(host), uuid_str, (unsigned long int) host->health.health_log_entries_written); + netdata_log_info("HEALTH [%s]: Table health_log_detail contains %lu entries.", rrdhost_hostname(host), (unsigned long int) host->health.health_log_entries_written); } /* Health related SQL queries - Cleans up the health_log table on a non-claimed host + Cleans up the health_log_detail table on a non-claimed host */ -#define SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED(guid,limit) "DELETE FROM health_log_%s ORDER BY unique_id ASC LIMIT %lu;", guid, limit -void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every) { +#define SQL_CLEANUP_HEALTH_LOG_DETAIL_NOT_CLAIMED "DELETE FROM health_log_detail WHERE health_log_id IN (SELECT health_log_id FROM health_log WHERE host_id = ?1) AND when_key + ?2 < unixepoch() AND updated_by_id <> 0 AND transition_id NOT IN (SELECT last_transition_id FROM health_log hl WHERE hl.host_id = ?3);" +void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host) { sqlite3_stmt *res = NULL; int rc; char command[MAX_HEALTH_SQL_SIZE + 1]; @@ -425,23 +408,42 @@ void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every char uuid_str[UUID_STR_LEN]; uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - 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))); + rc = sqlite3_prepare_v2(db_meta, SQL_CLEANUP_HEALTH_LOG_DETAIL_NOT_CLAIMED, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to cleanup health log detail table (un-claimed)"); + return; + } + + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED."); + sqlite3_finalize(res); + return; + } - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64)host->health_log.health_log_history); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind health log history for SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED."); + sqlite3_finalize(res); + return; + } + + rc = sqlite3_bind_blob(res, 3, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to prepare statement to cleanup health log table"); + error_report("Failed to bind host_id for SQL_CLEANUP_HEALTH_LOG_NOT_CLAIMED."); + sqlite3_finalize(res); return; } rc = sqlite3_step_monitored(res); if (unlikely(rc != SQLITE_DONE)) - error_report("Failed to cleanup health log table, rc = %d", rc); + error_report("Failed to cleanup health log detail table, rc = %d", rc); rc = sqlite3_finalize(res); if (unlikely(rc != SQLITE_OK)) - error_report("Failed to finalize the prepared statement to cleanup health log table"); + error_report("Failed to finalize the prepared statement to cleanup health log detail table (un-claimed)"); - host->health.health_log_entries_written = rotate_every; + sql_health_alarm_log_count(host); snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str); if (unlikely(table_exists_in_database(command))) { @@ -450,10 +452,10 @@ void sql_health_alarm_log_cleanup_not_claimed(RRDHOST *host, size_t rotate_every } /* Health related SQL queries - Cleans up the health_log table on a claimed host + Cleans up the health_log_detail table on a claimed host */ -#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 -void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) { +#define SQL_CLEANUP_HEALTH_LOG_DETAIL_CLAIMED(guid) "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) AND when_key + ?3 < unixepoch() AND updated_by_id <> 0 AND transition_id NOT IN (SELECT last_transition_id FROM health_log hl WHERE hl.host_id = ?4);", guid +void sql_health_alarm_log_cleanup_claimed(RRDHOST *host) { sqlite3_stmt *res = NULL; int rc; char command[MAX_HEALTH_SQL_SIZE + 1]; @@ -469,70 +471,83 @@ void sql_health_alarm_log_cleanup_claimed(RRDHOST *host, size_t rotate_every) { snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str); if (!table_exists_in_database(command)) { - sql_health_alarm_log_cleanup_not_claimed(host, rotate_every); + sql_health_alarm_log_cleanup_not_claimed(host); return; } - 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))); + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG_DETAIL_CLAIMED(uuid_str)); rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to prepare statement to cleanup health log table"); + error_report("Failed to prepare statement to cleanup health log detail table (claimed)"); + return; + } + + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind first host_id for SQL_CLEANUP_HEALTH_LOG_CLAIMED."); + sqlite3_finalize(res); + return; + } + + rc = sqlite3_bind_blob(res, 2, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind second host_id for SQL_CLEANUP_HEALTH_LOG_CLAIMED."); + sqlite3_finalize(res); + return; + } + + rc = sqlite3_bind_int64(res, 3, (sqlite3_int64)host->health_log.health_log_history); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind health log history for SQL_CLEANUP_HEALTH_LOG_CLAIMED."); + sqlite3_finalize(res); + return; + } + + rc = sqlite3_bind_blob(res, 4, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind second host_id for SQL_CLEANUP_HEALTH_LOG_CLAIMED."); + sqlite3_finalize(res); return; } rc = sqlite3_step_monitored(res); if (unlikely(rc != SQLITE_DONE)) - error_report("Failed to cleanup health log table, rc = %d", rc); + error_report("Failed to cleanup health log detail table, rc = %d", rc); rc = sqlite3_finalize(res); if (unlikely(rc != SQLITE_OK)) - error_report("Failed to finalize the prepared statement to cleanup health log table"); + error_report("Failed to finalize the prepared statement to cleanup health log detail table (claimed)"); sql_health_alarm_log_count(host); sql_aclk_alert_clean_dead_entries(host); + } /* Health related SQL queries Cleans up the health_log table. */ void sql_health_alarm_log_cleanup(RRDHOST *host) { - static size_t rotate_every = 0; - - if(unlikely(rotate_every == 0)) { - rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000); - if(rotate_every < 100) rotate_every = 100; - } - - if(likely(host->health.health_log_entries_written < rotate_every)) { - return; - } - if (!claimed()) { - sql_health_alarm_log_cleanup_not_claimed(host, rotate_every); + sql_health_alarm_log_cleanup_not_claimed(host); } else - sql_health_alarm_log_cleanup_claimed(host, rotate_every); + sql_health_alarm_log_cleanup_claimed(host); } -#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, " \ -"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) " \ -"select hostname, ?1, ?2, ?3, config_hash_id, 0, ?4, unixepoch(), 0, 0, flags, exec_run_timestamp, " \ -"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 " \ -"from health_log_%s where unique_id = ?6", guid, guid2 -#define SQL_INJECT_REMOVED_UPDATE(guid) "update health_log_%s set flags = flags | ?1, updated_by_id = ?2 where unique_id = ?3; ", guid -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) +#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;" +#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;" +#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;" +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) { int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; if (!alarm_id || !alarm_event_id || !unique_id || !max_unique_id) return; sqlite3_stmt *res = NULL; - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED(uuid_str, uuid_str)); - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_prepare_v2(db_meta, SQL_INJECT_REMOVED, -1, &res, 0); if (rc != SQLITE_OK) { error_report("Failed to prepare statement when trying to inject removed event"); return; @@ -566,7 +581,7 @@ void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm uuid_generate_random(transition_id); rc = sqlite3_bind_blob(res, 5, &transition_id, sizeof(transition_id), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind config_hash_id parameter for SQL_INSERT_HEALTH_LOG"); + error_report("Failed to bind config_hash_id parameter for SQL_INJECT_REMOVED"); goto failed; } @@ -576,6 +591,12 @@ void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm goto failed; } + rc = sqlite3_bind_blob(res, 7, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED."); + goto failed; + } + rc = execute_insert(res); if (unlikely(rc != SQLITE_DONE)) { error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED, rc = %d", rc); @@ -585,35 +606,77 @@ void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm if (unlikely(sqlite3_finalize(res) != SQLITE_OK)) error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event."); - //update the old entry - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED_UPDATE(uuid_str)); - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + //update the old entry in health_log_detail + rc = sqlite3_prepare_v2(db_meta, SQL_INJECT_REMOVED_UPDATE_DETAIL, -1, &res, 0); if (rc != SQLITE_OK) { - error_report("Failed to prepare statement when trying to update during inject removed event"); + error_report("Failed to prepare statement when trying to update health_log_detail during inject removed event"); return; } rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) HEALTH_ENTRY_FLAG_UPDATED); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind flags parameter for SQL_INJECT_REMOVED (update)"); + error_report("Failed to bind flags parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL"); goto failed; } rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) max_unique_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED (update)"); + error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL"); goto failed; } rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) unique_id); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED (update)"); + error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL"); + goto failed; + } + + rc = sqlite3_bind_blob(res, 4, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL"); + goto failed; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE_DETAIL, rc = %d", rc); + goto failed; + } + + //update the health_log_table + rc = sqlite3_prepare_v2(db_meta, SQL_INJECT_REMOVED_UPDATE_LOG, -1, &res, 0); + if (rc != SQLITE_OK) { + error_report("Failed to prepare statement when trying to update health_log during inject removed event"); + return; + } + + rc = sqlite3_bind_blob(res, 1, &transition_id, sizeof(transition_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_LOG"); + goto failed; + } + + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) alarm_id); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL"); + goto failed; + } + + rc = sqlite3_bind_blob(res, 3, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_LOG"); + goto failed; + } + + rc = sqlite3_bind_blob(res, 4, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_INJECT_REMOVED_UPDATE_DETAIL"); goto failed; } rc = execute_insert(res); if (unlikely(rc != SQLITE_DONE)) { - error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE, rc = %d", rc); + error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE_DETAIL, rc = %d", rc); goto failed; } @@ -622,22 +685,27 @@ failed: error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event."); } -#define SQL_SELECT_MAX_UNIQUE_ID(guid) "SELECT MAX(unique_id) from health_log_%s", guid -uint32_t sql_get_max_unique_id (char *uuid_str) +#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" +uint32_t sql_get_max_unique_id (RRDHOST *host) { int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; uint32_t max_unique_id = 0; sqlite3_stmt *res = NULL; - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_MAX_UNIQUE_ID(uuid_str)); - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_prepare_v2(db_meta, SQL_SELECT_MAX_UNIQUE_ID, -1, &res, 0); if (rc != SQLITE_OK) { error_report("Failed to prepare statement when trying to get max unique id"); return 0; } + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_SELECT_MAX_UNIQUE_ID."); + sqlite3_finalize(res); + return 0; + } + while (sqlite3_step_monitored(res) == SQLITE_ROW) { max_unique_id = (uint32_t) sqlite3_column_int64(res, 0); } @@ -649,36 +717,42 @@ uint32_t sql_get_max_unique_id (char *uuid_str) return max_unique_id; } -#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 -void sql_check_removed_alerts_state(char *uuid_str) +#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;" +void sql_check_removed_alerts_state(RRDHOST *host) { int rc; - char command[MAX_HEALTH_SQL_SIZE + 1]; uint32_t max_unique_id = 0; - sqlite3_stmt *res = NULL; + uuid_t transition_id; - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_LAST_STATUSES(uuid_str)); - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + rc = sqlite3_prepare_v2(db_meta, SQL_SELECT_LAST_STATUSES, -1, &res, 0); if (rc != SQLITE_OK) { error_report("Failed to prepare statement when trying to check removed statuses"); return; } - while (sqlite3_step_monitored(res) == SQLITE_ROW) { - uint32_t alarm_id, alarm_event_id, unique_id; - RRDCALC_STATUS status; - - status = (RRDCALC_STATUS) sqlite3_column_int(res, 0); - unique_id = (uint32_t) sqlite3_column_int64(res, 1); - alarm_id = (uint32_t) sqlite3_column_int64(res, 2); - alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3); - if (unlikely(status != RRDCALC_STATUS_REMOVED)) { - if (unlikely(!max_unique_id)) - max_unique_id = sql_get_max_unique_id (uuid_str); - sql_inject_removed_status (uuid_str, alarm_id, alarm_event_id, unique_id, ++max_unique_id); - } - } + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_SELECT_LAST_STATUSES."); + sqlite3_finalize(res); + return; + } + + while (sqlite3_step_monitored(res) == SQLITE_ROW) { + uint32_t alarm_id, alarm_event_id, unique_id; + RRDCALC_STATUS status; + + status = (RRDCALC_STATUS) sqlite3_column_int(res, 0); + unique_id = (uint32_t) sqlite3_column_int64(res, 1); + alarm_id = (uint32_t) sqlite3_column_int64(res, 2); + alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3); + uuid_copy(transition_id, *((uuid_t *) sqlite3_column_blob(res, 4))); + if (unlikely(status != RRDCALC_STATUS_REMOVED)) { + if (unlikely(!max_unique_id)) + max_unique_id = sql_get_max_unique_id (host); + sql_inject_removed_status (host, alarm_id, alarm_event_id, unique_id, ++max_unique_id, &transition_id); + } + } rc = sqlite3_finalize(res); if (unlikely(rc != SQLITE_OK)) @@ -688,12 +762,17 @@ void sql_check_removed_alerts_state(char *uuid_str) /* Health related SQL queries Load from the health log table */ -#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 +#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, hld.global_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;" void sql_health_alarm_log_load(RRDHOST *host) { sqlite3_stmt *res = NULL; int ret; ssize_t errored = 0, loaded = 0; - char command[MAX_HEALTH_SQL_SIZE + 1]; host->health.health_log_entries_written = 0; @@ -703,19 +782,21 @@ void sql_health_alarm_log_load(RRDHOST *host) { return; } - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - - sql_check_removed_alerts_state(uuid_str); + sql_check_removed_alerts_state(host); - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str)); - - ret = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + ret = sqlite3_prepare_v2(db_meta, SQL_LOAD_HEALTH_LOG, -1, &res, 0); if (unlikely(ret != SQLITE_OK)) { error_report("HEALTH [%s]: Failed to prepare sql statement to load health log.", rrdhost_hostname(host)); return; } + ret = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(ret != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_LOAD_HEALTH_LOG."); + sqlite3_finalize(res); + return; + } + DICTIONARY *all_rrdcalcs = dictionary_create( DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE); RRDCALC *rc; @@ -724,20 +805,20 @@ void sql_health_alarm_log_load(RRDHOST *host) { } foreach_rrdcalc_in_rrdhost_done(rc); - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock); + rw_spinlock_read_lock(&host->health_log.spinlock); while (sqlite3_step_monitored(res) == SQLITE_ROW) { ALARM_ENTRY *ae = NULL; // check that we have valid ids - uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 1); + uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 0); if(!unique_id) { error_report("HEALTH [%s]: Got invalid unique id. Ignoring it.", rrdhost_hostname(host)); errored++; continue; } - uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 2); + uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 1); if(!alarm_id) { error_report("HEALTH [%s]: Got invalid alarm id. Ignoring it.", rrdhost_hostname(host)); errored++; @@ -745,28 +826,28 @@ void sql_health_alarm_log_load(RRDHOST *host) { } //need name, chart and family - if (sqlite3_column_type(res, 13) == SQLITE_NULL) { + if (sqlite3_column_type(res, 12) == SQLITE_NULL) { error_report("HEALTH [%s]: Got null name field. Ignoring it.", rrdhost_hostname(host)); errored++; continue; } - if (sqlite3_column_type(res, 14) == SQLITE_NULL) { + if (sqlite3_column_type(res, 13) == SQLITE_NULL) { error_report("HEALTH [%s]: Got null chart field. Ignoring it.", rrdhost_hostname(host)); errored++; continue; } - if (sqlite3_column_type(res, 15) == SQLITE_NULL) { + if (sqlite3_column_type(res, 14) == SQLITE_NULL) { error_report("HEALTH [%s]: Got null family field. Ignoring it.", rrdhost_hostname(host)); errored++; continue; } // Check if we got last_repeat field - time_t last_repeat = (time_t)sqlite3_column_int64(res, 27); + time_t last_repeat = (time_t)sqlite3_column_int64(res, 26); - rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 14)); + rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 13)); if(unlikely(rc)) { if (rrdcalc_isrepeating(rc)) { rc->last_repeat = last_repeat; @@ -782,84 +863,87 @@ void sql_health_alarm_log_load(RRDHOST *host) { ae->unique_id = unique_id; ae->alarm_id = alarm_id; - if (sqlite3_column_type(res, 4) != SQLITE_NULL) - uuid_copy(ae->config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 4))); + if (sqlite3_column_type(res, 3) != SQLITE_NULL) + uuid_copy(ae->config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 3))); - ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3); - ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 5); - ae->updates_id = (uint32_t) sqlite3_column_int64(res, 6); + ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 2); + ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 4); + ae->updates_id = (uint32_t) sqlite3_column_int64(res, 5); - ae->when = (time_t) sqlite3_column_int64(res, 7); - ae->duration = (time_t) sqlite3_column_int64(res, 8); - ae->non_clear_duration = (time_t) sqlite3_column_int64(res, 9); + ae->when = (time_t) sqlite3_column_int64(res, 6); + ae->duration = (time_t) sqlite3_column_int64(res, 7); + ae->non_clear_duration = (time_t) sqlite3_column_int64(res, 8); - ae->flags = (uint32_t) sqlite3_column_int64(res, 10); + ae->flags = (uint32_t) sqlite3_column_int64(res, 9); ae->flags |= HEALTH_ENTRY_FLAG_SAVED; - ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 11); - ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 12); + ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 10); + ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 11); - ae->name = string_strdupz((char *) sqlite3_column_text(res, 13)); - ae->chart = string_strdupz((char *) sqlite3_column_text(res, 14)); - ae->family = string_strdupz((char *) sqlite3_column_text(res, 15)); + ae->name = string_strdupz((char *) sqlite3_column_text(res, 12)); + ae->chart = string_strdupz((char *) sqlite3_column_text(res, 13)); + ae->family = string_strdupz((char *) sqlite3_column_text(res, 14)); - if (sqlite3_column_type(res, 16) != SQLITE_NULL) - ae->exec = string_strdupz((char *) sqlite3_column_text(res, 16)); + if (sqlite3_column_type(res, 15) != SQLITE_NULL) + ae->exec = string_strdupz((char *) sqlite3_column_text(res, 15)); else ae->exec = NULL; - if (sqlite3_column_type(res, 17) != SQLITE_NULL) - ae->recipient = string_strdupz((char *) sqlite3_column_text(res, 17)); + if (sqlite3_column_type(res, 16) != SQLITE_NULL) + ae->recipient = string_strdupz((char *) sqlite3_column_text(res, 16)); else ae->recipient = NULL; - if (sqlite3_column_type(res, 18) != SQLITE_NULL) - ae->source = string_strdupz((char *) sqlite3_column_text(res, 18)); + if (sqlite3_column_type(res, 17) != SQLITE_NULL) + ae->source = string_strdupz((char *) sqlite3_column_text(res, 17)); else ae->source = NULL; - if (sqlite3_column_type(res, 19) != SQLITE_NULL) - ae->units = string_strdupz((char *) sqlite3_column_text(res, 19)); + if (sqlite3_column_type(res, 18) != SQLITE_NULL) + ae->units = string_strdupz((char *) sqlite3_column_text(res, 18)); else ae->units = NULL; - if (sqlite3_column_type(res, 20) != SQLITE_NULL) - ae->info = string_strdupz((char *) sqlite3_column_text(res, 20)); + if (sqlite3_column_type(res, 19) != SQLITE_NULL) + ae->info = string_strdupz((char *) sqlite3_column_text(res, 19)); else ae->info = NULL; - ae->exec_code = (int) sqlite3_column_int(res, 21); - ae->new_status = (RRDCALC_STATUS) sqlite3_column_int(res, 22); - ae->old_status = (RRDCALC_STATUS)sqlite3_column_int(res, 23); - ae->delay = (int) sqlite3_column_int(res, 24); + ae->exec_code = (int) sqlite3_column_int(res, 20); + ae->new_status = (RRDCALC_STATUS) sqlite3_column_int(res, 21); + ae->old_status = (RRDCALC_STATUS)sqlite3_column_int(res, 22); + ae->delay = (int) sqlite3_column_int(res, 23); - ae->new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 25); - ae->old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 26); + ae->new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 24); + ae->old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 25); ae->last_repeat = last_repeat; - if (sqlite3_column_type(res, 28) != SQLITE_NULL) - ae->classification = string_strdupz((char *) sqlite3_column_text(res, 28)); + if (sqlite3_column_type(res, 27) != SQLITE_NULL) + ae->classification = string_strdupz((char *) sqlite3_column_text(res, 27)); else ae->classification = NULL; - if (sqlite3_column_type(res, 29) != SQLITE_NULL) - ae->component = string_strdupz((char *) sqlite3_column_text(res, 29)); + if (sqlite3_column_type(res, 28) != SQLITE_NULL) + ae->component = string_strdupz((char *) sqlite3_column_text(res, 28)); else ae->component = NULL; - if (sqlite3_column_type(res, 30) != SQLITE_NULL) - ae->type = string_strdupz((char *) sqlite3_column_text(res, 30)); + if (sqlite3_column_type(res, 29) != SQLITE_NULL) + ae->type = string_strdupz((char *) sqlite3_column_text(res, 29)); else ae->type = NULL; - if (sqlite3_column_type(res, 31) != SQLITE_NULL) - ae->chart_context = string_strdupz((char *) sqlite3_column_text(res, 31)); + if (sqlite3_column_type(res, 30) != SQLITE_NULL) + ae->chart_context = string_strdupz((char *) sqlite3_column_text(res, 30)); else ae->chart_context = NULL; - if (sqlite3_column_type(res, 32) != SQLITE_NULL) - uuid_copy(ae->transition_id, *((uuid_t *) sqlite3_column_blob(res, 32))); + if (sqlite3_column_type(res, 31) != SQLITE_NULL) + uuid_copy(ae->transition_id, *((uuid_t *)sqlite3_column_blob(res, 31))); + + if (sqlite3_column_type(res, 32) != SQLITE_NULL) + ae->global_id = sqlite3_column_int64(res, 32); char value_string[100 + 1]; string_freez(ae->old_value_string); @@ -879,7 +963,7 @@ void sql_health_alarm_log_load(RRDHOST *host) { loaded++; } - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock); + rw_spinlock_read_unlock(&host->health_log.spinlock); dictionary_destroy(all_rrdcalcs); all_rrdcalcs = NULL; @@ -891,7 +975,7 @@ void sql_health_alarm_log_load(RRDHOST *host) { if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id)) host->health_log.next_alarm_id = host->health_max_alarm_id + 1; - log_health("[%s]: Table health_log_%s, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), uuid_str, loaded, errored); + netdata_log_health("[%s]: Table health_log, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), loaded, errored); ret = sqlite3_finalize(res); if (unlikely(ret != SQLITE_OK)) @@ -907,8 +991,8 @@ void sql_health_alarm_log_load(RRDHOST *host) { "on_key, class, component, type, os, hosts, lookup, every, units, calc, families, plugin, module, " \ "charts, green, red, warn, crit, exec, to_key, info, delay, options, repeat, host_labels, " \ "p_db_lookup_dimensions, p_db_lookup_method, p_db_lookup_options, p_db_lookup_after, " \ - "p_db_lookup_before, p_update_every) values (?1,unixepoch(),?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12," \ - "?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34);" + "p_db_lookup_before, p_update_every, source, chart_labels) values (?1,unixepoch(),?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12," \ + "?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34,?35,?36);" int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg) { @@ -1088,6 +1172,14 @@ int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg) if (unlikely(rc != SQLITE_OK)) goto bind_fail; + rc = sqlite3_bind_string_or_null(res, cfg->source, ++param); + if (unlikely(rc != SQLITE_OK)) + goto bind_fail; + + rc = sqlite3_bind_string_or_null(res, cfg->chart_labels, ++param); + if (unlikely(rc != SQLITE_OK)) + goto bind_fail; + rc = execute_insert(res); if (unlikely(rc != SQLITE_DONE)) error_report("Failed to store alert config, rc = %d", rc); @@ -1175,18 +1267,14 @@ int alert_hash_and_store_config( return 1; } -#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" +#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 & %u AND hl.host_id = @host_id and hl.health_log_id = hld.health_log_id ORDER BY hld.unique_id DESC LIMIT 1;" int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status) { int rc = 0, ret = -1; char command[MAX_HEALTH_SQL_SIZE + 1]; - - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - sqlite3_stmt *res = NULL; - 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); + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT, ae->alarm_id, ae->unique_id, (uint32_t) HEALTH_ENTRY_FLAG_EXEC_RUN); rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); if (rc != SQLITE_OK) { @@ -1194,6 +1282,13 @@ int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_S return ret; } + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT."); + sqlite3_finalize(res); + return ret; + } + ret = 0; while (sqlite3_step_monitored(res) == SQLITE_ROW) { *last_executed_status = (RRDCALC_STATUS) sqlite3_column_int(res, 0); @@ -1207,7 +1302,7 @@ int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_S return ret; } -#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 +#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 " void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart) { buffer_strcat(wb, "["); @@ -1219,26 +1314,23 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char * int rc; BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL); - char uuid_str[UUID_STR_LEN]; - uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - - buffer_sprintf(command, SQL_SELECT_HEALTH_LOG(uuid_str)); + buffer_sprintf(command, SQL_SELECT_HEALTH_LOG); if (chart) { char chart_sql[MAX_HEALTH_SQL_SIZE + 1]; - snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND chart = '%s' ", chart); + snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND hl.chart = '%s' ", chart); buffer_strcat(command, chart_sql); } if (after) { char after_sql[MAX_HEALTH_SQL_SIZE + 1]; - snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND unique_id > %u ", after); + snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND hld.unique_id > %u ", after); buffer_strcat(command, after_sql); } { char limit_sql[MAX_HEALTH_SQL_SIZE + 1]; - snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY unique_id DESC LIMIT %u ", max); + snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY hld.unique_id DESC LIMIT %u ", max); buffer_strcat(command, limit_sql); } @@ -1249,19 +1341,27 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char * return; } + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id for SQL_SELECT_HEALTH_LOG."); + sqlite3_finalize(res); + buffer_free(command); + return; + } + while (sqlite3_step(res) == SQLITE_ROW) { char old_value_string[100 + 1]; char new_value_string[100 + 1]; char config_hash_id[UUID_STR_LEN]; - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 4)), config_hash_id); + uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 3)), config_hash_id); char transition_id[UUID_STR_LEN] = {0}; - if (sqlite3_column_type(res, 32) != SQLITE_NULL) - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 32)), transition_id); + if (sqlite3_column_type(res, 31) != SQLITE_NULL) + uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 31)), transition_id); - char *edit_command = health_edit_command_from_source((char *)sqlite3_column_text(res, 18)); + char *edit_command = sqlite3_column_bytes(res, 17) > 0 ? health_edit_command_from_source((char *)sqlite3_column_text(res, 17)) : strdupz("UNKNOWN=0=UNKNOWN"); if (count) buffer_sprintf(wb, ","); @@ -1309,63 +1409,63 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char * "\t\t\"old_value_string\": \"%s\",\n" "\t\t\"last_repeat\": \"%lu\",\n" "\t\t\"silenced\": \"%s\",\n", - sqlite3_column_text(res, 0), + rrdhost_hostname(host), host->utc_offset, rrdhost_abbrev_timezone(host), + (unsigned int) sqlite3_column_int64(res, 0), (unsigned int) sqlite3_column_int64(res, 1), (unsigned int) sqlite3_column_int64(res, 2), - (unsigned int) sqlite3_column_int64(res, 3), config_hash_id, transition_id, + sqlite3_column_text(res, 12), sqlite3_column_text(res, 13), + sqlite3_column_text(res, 30), sqlite3_column_text(res, 14), - sqlite3_column_text(res, 31), - sqlite3_column_text(res, 15), + sqlite3_column_text(res, 27) ? (const char *) sqlite3_column_text(res, 27) : (char *) "Unknown", sqlite3_column_text(res, 28) ? (const char *) sqlite3_column_text(res, 28) : (char *) "Unknown", sqlite3_column_text(res, 29) ? (const char *) sqlite3_column_text(res, 29) : (char *) "Unknown", - sqlite3_column_text(res, 30) ? (const char *) sqlite3_column_text(res, 30) : (char *) "Unknown", - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false", - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false", - (long unsigned int)sqlite3_column_int64(res, 11), - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false", - sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : string2str(host->health.health_default_exec), - sqlite3_column_text(res, 17) ? (const char *) sqlite3_column_text(res, 17) : string2str(host->health.health_default_recipient), - sqlite3_column_int(res, 21), - sqlite3_column_text(res, 18), + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false", + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false", + (long unsigned int)sqlite3_column_int64(res, 10), + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false", + sqlite3_column_text(res, 15) ? (const char *) sqlite3_column_text(res, 15) : string2str(host->health.health_default_exec), + sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : string2str(host->health.health_default_recipient), + sqlite3_column_int(res, 20), + sqlite3_column_text(res, 17) ? (const char *) sqlite3_column_text(res, 17) : (char *) "Unknown", edit_command, - sqlite3_column_text(res, 19), + sqlite3_column_text(res, 18), + (long unsigned int)sqlite3_column_int64(res, 6), (long unsigned int)sqlite3_column_int64(res, 7), (long unsigned int)sqlite3_column_int64(res, 8), - (long unsigned int)sqlite3_column_int64(res, 9), + rrdcalc_status2string(sqlite3_column_int(res, 21)), rrdcalc_status2string(sqlite3_column_int(res, 22)), - rrdcalc_status2string(sqlite3_column_int(res, 23)), - sqlite3_column_int(res, 24), - (long unsigned int)sqlite3_column_int64(res, 12), + sqlite3_column_int(res, 23), + (long unsigned int)sqlite3_column_int64(res, 11), + (unsigned int)sqlite3_column_int64(res, 4), (unsigned int)sqlite3_column_int64(res, 5), - (unsigned int)sqlite3_column_int64(res, 6), - 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), - 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), - (long unsigned int)sqlite3_column_int64(res, 27), - (sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false"); + 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), + 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), + (long unsigned int)sqlite3_column_int64(res, 26), + (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false"); - health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 20), ",\n"); + health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 19), ",\n"); - if(unlikely(sqlite3_column_int64(res, 10) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) { + if(unlikely(sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) { buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n"); } buffer_strcat(wb, "\t\t\"value\":"); - if (sqlite3_column_type(res, 25) == SQLITE_NULL) + if (sqlite3_column_type(res, 24) == SQLITE_NULL) buffer_strcat(wb, "null"); else - buffer_print_netdata_double(wb, sqlite3_column_double(res, 25)); + buffer_print_netdata_double(wb, sqlite3_column_double(res, 24)); buffer_strcat(wb, ",\n"); buffer_strcat(wb, "\t\t\"old_value\":"); - if (sqlite3_column_type(res, 26) == SQLITE_NULL) + if (sqlite3_column_type(res, 25) == SQLITE_NULL) buffer_strcat(wb, "null"); else - buffer_print_netdata_double(wb, sqlite3_column_double(res, 26)); + buffer_print_netdata_double(wb, sqlite3_column_double(res, 25)); buffer_strcat(wb, "\n"); buffer_strcat(wb, "\t}"); @@ -1381,3 +1481,609 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char * buffer_free(command); } + +#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 +#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 +#define SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID "update health_log_detail set transition_id = uuid_random() where transition_id is null;" +#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;" +#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;" +int health_migrate_old_health_log_table(char *table) { + if (!table) + return 0; + + //table should contain guid. We need to + //keep it in the new table along with it's data + //health_log_XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX + if (strnlen(table, 46) != 46) { + return 0; + } + + char *uuid_from_table = strdupz(table + 11); + uuid_t uuid; + if (uuid_parse_fix(uuid_from_table, uuid)) { + freez(uuid_from_table); + return 0; + } + + int rc; + char command[MAX_HEALTH_SQL_SIZE + 1]; + sqlite3_stmt *res = NULL; + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COPY_HEALTH_LOG(table)); + rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to copy health log, rc = %d", rc); + freez(uuid_from_table); + return 0; + } + + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to copy health log table, rc = %d", rc); + freez(uuid_from_table); + return 0; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to execute SQL_COPY_HEALTH_LOG, rc = %d", rc); + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to copy health log table, rc = %d", rc); + freez(uuid_from_table); + } + + //detail + snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COPY_HEALTH_LOG_DETAIL(table)); + rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to copy health log detail, rc = %d", rc); + return 0; + } + + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to copy health log detail, rc = %d", rc); + return 0; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to execute SQL_COPY_HEALTH_LOG_DETAIL, rc = %d", rc); + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to copy health log detail table, rc = %d", rc); + return 0; + } + + //update transition ids + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to update health log detail with transition ids, rc = %d", rc); + return 0; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID, rc = %d", rc); + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to update health log detail table with transition ids, rc = %d", rc); + return 0; + } + + //update health_log_id + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to update health log detail with health log ids, rc = %d", rc); + return 0; + } + + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to update health log detail with health log ids, rc = %d", rc); + return 0; + } + + rc = sqlite3_bind_blob(res, 2, &uuid, sizeof(uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to update health log detail with health log ids, rc = %d", rc); + return 0; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID, rc = %d", rc); + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to update health log detail table with health log ids, rc = %d", rc); + } + + //update last transition id + rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to update health log with last transition id, rc = %d", rc); + return 0; + } + + rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to update health log with last transition id, rc = %d", rc); + return 0; + } + + rc = execute_insert(res); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID, rc = %d", rc); + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to update health log table with last transition id, rc = %d", rc); + } + + return 1; +} + +#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 and config_hash_id = @config_hash_id" +#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" +uint32_t sql_get_alarm_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, uuid_t *config_hash_id) +{ + int rc = 0; + sqlite3_stmt *res = NULL; + uint32_t alarm_id = 0; + uint64_t health_log_id = 0; + + rc = sqlite3_prepare_v2(db_meta, SQL_GET_ALARM_ID, -1, &res, 0); + if (rc != SQLITE_OK) { + error_report("Failed to prepare statement when trying to get an alarm id"); + return alarm_id; + } + + rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_GET_ALARM_ID."); + sqlite3_finalize(res); + return alarm_id; + } + + rc = sqlite3_bind_string_or_null(res, chart, 2); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind char parameter for SQL_GET_ALARM_ID."); + sqlite3_finalize(res); + return alarm_id; + } + + rc = sqlite3_bind_string_or_null(res, name, 3); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind name parameter for SQL_GET_ALARM_ID."); + sqlite3_finalize(res); + return alarm_id; + } + + rc = sqlite3_bind_blob(res, 4, config_hash_id, sizeof(*config_hash_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind config_hash_id parameter for SQL_GET_ALARM_ID."); + sqlite3_finalize(res); + return alarm_id; + } + + while (sqlite3_step_monitored(res) == SQLITE_ROW) { + alarm_id = (uint32_t) sqlite3_column_int64(res, 0); + health_log_id = (uint64_t) sqlite3_column_int64(res, 1); + } + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize the statement while getting an alarm id."); + + if (alarm_id) { + rc = sqlite3_prepare_v2(db_meta, SQL_GET_EVENT_ID, -1, &res, 0); + if (rc != SQLITE_OK) { + error_report("Failed to prepare statement when trying to get an event id"); + return alarm_id; + } + + rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) health_log_id); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter for SQL_GET_EVENT_ID."); + sqlite3_finalize(res); + return alarm_id; + } + + rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) alarm_id); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind char parameter for SQL_GET_EVENT_ID."); + sqlite3_finalize(res); + return alarm_id; + } + + while (sqlite3_step_monitored(res) == SQLITE_ROW) { + *next_event_id = (uint32_t) sqlite3_column_int64(res, 0); + } + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize the statement while getting an alarm id."); + } + + return alarm_id; +} + +#define SQL_GET_ALARM_ID_FROM_TRANSITION_ID "SELECT hld.alarm_id, hl.host_id, hl.chart_context FROM " \ + "health_log_detail hld, health_log hl WHERE hld.transition_id = @transition_id " \ + "and hld.health_log_id = hl.health_log_id" + +bool sql_find_alert_transition(const char *transition, void (*cb)(const char *machine_guid, const char *context, time_t alert_id, void *data), void *data) +{ + static __thread sqlite3_stmt *res = NULL; + + char machine_guid[UUID_STR_LEN]; + + int rc; + uuid_t transition_uuid; + if (uuid_parse(transition, transition_uuid)) + return false; + + if (unlikely(!res)) { + rc = prepare_statement(db_meta, SQL_GET_ALARM_ID_FROM_TRANSITION_ID, &res); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement when trying to get transition id"); + return false; + } + } + + bool ok = false; + + rc = sqlite3_bind_blob(res, 1, &transition_uuid, sizeof(transition_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind transition"); + goto fail; + } + + while (sqlite3_step_monitored(res) == SQLITE_ROW) { + ok = true; + uuid_unparse_lower(*(uuid_t *) sqlite3_column_blob(res, 1), machine_guid); + cb(machine_guid, (const char *) sqlite3_column_text(res, 2), sqlite3_column_int(res, 0), data); + } + +fail: + rc = sqlite3_reset(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset the statement when trying to find transition"); + + return ok; +} + +#define SQL_BUILD_ALERT_TRANSITION "CREATE TEMP TABLE IF NOT EXISTS v_%p (host_id blob)" + +#define SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE "INSERT INTO v_%p (host_id) VALUES (@host_id)" + +#define SQL_SEARCH_ALERT_TRANSITION_SELECT "SELECT " \ + "h.host_id, h.alarm_id, h.config_hash_id, h.name, h.chart, h.family, h.recipient, h.units, h.exec, " \ + "h.chart_context, d.when_key, d.duration, d.non_clear_duration, d.flags, d.delay_up_to_timestamp, " \ + "d.info, d.exec_code, d.new_status, d.old_status, d.delay, d.new_value, d.old_value, d.last_repeat, " \ + "d.transition_id, d.global_id, ah.class, ah.type, ah.component, d.exec_run_timestamp" + +#define SQL_SEARCH_ALERT_TRANSITION_COMMON_WHERE \ + "h.config_hash_id = ah.hash_id AND h.health_log_id = d.health_log_id" + +#define SQL_SEARCH_ALERT_TRANSITION SQL_SEARCH_ALERT_TRANSITION_SELECT " FROM health_log h, health_log_detail d, v_%p t, alert_hash ah " \ + " WHERE h.host_id = t.host_id AND " SQL_SEARCH_ALERT_TRANSITION_COMMON_WHERE " AND ( d.new_status > 2 OR d.old_status > 2 ) AND d.global_id BETWEEN @after AND @before " + +#define SQL_SEARCH_ALERT_TRANSITION_DIRECT SQL_SEARCH_ALERT_TRANSITION_SELECT " FROM health_log h, health_log_detail d, alert_hash ah " \ + " WHERE " SQL_SEARCH_ALERT_TRANSITION_COMMON_WHERE " AND transition_id = @transition " + +void sql_alert_transitions( + DICTIONARY *nodes, + time_t after, + time_t before, + const char *context, + const char *alert_name, + const char *transition, + void (*cb)(struct sql_alert_transition_data *, void *), + void *data, + bool debug __maybe_unused) +{ + uuid_t transition_uuid; + char sql[512]; + int rc; + sqlite3_stmt *res = NULL; + BUFFER *command = NULL; + + if (unlikely(!nodes)) + return; + + if (transition) { + if (uuid_parse(transition, transition_uuid)) { + error_report("Invalid transition given %s", transition); + return; + } + + rc = sqlite3_prepare_v2(db_meta, SQL_SEARCH_ALERT_TRANSITION_DIRECT, -1, &res, 0); + + rc = sqlite3_bind_blob(res, 1, &transition_uuid, sizeof(transition_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind transition_id parameter"); + goto fail; + } + goto run_query; + } + + snprintfz(sql, 511, SQL_BUILD_ALERT_TRANSITION, nodes); + rc = db_execute(db_meta, sql); + if (rc) + return; + + snprintfz(sql, 511, SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE, nodes); + + // Prepare statement to add things + rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to INSERT into v_%p", nodes); + goto fail_only_drop; + } + + void *t; + dfe_start_read(nodes, t) { + uuid_t host_uuid; + uuid_parse( t_dfe.name, host_uuid); + + rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to bind host_id parameter."); + + rc = sqlite3_step_monitored(res); + if (rc != SQLITE_DONE) + error_report("Error while populating temp table"); + + rc = sqlite3_reset(res); + if (rc != SQLITE_OK) + error_report("Error while resetting parameters"); + } + dfe_done(t); + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) { + // log error but continue + error_report("Failed to finalize statement for sql_alert_transitions temp table population"); + } + + command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL); + + buffer_sprintf(command, SQL_SEARCH_ALERT_TRANSITION, nodes); + + if (context) + buffer_sprintf(command, " AND h.chart_context = @context"); + + if (alert_name) + buffer_sprintf(command, " AND h.name = @alert_name"); + + buffer_strcat(command, " ORDER BY d.global_id DESC"); + + rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement sql_alert_transitions"); + goto fail_only_drop; + } + + int param = 1; + rc = sqlite3_bind_int64(res, param++, (sqlite3_int64)(after * USEC_PER_SEC)); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind after parameter"); + goto fail; + } + + rc = sqlite3_bind_int64(res, param++, (sqlite3_int64)(before * USEC_PER_SEC)); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind before parameter"); + goto fail; + } + + if (context) { + rc = sqlite3_bind_text(res, param++, context, -1, SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind context parameter"); + goto fail; + } + } + + if (alert_name) { + rc = sqlite3_bind_text(res, param++, alert_name, -1, SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind alert_name parameter"); + goto fail; + } + } + +run_query:; + + struct sql_alert_transition_data atd = {0 }; + + while (sqlite3_step(res) == SQLITE_ROW) { + atd.host_id = (uuid_t *) sqlite3_column_blob(res, 0); + atd.alarm_id = sqlite3_column_int64(res, 1); + atd.config_hash_id = (uuid_t *)sqlite3_column_blob(res, 2); + atd.alert_name = (const char *) sqlite3_column_text(res, 3); + atd.chart = (const char *) sqlite3_column_text(res, 4); + atd.chart_name = (const char *) sqlite3_column_text(res, 4); // FIXME don't copy the id, find the name + atd.family = (const char *) sqlite3_column_text(res, 5); + atd.recipient = (const char *) sqlite3_column_text(res, 6); + atd.units = (const char *) sqlite3_column_text(res, 7); + atd.exec = (const char *) sqlite3_column_text(res, 8); + atd.chart_context = (const char *) sqlite3_column_text(res, 9); + atd.when_key = sqlite3_column_int64(res, 10); + atd.duration = sqlite3_column_int64(res, 11); + atd.non_clear_duration = sqlite3_column_int64(res, 12); + atd.flags = sqlite3_column_int64(res, 13); + atd.delay_up_to_timestamp = sqlite3_column_int64(res, 14); + atd.info = (const char *) sqlite3_column_text(res, 15); + atd.exec_code = sqlite3_column_int(res, 16); + atd.new_status = sqlite3_column_int(res, 17); + atd.old_status = sqlite3_column_int(res, 18); + atd.delay = (int) sqlite3_column_int(res, 19); + atd.new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 20); + atd.old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 21); + atd.last_repeat = sqlite3_column_int64(res, 22); + atd.transition_id = (uuid_t *) sqlite3_column_blob(res, 23); + atd.global_id = sqlite3_column_int64(res, 24); + atd.classification = (const char *) sqlite3_column_text(res, 25); + atd.type = (const char *) sqlite3_column_text(res, 26); + atd.component = (const char *) sqlite3_column_text(res, 27); + atd.exec_run_timestamp = sqlite3_column_int64(res, 28); + + cb(&atd, data); + } + +fail: + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize statement for sql_alert_transitions"); + +fail_only_drop: + if (likely(!transition)) { + (void)snprintfz(sql, 511, "DROP TABLE IF EXISTS v_%p", nodes); + (void)db_execute(db_meta, sql); + buffer_free(command); + } +} + +#define SQL_BUILD_CONFIG_TARGET_LIST "CREATE TEMP TABLE IF NOT EXISTS c_%p (hash_id blob)" + +#define SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE "INSERT INTO c_%p (hash_id) VALUES (@hash_id)" + +#define SQL_SEARCH_CONFIG_LIST "SELECT ah.hash_id, alarm, template, on_key, class, component, type, os, hosts, lookup, every, " \ + " units, calc, families, plugin, module, charts, green, red, warn, crit, " \ + " exec, to_key, info, delay, options, repeat, host_labels, p_db_lookup_dimensions, p_db_lookup_method, " \ + " p_db_lookup_options, p_db_lookup_after, p_db_lookup_before, p_update_every, source, chart_labels " \ + " FROM alert_hash ah, c_%p t where ah.hash_id = t.hash_id" + +int sql_get_alert_configuration( + DICTIONARY *configs, + void (*cb)(struct sql_alert_config_data *, void *), + void *data, + bool debug __maybe_unused) +{ + int added = -1; + char sql[512]; + int rc; + sqlite3_stmt *res = NULL; + BUFFER *command = NULL; + + if (unlikely(!configs)) + return added; + + snprintfz(sql, 511, SQL_BUILD_CONFIG_TARGET_LIST, configs); + rc = db_execute(db_meta, sql); + if (rc) + return added; + + snprintfz(sql, 511, SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE, configs); + + // Prepare statement to add things + rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to INSERT into c_%p", configs); + goto fail_only_drop; + } + + void *t; + dfe_start_read(configs, t) { + uuid_t hash_id; + uuid_parse( t_dfe.name, hash_id); + + rc = sqlite3_bind_blob(res, 1, &hash_id, sizeof(hash_id), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to bind host_id parameter."); + + rc = sqlite3_step_monitored(res); + if (rc != SQLITE_DONE) + error_report("Error while populating temp table"); + + rc = sqlite3_reset(res); + if (rc != SQLITE_OK) + error_report("Error while resetting parameters"); + } + dfe_done(t); + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) { + // log error but continue + error_report("Failed to finalize statement for sql_get_alert_configuration temp table population"); + } + + command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL); + + buffer_sprintf(command, SQL_SEARCH_CONFIG_LIST, configs); + + rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement sql_get_alert_configuration"); + goto fail_only_drop; + } + + struct sql_alert_config_data acd = {0 }; + + added = 0; + int param; + while (sqlite3_step(res) == SQLITE_ROW) { + param = 0; + acd.config_hash_id = (uuid_t *) sqlite3_column_blob(res, param++); + acd.name = (const char *) sqlite3_column_text(res, param++); + acd.selectors.on_template = (const char *) sqlite3_column_text(res, param++); + acd.selectors.on_key = (const char *) sqlite3_column_text(res, param++); + acd.classification = (const char *) sqlite3_column_text(res, param++); + acd.component = (const char *) sqlite3_column_text(res, param++); + acd.type = (const char *) sqlite3_column_text(res, param++); + acd.selectors.os = (const char *) sqlite3_column_text(res, param++); + acd.selectors.hosts = (const char *) sqlite3_column_text(res, param++); + acd.value.db.lookup = (const char *) sqlite3_column_text(res, param++); + acd.value.every = (const char *) sqlite3_column_text(res, param++); + acd.value.units = (const char *) sqlite3_column_text(res, param++); + acd.value.calc = (const char *) sqlite3_column_text(res, param++); + acd.selectors.families = (const char *) sqlite3_column_text(res, param++); + acd.selectors.plugin = (const char *) sqlite3_column_text(res, param++); + acd.selectors.module = (const char *) sqlite3_column_text(res, param++); + acd.selectors.charts = (const char *) sqlite3_column_text(res, param++); + acd.status.green = (const char *) sqlite3_column_text(res, param++); + acd.status.red = (const char *) sqlite3_column_text(res, param++); + acd.status.warn = (const char *) sqlite3_column_text(res, param++); + acd.status.crit = (const char *) sqlite3_column_text(res, param++); + acd.notification.exec = (const char *) sqlite3_column_text(res, param++); + acd.notification.to_key = (const char *) sqlite3_column_text(res, param++); + acd.info = (const char *) sqlite3_column_text(res, param++); + acd.notification.delay = (const char *) sqlite3_column_text(res, param++); + acd.notification.options = (const char *) sqlite3_column_text(res, param++); + acd.notification.repeat = (const char *) sqlite3_column_text(res, param++); + acd.selectors.host_labels = (const char *) sqlite3_column_text(res, param++); + acd.value.db.dimensions = (const char *) sqlite3_column_text(res, param++); + acd.value.db.method = (const char *) sqlite3_column_text(res, param++); + acd.value.db.options = (uint32_t) sqlite3_column_int(res, param++); + acd.value.db.after = (int32_t) sqlite3_column_int(res, param++); + acd.value.db.before = (int32_t) sqlite3_column_int(res, param++); + acd.value.update_every = (int32_t) sqlite3_column_int(res, param++); + acd.source = (const char *) sqlite3_column_text(res, param++); + acd.selectors.chart_labels = (const char *) sqlite3_column_text(res, param++); + + cb(&acd, data); + added++; + } + + rc = sqlite3_finalize(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to finalize statement for sql_get_alert_configuration"); + +fail_only_drop: + (void)snprintfz(sql, 511, "DROP TABLE IF EXISTS c_%p", configs); + (void)db_execute(db_meta, sql); + buffer_free(command); + return added; +} + diff --git a/database/sqlite/sqlite_health.h b/database/sqlite/sqlite_health.h index 96d090b54..55e523d2f 100644 --- a/database/sqlite/sqlite_health.h +++ b/database/sqlite/sqlite_health.h @@ -5,9 +5,10 @@ #include "../../daemon/common.h" #include "sqlite3.h" +struct sql_alert_transition_data; +struct sql_alert_config_data; extern sqlite3 *db_meta; void sql_health_alarm_log_load(RRDHOST *host); -int sql_create_health_log_table(RRDHOST *host); void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae); void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae); void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae); @@ -16,4 +17,24 @@ int alert_hash_and_store_config(uuid_t hash_id, struct alert_config *cfg, int st void sql_aclk_alert_clean_dead_entries(RRDHOST *host); int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status); void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart); +int health_migrate_old_health_log_table(char *table); +uint32_t sql_get_alarm_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, uuid_t *config_hash_id); +void sql_alert_transitions( + DICTIONARY *nodes, + time_t after, + time_t before, + const char *context, + const char *alert_name, + const char *transition, + void (*cb)(struct sql_alert_transition_data *, void *), + void *data, + bool debug); + +int sql_get_alert_configuration( + DICTIONARY *configs, + void (*cb)(struct sql_alert_config_data *, void *), + void *data, + bool debug __maybe_unused); + +bool sql_find_alert_transition(const char *transition, void (*cb)(const char *machine_guid, const char *context, time_t alert_id, void *data), void *data); #endif //NETDATA_SQLITE_HEALTH_H diff --git a/database/sqlite/sqlite_metadata.c b/database/sqlite/sqlite_metadata.c index 607d789a5..697772bf5 100644 --- a/database/sqlite/sqlite_metadata.c +++ b/database/sqlite/sqlite_metadata.c @@ -37,8 +37,8 @@ #define SELECT_DIMENSION_LIST "SELECT dim_id, rowid FROM dimension WHERE rowid > @row_id" -#define STORE_HOST_INFO "INSERT OR REPLACE INTO host_info (host_id, system_key, system_value, date_created) VALUES " -#define STORE_HOST_INFO_VALUES "(u2h('%s'), '%s','%s', unixepoch())" +#define SQL_STORE_HOST_SYSTEM_INFO_VALUES "INSERT OR REPLACE INTO host_info (host_id, system_key, system_value, date_created) VALUES " \ + "(@uuid, @name, @value, unixepoch())" #define MIGRATE_LOCALHOST_TO_NEW_MACHINE_GUID \ "UPDATE chart SET host_id = @host_id WHERE host_id in (SELECT host_id FROM host where host_id <> @host_id and hops = 0);" @@ -378,59 +378,90 @@ bind_fail: return 1; } -static void add_host_sysinfo_key_value(const char *name, const char *value, void *data) +static int add_host_sysinfo_key_value(const char *name, const char *value, uuid_t *uuid) { - struct query_build *lb = data; + static __thread sqlite3_stmt *res = NULL; + int rc, param = 0; - if (unlikely(!value)) - return; + if (unlikely(!db_meta)) { + if (default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE) + return 0; + error_report("Database has not been initialized"); + return 0; + } - if (unlikely(!lb->count)) - buffer_sprintf( - lb->sql, STORE_HOST_INFO); - else - buffer_strcat(lb->sql, ", "); - buffer_sprintf(lb->sql, STORE_HOST_INFO_VALUES, lb->uuid_str, name, value); - lb->count++; + if (unlikely((!res))) { + rc = prepare_statement(db_meta, SQL_STORE_HOST_SYSTEM_INFO_VALUES, &res); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to store host info values, rc = %d", rc); + return 0; + } + } + + rc = sqlite3_bind_blob(res, ++param, uuid, sizeof(*uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) + goto bind_fail; + + rc = bind_text_null(res, ++param, name, 0); + if (unlikely(rc != SQLITE_OK)) + goto bind_fail; + + rc = bind_text_null(res, ++param, value ? value : "unknown", 0); + if (unlikely(rc != SQLITE_OK)) + goto bind_fail; + + int store_rc = sqlite3_step_monitored(res); + if (unlikely(store_rc != SQLITE_DONE)) + error_report("Failed to store host info value %s, rc = %d", name, rc); + + rc = sqlite3_reset(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to store host info value %s, rc = %d", name, rc); + + return store_rc == SQLITE_DONE; +bind_fail: + error_report("Failed to bind %d parameter to store host info values %s, rc = %d", param, name, rc); + rc = sqlite3_reset(res); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement to store host info values %s, rc = %d", name, rc); + return 0; } -static bool build_host_system_info_statements(RRDHOST *host, BUFFER *work_buffer) +static bool store_host_systeminfo(RRDHOST *host) { struct rrdhost_system_info *system_info = host->system_info; if (unlikely(!system_info)) return false; - buffer_flush(work_buffer); - struct query_build key_data = {.sql = work_buffer, .count = 0}; - uuid_unparse_lower(host->host_uuid, key_data.uuid_str); - - add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_NAME", system_info->container_os_name, &key_data); - add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_ID", system_info->container_os_id, &key_data); - add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_ID_LIKE", system_info->container_os_id_like, &key_data); - add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_VERSION", system_info->container_os_version, &key_data); - add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_VERSION_ID", system_info->container_os_version_id, &key_data); - add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_DETECTION", system_info->host_os_detection, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_OS_NAME", system_info->host_os_name, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_OS_ID", system_info->host_os_id, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_OS_ID_LIKE", system_info->host_os_id_like, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_OS_VERSION", system_info->host_os_version, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_OS_VERSION_ID", system_info->host_os_version_id, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_OS_DETECTION", system_info->host_os_detection, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_KERNEL_NAME", system_info->kernel_name, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_CPU_LOGICAL_CPU_COUNT", system_info->host_cores, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_CPU_FREQ", system_info->host_cpu_freq, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_TOTAL_RAM", system_info->host_ram_total, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_TOTAL_DISK_SIZE", system_info->host_disk_space, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_KERNEL_VERSION", system_info->kernel_version, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_ARCHITECTURE", system_info->architecture, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_VIRTUALIZATION", system_info->virtualization, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_VIRT_DETECTION", system_info->virt_detection, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_CONTAINER", system_info->container, &key_data); - add_host_sysinfo_key_value("NETDATA_SYSTEM_CONTAINER_DETECTION", system_info->container_detection, &key_data); - add_host_sysinfo_key_value("NETDATA_HOST_IS_K8S_NODE", system_info->is_k8s_node, &key_data); - - return true; + int ret = 0; + + ret += add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_NAME", system_info->container_os_name, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_ID", system_info->container_os_id, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_ID_LIKE", system_info->container_os_id_like, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_VERSION", system_info->container_os_version, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_VERSION_ID", system_info->container_os_version_id, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_CONTAINER_OS_DETECTION", system_info->host_os_detection, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_OS_NAME", system_info->host_os_name, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_OS_ID", system_info->host_os_id, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_OS_ID_LIKE", system_info->host_os_id_like, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_OS_VERSION", system_info->host_os_version, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_OS_VERSION_ID", system_info->host_os_version_id, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_OS_DETECTION", system_info->host_os_detection, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_KERNEL_NAME", system_info->kernel_name, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_CPU_LOGICAL_CPU_COUNT", system_info->host_cores, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_CPU_FREQ", system_info->host_cpu_freq, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_TOTAL_RAM", system_info->host_ram_total, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_TOTAL_DISK_SIZE", system_info->host_disk_space, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_KERNEL_VERSION", system_info->kernel_version, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_ARCHITECTURE", system_info->architecture, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_VIRTUALIZATION", system_info->virtualization, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_VIRT_DETECTION", system_info->virt_detection, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_CONTAINER", system_info->container, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_SYSTEM_CONTAINER_DETECTION", system_info->container_detection, &host->host_uuid); + ret += add_host_sysinfo_key_value("NETDATA_HOST_IS_K8S_NODE", system_info->is_k8s_node, &host->host_uuid); + + return !(24 == ret); } @@ -522,7 +553,7 @@ static int store_chart_metadata(RRDSET *st) if (unlikely(rc != SQLITE_OK)) goto bind_fail; - rc = sqlite3_bind_int(res, ++param, (int) st->entries); + rc = sqlite3_bind_int(res, ++param, (int) st->db.entries); if (unlikely(rc != SQLITE_OK)) goto bind_fail; @@ -665,7 +696,7 @@ static void check_dimension_metadata(struct metadata_wc *wc) uint32_t total_deleted= 0; uint64_t last_row_id = wc->row_id; - info("METADATA: Checking dimensions starting after row %"PRIu64, wc->row_id); + netdata_log_info("METADATA: Checking dimensions starting after row %"PRIu64, wc->row_id); while (sqlite3_step_monitored(res) == SQLITE_ROW && total_deleted < MAX_METADATA_CLEANUP) { if (unlikely(metadata_flag_check(wc, METADATA_FLAG_SHUTDOWN))) @@ -685,7 +716,7 @@ static void check_dimension_metadata(struct metadata_wc *wc) wc->check_metadata_after = now + METADATA_MAINTENANCE_RETRY; } else wc->row_id = 0; - info("METADATA: Checked %u, deleted %u -- will resume after row %"PRIu64" in %lld seconds", total_checked, total_deleted, wc->row_id, + netdata_log_info("METADATA: Checked %u, deleted %u -- will resume after row %"PRIu64" in %lld seconds", total_checked, total_deleted, wc->row_id, (long long)(wc->check_metadata_after - now)); skip_run: @@ -919,7 +950,7 @@ static void cleanup_finished_threads(struct host_context_load_thread *hclt, size || (wait && __atomic_load_n(&(hclt[index].busy), __ATOMIC_ACQUIRE))) { int rc = uv_thread_join(&(hclt[index].thread)); if (rc) - error("Failed to join thread, rc = %d",rc); + netdata_log_error("Failed to join thread, rc = %d",rc); __atomic_store_n(&(hclt[index].busy), false, __ATOMIC_RELEASE); __atomic_store_n(&(hclt[index].finished), false, __ATOMIC_RELEASE); } @@ -1067,23 +1098,15 @@ static bool metadata_scan_host(RRDHOST *host, uint32_t max_count, bool use_trans return more_to_do; } -static void store_host_and_system_info(RRDHOST *host, BUFFER *work_buffer, size_t *query_counter) +static void store_host_and_system_info(RRDHOST *host, size_t *query_counter) { - bool free_work_buffer = (NULL == work_buffer); - - if (unlikely(free_work_buffer)) - work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite); - - if (build_host_system_info_statements(host, work_buffer)) { - int rc = db_execute(db_meta, buffer_tostring(work_buffer)); - if (unlikely(rc)) { - error_report("METADATA: 'host:%s': Failed to store host updated information in the database", rrdhost_hostname(host)); - rrdhost_flag_set(host, RRDHOST_FLAG_METADATA_INFO | RRDHOST_FLAG_METADATA_UPDATE); - } - else { - if (likely(query_counter)) - (*query_counter)++; - } + if (unlikely(store_host_systeminfo(host))) { + error_report("METADATA: 'host:%s': Failed to store host updated system information in the database", rrdhost_hostname(host)); + rrdhost_flag_set(host, RRDHOST_FLAG_METADATA_INFO | RRDHOST_FLAG_METADATA_UPDATE); + } + else { + if (likely(query_counter)) + (*query_counter)++; } if (unlikely(store_host_metadata(host))) { @@ -1094,9 +1117,6 @@ static void store_host_and_system_info(RRDHOST *host, BUFFER *work_buffer, size_ if (likely(query_counter)) (*query_counter)++; } - - if (unlikely(free_work_buffer)) - buffer_free(work_buffer); } // Worker thread to scan hosts for pending metadata to store @@ -1170,7 +1190,7 @@ static void start_metadata_hosts(uv_work_t *req __maybe_unused) } if (unlikely(rrdhost_flag_check(host, RRDHOST_FLAG_METADATA_INFO))) { rrdhost_flag_clear(host, RRDHOST_FLAG_METADATA_INFO); - store_host_and_system_info(host, work_buffer, &query_counter); + store_host_and_system_info(host, &query_counter); } // For clarity @@ -1224,27 +1244,27 @@ static void metadata_event_loop(void *arg) loop = wc->loop = mallocz(sizeof(uv_loop_t)); ret = uv_loop_init(loop); if (ret) { - error("uv_loop_init(): %s", uv_strerror(ret)); + netdata_log_error("uv_loop_init(): %s", uv_strerror(ret)); goto error_after_loop_init; } loop->data = wc; ret = uv_async_init(wc->loop, &wc->async, async_cb); if (ret) { - error("uv_async_init(): %s", uv_strerror(ret)); + netdata_log_error("uv_async_init(): %s", uv_strerror(ret)); goto error_after_async_init; } wc->async.data = wc; ret = uv_timer_init(loop, &wc->timer_req); if (ret) { - error("uv_timer_init(): %s", uv_strerror(ret)); + netdata_log_error("uv_timer_init(): %s", uv_strerror(ret)); goto error_after_timer_init; } wc->timer_req.data = wc; fatal_assert(0 == uv_timer_start(&wc->timer_req, timer_cb, TIMER_INITIAL_PERIOD_MS, TIMER_REPEAT_PERIOD_MS)); - info("Starting metadata sync thread with %d entries command queue", METADATA_CMD_Q_MAX_SIZE); + netdata_log_info("Starting metadata sync thread with %d entries command queue", METADATA_CMD_Q_MAX_SIZE); struct metadata_cmd cmd; memset(&cmd, 0, sizeof(cmd)); @@ -1309,7 +1329,7 @@ static void metadata_event_loop(void *arg) break; case METADATA_ADD_HOST_INFO: host = (RRDHOST *) cmd.param[0]; - store_host_and_system_info(host, NULL, NULL); + store_host_and_system_info(host, NULL); break; case METADATA_SCAN_HOSTS: if (unlikely(metadata_flag_check(wc, METADATA_FLAG_SCANNING_HOSTS))) @@ -1394,7 +1414,7 @@ static void metadata_event_loop(void *arg) freez(loop); worker_unregister(); - info("METADATA: Shutting down event loop"); + netdata_log_info("METADATA: Shutting down event loop"); completion_mark_complete(&wc->init_complete); return; @@ -1415,15 +1435,15 @@ void metadata_sync_shutdown(void) struct metadata_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - info("METADATA: Sending a shutdown command"); + netdata_log_info("METADATA: Sending a shutdown command"); cmd.opcode = METADATA_SYNC_SHUTDOWN; metadata_enq_cmd(&metasync_worker, &cmd); /* wait for metadata thread to shut down */ - info("METADATA: Waiting for shutdown ACK"); + netdata_log_info("METADATA: Waiting for shutdown ACK"); completion_wait_for(&metasync_worker.init_complete); completion_destroy(&metasync_worker.init_complete); - info("METADATA: Shutdown complete"); + netdata_log_info("METADATA: Shutdown complete"); } void metadata_sync_shutdown_prepare(void) @@ -1437,11 +1457,11 @@ void metadata_sync_shutdown_prepare(void) struct completion compl; completion_init(&compl); - info("METADATA: Sending a scan host command"); + netdata_log_info("METADATA: Sending a scan host command"); uint32_t max_wait_iterations = 2000; while (unlikely(metadata_flag_check(&metasync_worker, METADATA_FLAG_SCANNING_HOSTS)) && max_wait_iterations--) { if (max_wait_iterations == 1999) - info("METADATA: Current worker is running; waiting to finish"); + netdata_log_info("METADATA: Current worker is running; waiting to finish"); sleep_usec(1000); } @@ -1449,10 +1469,10 @@ void metadata_sync_shutdown_prepare(void) cmd.completion = &compl; metadata_enq_cmd(&metasync_worker, &cmd); - info("METADATA: Waiting for host scan completion"); + netdata_log_info("METADATA: Waiting for host scan completion"); completion_wait_for(&compl); completion_destroy(&compl); - info("METADATA: Host scan complete; can continue with shutdown"); + netdata_log_info("METADATA: Host scan complete; can continue with shutdown"); } // ------------------------------------------------------------- @@ -1471,7 +1491,7 @@ void metadata_sync_init(void) completion_wait_for(&wc->init_complete); completion_destroy(&wc->init_complete); - info("SQLite metadata sync initialization complete"); + netdata_log_info("SQLite metadata sync initialization complete"); } @@ -1485,7 +1505,6 @@ static inline void queue_metadata_cmd(enum metadata_opcode opcode, const void *p cmd.param[1] = param1; cmd.completion = NULL; metadata_enq_cmd(&metasync_worker, &cmd); - } // Public -- cgit v1.2.3