From c21c3b0befeb46a51b6bf3758ffa30813bea0ff0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 9 Mar 2024 14:19:22 +0100 Subject: Adding upstream version 1.44.3. Signed-off-by: Daniel Baumann --- database/sqlite/sqlite_health.c | 479 ++++++++++++++++++---------------------- 1 file changed, 209 insertions(+), 270 deletions(-) (limited to 'database/sqlite/sqlite_health.c') diff --git a/database/sqlite/sqlite_health.c b/database/sqlite/sqlite_health.c index 6fc6a2e64..7d79ff70b 100644 --- a/database/sqlite/sqlite_health.c +++ b/database/sqlite/sqlite_health.c @@ -95,18 +95,22 @@ failed: /* Health related SQL queries Inserts an entry in the table */ + #define SQL_INSERT_HEALTH_LOG \ "INSERT INTO health_log (host_id, alarm_id, " \ - "config_hash_id, name, chart, exec, recipient, units, chart_context, last_transition_id, chart_name) " \ - "VALUES (?,?,?,?,?,?,?,?,?,?,?) " \ - "ON CONFLICT (host_id, alarm_id) DO UPDATE SET last_transition_id = excluded.last_transition_id, " \ - "chart_name = excluded.chart_name 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, " \ + "config_hash_id, name, chart, exec, recipient, units, chart_context, last_transition_id, chart_name) " \ + "VALUES (@host_id,@alarm_id, @config_hash_id,@name,@chart,@exec,@recipient,@units,@chart_context," \ + "@last_transition_id,@chart_name) ON CONFLICT (host_id, alarm_id) DO UPDATE " \ + "SET last_transition_id = excluded.last_transition_id, chart_name = excluded.chart_name 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, summary) " \ - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,@global_id,?); " + "VALUES (@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,@summary)" + static void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) { sqlite3_stmt *res = NULL; int rc; @@ -353,7 +357,6 @@ static void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) { } ae->flags |= HEALTH_ENTRY_FLAG_SAVED; - host->health.health_log_entries_written++; failed: if (unlikely(sqlite3_finalize(res) != SQLITE_OK)) @@ -374,48 +377,6 @@ 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_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" - -static int sql_health_alarm_log_count(RRDHOST *host) { - sqlite3_stmt *res = NULL; - int rc; - - if (unlikely(!db_meta)) { - if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) - error_report("Database has not been initialized"); - return -1; - } - - int entries_in_db = -1; - - 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"); - goto done; - } - - 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."); - goto done; - } - - rc = sqlite3_step_monitored(res); - if (likely(rc == SQLITE_ROW)) - entries_in_db = (int) sqlite3_column_int64(res, 0); - -done: - rc = sqlite3_finalize(res); - if (unlikely(rc != SQLITE_OK)) - error_report("Failed to finalize the prepared statement to count health log entries from db"); - - return entries_in_db; -} - /* * * Health related SQL queries @@ -423,19 +384,22 @@ done: * */ -#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 = @host_id) AND when_key < unixepoch() - @history " \ - "AND updated_by_id <> 0 AND transition_id NOT IN " \ - "(SELECT last_transition_id FROM health_log hl WHERE hl.host_id = @host_id);" - -#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 = @host_id AND hl.health_log_id = hld.health_log_id) " \ - "AND health_log_id IN (SELECT health_log_id FROM health_log WHERE host_id = @host_id) " \ - "AND when_key < unixepoch() - @history " \ - "AND updated_by_id <> 0 AND transition_id NOT IN " \ - "(SELECT last_transition_id FROM health_log hl WHERE hl.host_id = @host_id);", guid +#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 = @host_id) AND when_key < UNIXEPOCH() - @history " \ + "AND updated_by_id <> 0 AND transition_id NOT IN " \ + "(SELECT last_transition_id FROM health_log hl WHERE hl.host_id = @host_id)" + +#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 = @host_id AND hl.health_log_id = hld.health_log_id) " \ + "AND health_log_id IN (SELECT health_log_id FROM health_log WHERE host_id = @host_id) " \ + "AND when_key < unixepoch() - @history " \ + "AND updated_by_id <> 0 AND transition_id NOT IN " \ + "(SELECT last_transition_id FROM health_log hl WHERE hl.host_id = @host_id)", \ + guid void sql_health_alarm_log_cleanup(RRDHOST *host, bool claimed) { sqlite3_stmt *res = NULL; @@ -450,14 +414,14 @@ void sql_health_alarm_log_cleanup(RRDHOST *host, bool claimed) { char uuid_str[UUID_STR_LEN]; uuid_unparse_lower_fix(&host->host_uuid, uuid_str); - snprintfz(command, MAX_HEALTH_SQL_SIZE, "aclk_alert_%s", uuid_str); + snprintfz(command, sizeof(command) - 1, "aclk_alert_%s", uuid_str); bool aclk_table_exists = table_exists_in_database(db_meta, command); char *sql = SQL_CLEANUP_HEALTH_LOG_DETAIL_NOT_CLAIMED; if (claimed && aclk_table_exists) { - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_CLEANUP_HEALTH_LOG_DETAIL_CLAIMED(uuid_str)); + snprintfz(command, sizeof(command) - 1, SQL_CLEANUP_HEALTH_LOG_DETAIL_CLAIMED(uuid_str)); sql = command; } @@ -483,10 +447,6 @@ void sql_health_alarm_log_cleanup(RRDHOST *host, bool claimed) { if (unlikely(rc != SQLITE_DONE)) error_report("Failed to cleanup health log detail table, rc = %d", rc); - int rows = sql_health_alarm_log_count(host); - if (rows >= 0) - host->health.health_log_entries_written = rows; - if (aclk_table_exists) sql_aclk_alert_clean_dead_entries(host); @@ -497,17 +457,25 @@ done: } #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, " \ + "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, summary) " \ - "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), summary 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) + "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), summary 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; @@ -737,13 +705,14 @@ void sql_check_removed_alerts_state(RRDHOST *host) /* Health related SQL queries Load from the health log table */ -#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.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, hl.chart_name, hld.summary " \ - "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;" +#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.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, " \ + "hl.chart_name, hld.summary 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) { @@ -751,8 +720,6 @@ void sql_health_alarm_log_load(RRDHOST *host) int ret; ssize_t errored = 0, loaded = 0; - host->health.health_log_entries_written = 0; - 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)); @@ -914,27 +881,28 @@ 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; - netdata_log_health("[%s]: Table health_log, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), loaded, errored); + nd_log(NDLS_DAEMON, errored ? NDLP_WARNING : NDLP_DEBUG, + "[%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)) error_report("Failed to finalize the health log read statement"); - - int rows = sql_health_alarm_log_count(host); - - if (rows >= 0) - host->health.health_log_entries_written = rows; } /* * Store an alert config hash in the database */ -#define SQL_STORE_ALERT_CONFIG_HASH "insert or replace into alert_hash (hash_id, date_updated, alarm, template, " \ - "on_key, class, component, type, os, hosts, lookup, every, units, calc, 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, summary) 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);" +#define SQL_STORE_ALERT_CONFIG_HASH \ + "insert or replace into alert_hash (hash_id, date_updated, alarm, template, " \ + "on_key, class, component, type, os, hosts, lookup, every, units, calc, 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, summary) values (@hash_id,UNIXEPOCH(),@alarm,@template," \ + "@on_key,@class,@component,@type,@os,@hosts,@lookup,@every,@units,@calc,@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,@summary)" int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg) { @@ -1212,7 +1180,7 @@ int alert_hash_and_store_config( #define SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT \ "SELECT hld.new_status FROM health_log hl, health_log_detail hld " \ "WHERE hl.host_id = @host_id AND hl.alarm_id = @alarm_id AND hld.unique_id != @unique_id AND hld.flags & @flags " \ - "AND hl.health_log_id = hld.health_log_id ORDER BY hld.unique_id DESC LIMIT 1;" + "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) { @@ -1270,191 +1238,162 @@ done: "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.summary " \ "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 " + "hl.health_log_id = hld.health_log_id and hl.host_id = @host_id AND hld.unique_id > @after " -void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart) { +void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, time_t after, const char *chart) +{ + unsigned int max = host->health_log.max; - buffer_strcat(wb, "["); + static __thread sqlite3_stmt *stmt_no_chart = NULL; + static __thread sqlite3_stmt *stmt_with_chart = NULL; - unsigned int max = host->health_log.max; - unsigned int count = 0; + sqlite3_stmt **active_stmt; + sqlite3_stmt *stmt_query; - sqlite3_stmt *res = NULL; - int rc; + int rc; - BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL); - buffer_sprintf(command, SQL_SELECT_HEALTH_LOG); + active_stmt = chart ? &stmt_with_chart : &stmt_no_chart; - if (chart) { - char chart_sql[MAX_HEALTH_SQL_SIZE + 1]; - snprintfz(chart_sql, MAX_HEALTH_SQL_SIZE, "AND hl.chart = '%s' ", chart); - buffer_strcat(command, chart_sql); - } + if (!*active_stmt) { - if (after) { - char after_sql[MAX_HEALTH_SQL_SIZE + 1]; - snprintfz(after_sql, MAX_HEALTH_SQL_SIZE, "AND hld.unique_id > %u ", after); - buffer_strcat(command, after_sql); - } + BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL); + buffer_sprintf(command, SQL_SELECT_HEALTH_LOG); - { - char limit_sql[MAX_HEALTH_SQL_SIZE + 1]; - snprintfz(limit_sql, MAX_HEALTH_SQL_SIZE, "ORDER BY hld.unique_id DESC LIMIT %u ", max); - buffer_strcat(command, limit_sql); - } + if (chart) + buffer_strcat(command, " AND hl.chart = @chart "); - rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0); - if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to prepare statement SQL_SELECT_HEALTH_LOG"); - buffer_free(command); - return; - } + buffer_strcat(command, " ORDER BY hld.unique_id DESC LIMIT @limit"); - 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; - } + rc = prepare_statement(db_meta, buffer_tostring(command), active_stmt); + buffer_free(command); - while (sqlite3_step(res) == SQLITE_ROW) { + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement SQL_SELECT_HEALTH_LOG"); + return; + } + } - char old_value_string[100 + 1]; - char new_value_string[100 + 1]; + stmt_query = *active_stmt; - char config_hash_id[UUID_STR_LEN]; - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 3)), config_hash_id); + int param = 0; + rc = sqlite3_bind_blob(stmt_query, ++param, &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."); + goto finish; + } - char transition_id[UUID_STR_LEN] = {0}; - if (sqlite3_column_type(res, 30) != SQLITE_NULL) - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 30)), transition_id); - - char *edit_command = sqlite3_column_bytes(res, 16) > 0 ? health_edit_command_from_source((char *)sqlite3_column_text(res, 16)) : strdupz("UNKNOWN=0=UNKNOWN"); - - if (count) - buffer_sprintf(wb, ","); - - count++; - - buffer_sprintf( - wb, - "\n\t{\n" - "\t\t\"hostname\": \"%s\",\n" - "\t\t\"utc_offset\": %d,\n" - "\t\t\"timezone\": \"%s\",\n" - "\t\t\"unique_id\": %u,\n" - "\t\t\"alarm_id\": %u,\n" - "\t\t\"alarm_event_id\": %u,\n" - "\t\t\"config_hash_id\": \"%s\",\n" - "\t\t\"transition_id\": \"%s\",\n" - "\t\t\"name\": \"%s\",\n" - "\t\t\"chart\": \"%s\",\n" - "\t\t\"context\": \"%s\",\n" - "\t\t\"class\": \"%s\",\n" - "\t\t\"component\": \"%s\",\n" - "\t\t\"type\": \"%s\",\n" - "\t\t\"processed\": %s,\n" - "\t\t\"updated\": %s,\n" - "\t\t\"exec_run\": %lu,\n" - "\t\t\"exec_failed\": %s,\n" - "\t\t\"exec\": \"%s\",\n" - "\t\t\"recipient\": \"%s\",\n" - "\t\t\"exec_code\": %d,\n" - "\t\t\"source\": \"%s\",\n" - "\t\t\"command\": \"%s\",\n" - "\t\t\"units\": \"%s\",\n" - "\t\t\"when\": %lu,\n" - "\t\t\"duration\": %lu,\n" - "\t\t\"non_clear_duration\": %lu,\n" - "\t\t\"status\": \"%s\",\n" - "\t\t\"old_status\": \"%s\",\n" - "\t\t\"delay\": %d,\n" - "\t\t\"delay_up_to_timestamp\": %lu,\n" - "\t\t\"updated_by_id\": %u,\n" - "\t\t\"updates_id\": %u,\n" - "\t\t\"value_string\": \"%s\",\n" - "\t\t\"old_value_string\": \"%s\",\n" - "\t\t\"last_repeat\": %lu,\n" - "\t\t\"silenced\": \"%s\",\n", - 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), - config_hash_id, - transition_id, - sqlite3_column_text(res, 12), - sqlite3_column_text(res, 13), - sqlite3_column_text(res, 29), - sqlite3_column_text(res, 26) ? (const char *) sqlite3_column_text(res, 26) : (char *) "Unknown", - 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_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, 14) ? (const char *) sqlite3_column_text(res, 14) : string2str(host->health.health_default_exec), - sqlite3_column_text(res, 15) ? (const char *) sqlite3_column_text(res, 15) : string2str(host->health.health_default_recipient), - sqlite3_column_int(res, 19), - sqlite3_column_text(res, 16) ? (const char *) sqlite3_column_text(res, 16) : (char *) "Unknown", - edit_command, - sqlite3_column_text(res, 17), - (long unsigned int)sqlite3_column_int64(res, 6), - (long unsigned int)sqlite3_column_int64(res, 7), - (long unsigned int)sqlite3_column_int64(res, 8), - rrdcalc_status2string(sqlite3_column_int(res, 20)), - rrdcalc_status2string(sqlite3_column_int(res, 21)), - sqlite3_column_int(res, 22), - (long unsigned int)sqlite3_column_int64(res, 11), - (unsigned int)sqlite3_column_int64(res, 4), - (unsigned int)sqlite3_column_int64(res, 5), - sqlite3_column_type(res, 23) == SQLITE_NULL ? "-" : format_value_and_unit(new_value_string, 100, sqlite3_column_double(res, 23), (char *) sqlite3_column_text(res, 17), -1), - sqlite3_column_type(res, 24) == SQLITE_NULL ? "-" : format_value_and_unit(old_value_string, 100, sqlite3_column_double(res, 24), (char *) sqlite3_column_text(res, 17), -1), - (long unsigned int)sqlite3_column_int64(res, 25), - (sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false"); - - health_string2json(wb, "\t\t", "summary", (char *) sqlite3_column_text(res, 31), ",\n"); - health_string2json(wb, "\t\t", "info", (char *) sqlite3_column_text(res, 18), ",\n"); - - if(unlikely(sqlite3_column_int64(res, 9) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) { - buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n"); - } + rc = sqlite3_bind_int64(stmt_query, ++param, after); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind after for SQL_SELECT_HEALTH_LOG."); + goto finish; + } - buffer_strcat(wb, "\t\t\"value\":"); - if (sqlite3_column_type(res, 23) == SQLITE_NULL) - buffer_strcat(wb, "null"); - else - buffer_print_netdata_double(wb, sqlite3_column_double(res, 23)); - buffer_strcat(wb, ",\n"); + if (chart) { + rc = sqlite3_bind_text(stmt_query, ++param, chart, -1, SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind after for SQL_SELECT_HEALTH_LOG."); + goto finish; + } + } - buffer_strcat(wb, "\t\t\"old_value\":"); - if (sqlite3_column_type(res, 24) == SQLITE_NULL) - buffer_strcat(wb, "null"); + rc = sqlite3_bind_int64(stmt_query, ++param, max); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind max lines for SQL_SELECT_HEALTH_LOG."); + goto finish; + } + + buffer_json_initialize(wb, "\"", "\"", 0, false, BUFFER_JSON_OPTIONS_DEFAULT); + buffer_json_member_add_array(wb, NULL); + + while (sqlite3_step(stmt_query) == 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(stmt_query, 3)), config_hash_id); + + char transition_id[UUID_STR_LEN] = {0}; + if (sqlite3_column_type(stmt_query, 30) != SQLITE_NULL) + uuid_unparse_lower(*((uuid_t *)sqlite3_column_blob(stmt_query, 30)), transition_id); + + char *edit_command = sqlite3_column_bytes(stmt_query, 16) > 0 ? + health_edit_command_from_source((char *)sqlite3_column_text(stmt_query, 16)) : + strdupz("UNKNOWN=0=UNKNOWN"); + + buffer_json_add_array_item_object(wb); // this node + + buffer_json_member_add_string_or_empty(wb, "hostname", rrdhost_hostname(host)); + buffer_json_member_add_int64(wb, "utc_offset", (int64_t)host->utc_offset); + buffer_json_member_add_string_or_empty(wb, "timezone", rrdhost_abbrev_timezone(host)); + buffer_json_member_add_int64(wb, "unique_id", (int64_t) sqlite3_column_int64(stmt_query, 0)); + buffer_json_member_add_int64(wb, "alarm_id", (int64_t) sqlite3_column_int64(stmt_query, 1)); + buffer_json_member_add_int64(wb, "alarm_event_id", (int64_t) sqlite3_column_int64(stmt_query, 2)); + buffer_json_member_add_string_or_empty(wb, "config_hash_id", config_hash_id); + buffer_json_member_add_string_or_empty(wb, "transition_id", transition_id); + buffer_json_member_add_string_or_empty(wb, "name", (const char *) sqlite3_column_text(stmt_query, 12)); + buffer_json_member_add_string_or_empty(wb, "chart", (const char *) sqlite3_column_text(stmt_query, 13)); + buffer_json_member_add_string_or_empty(wb, "context", (const char *) sqlite3_column_text(stmt_query, 29)); + buffer_json_member_add_string_or_empty(wb, "class", sqlite3_column_text(stmt_query, 26) ? (const char *) sqlite3_column_text(stmt_query, 26) : (char *) "Unknown"); + buffer_json_member_add_string_or_empty(wb, "component", sqlite3_column_text(stmt_query, 27) ? (const char *) sqlite3_column_text(stmt_query, 27) : (char *) "Unknown"); + buffer_json_member_add_string_or_empty(wb, "type", sqlite3_column_text(stmt_query, 28) ? (const char *) sqlite3_column_text(stmt_query, 28) : (char *) "Unknown"); + buffer_json_member_add_boolean(wb, "processed", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_PROCESSED)); + buffer_json_member_add_boolean(wb, "updated", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_UPDATED)); + buffer_json_member_add_int64(wb, "exec_run", (int64_t)sqlite3_column_int64(stmt_query, 10)); + buffer_json_member_add_boolean(wb, "exec_failed", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_EXEC_FAILED)); + buffer_json_member_add_string_or_empty(wb, "exec", sqlite3_column_text(stmt_query, 14) ? (const char *) sqlite3_column_text(stmt_query, 14) : string2str(host->health.health_default_exec)); + buffer_json_member_add_string_or_empty(wb, "recipient", sqlite3_column_text(stmt_query, 15) ? (const char *) sqlite3_column_text(stmt_query, 15) : string2str(host->health.health_default_recipient)); + buffer_json_member_add_int64(wb, "exec_code", sqlite3_column_int(stmt_query, 19)); + buffer_json_member_add_string_or_empty(wb, "source", sqlite3_column_text(stmt_query, 16) ? (const char *) sqlite3_column_text(stmt_query, 16) : (char *) "Unknown"); + buffer_json_member_add_string_or_empty(wb, "command", edit_command); + buffer_json_member_add_string_or_empty(wb, "units", (const char *) sqlite3_column_text(stmt_query, 17)); + buffer_json_member_add_int64(wb, "when", (int64_t)sqlite3_column_int64(stmt_query, 6)); + buffer_json_member_add_int64(wb, "duration", (int64_t)sqlite3_column_int64(stmt_query, 7)); + buffer_json_member_add_int64(wb, "non_clear_duration", (int64_t)sqlite3_column_int64(stmt_query, 8)); + buffer_json_member_add_string_or_empty(wb, "status", rrdcalc_status2string(sqlite3_column_int(stmt_query, 20))); + buffer_json_member_add_string_or_empty(wb, "old_status", rrdcalc_status2string(sqlite3_column_int(stmt_query, 21))); + buffer_json_member_add_int64(wb, "delay", sqlite3_column_int(stmt_query, 22)); + buffer_json_member_add_int64(wb, "delay_up_to_timestamp",(int64_t)sqlite3_column_int64(stmt_query, 11)); + buffer_json_member_add_int64(wb, "updated_by_id", (unsigned int)sqlite3_column_int64(stmt_query, 4)); + buffer_json_member_add_int64(wb, "updates_id", (unsigned int)sqlite3_column_int64(stmt_query, 5)); + buffer_json_member_add_string_or_empty(wb, "value_string", sqlite3_column_type(stmt_query, 23) == SQLITE_NULL ? "-" : + format_value_and_unit(new_value_string, 100, sqlite3_column_double(stmt_query, 23), (char *) sqlite3_column_text(stmt_query, 17), -1)); + buffer_json_member_add_string_or_empty(wb, "old_value_string", sqlite3_column_type(stmt_query, 24) == SQLITE_NULL ? "-" : + format_value_and_unit(old_value_string, 100, sqlite3_column_double(stmt_query, 24), (char *) sqlite3_column_text(stmt_query, 17), -1)); + buffer_json_member_add_int64(wb, "last_repeat", (int64_t)sqlite3_column_int64(stmt_query, 25)); + buffer_json_member_add_boolean(wb, "silenced", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_SILENCED)); + buffer_json_member_add_string_or_empty(wb, "summary", (const char *) sqlite3_column_text(stmt_query, 31)); + buffer_json_member_add_string_or_empty(wb, "info", (const char *) sqlite3_column_text(stmt_query, 18)); + buffer_json_member_add_boolean(wb, "no_clear_notification",(sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)); + + if (sqlite3_column_type(stmt_query, 23) == SQLITE_NULL) + buffer_json_member_add_string(wb, "value", NULL); else - buffer_print_netdata_double(wb, sqlite3_column_double(res, 24)); - buffer_strcat(wb, "\n"); + buffer_json_member_add_double(wb, "value", sqlite3_column_double(stmt_query, 23)); - buffer_strcat(wb, "\t}"); + if (sqlite3_column_type(stmt_query, 24) == SQLITE_NULL) + buffer_json_member_add_string(wb, "old_value", NULL); + else + buffer_json_member_add_double(wb, "old_value", sqlite3_column_double(stmt_query, 23)); freez(edit_command); + + buffer_json_object_close(wb); } - buffer_strcat(wb, "\n]"); + buffer_json_array_close(wb); + buffer_json_finalize(wb); - rc = sqlite3_finalize(res); - if (unlikely(rc != SQLITE_OK)) - error_report("Failed to finalize statement for SQL_SELECT_HEALTH_LOG"); - - buffer_free(command); +finish: + rc = sqlite3_reset(stmt_query); + if (unlikely(rc != SQLITE_OK)) + error_report("Failed to reset statement for SQL_SELECT_HEALTH_LOG"); } -#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;" +#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; @@ -1476,7 +1415,7 @@ int health_migrate_old_health_log_table(char *table) { int rc; char command[MAX_HEALTH_SQL_SIZE + 1]; sqlite3_stmt *res = NULL; - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COPY_HEALTH_LOG(table)); + snprintfz(command, sizeof(command) - 1, 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); @@ -1503,7 +1442,7 @@ int health_migrate_old_health_log_table(char *table) { } //detail - snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_COPY_HEALTH_LOG_DETAIL(table)); + snprintfz(command, sizeof(command) - 1, 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); @@ -1913,12 +1852,12 @@ void sql_alert_transitions( goto run_query; } - snprintfz(sql, 511, SQL_BUILD_ALERT_TRANSITION, nodes); + snprintfz(sql, sizeof(sql) - 1, SQL_BUILD_ALERT_TRANSITION, nodes); rc = db_execute(db_meta, sql); if (rc) return; - snprintfz(sql, 511, SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE, nodes); + snprintfz(sql, sizeof(sql) - 1, SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE, nodes); // Prepare statement to add things rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); @@ -2046,7 +1985,7 @@ done: done_only_drop: if (likely(!transition)) { - (void)snprintfz(sql, 511, "DROP TABLE IF EXISTS v_%p", nodes); + (void)snprintfz(sql, sizeof(sql) - 1, "DROP TABLE IF EXISTS v_%p", nodes); (void)db_execute(db_meta, sql); buffer_free(command); } @@ -2078,12 +2017,12 @@ int sql_get_alert_configuration( if (unlikely(!configs)) return added; - snprintfz(sql, 511, SQL_BUILD_CONFIG_TARGET_LIST, configs); + snprintfz(sql, sizeof(sql) - 1, 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); + snprintfz(sql, sizeof(sql) - 1, SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE, configs); // Prepare statement to add things rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0); @@ -2180,7 +2119,7 @@ int sql_get_alert_configuration( 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)snprintfz(sql, sizeof(sql) - 1, "DROP TABLE IF EXISTS c_%p", configs); (void)db_execute(db_meta, sql); buffer_free(command); return added; -- cgit v1.2.3