From 5a7b22181ff1b756c0690f3f2efab682b2bf0dd9 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sat, 6 Dec 2025 16:06:47 +0000 Subject: [PATCH] Fix metrics collection for wait_timeout counters The get_status_variable() function was only scanning worker threads but ignoring auxiliary threads (idle threads) where timeout terminations are detected. This caused the timeout termination counter to show incorrect/zero values. - Added idle thread scanning to both overloaded versions of get_status_variable() function - Now properly collects metrics from both worker and idle threads - Fixes the issue where proxysql_mysql_timeout_terminated_connections_total showed zero despite actual timeout terminations Resolves the metrics reading issue identified in the previous commits. --- include/MySQL_Thread.h | 4 ++++ lib/MySQL_Session.cpp | 3 +++ lib/MySQL_Thread.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index aaedadf8e..7391b5ab5 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -90,6 +90,8 @@ enum MySQL_Thread_status_variable { st_var_automatic_detected_sqli, st_var_mysql_whitelisted_sqli_fingerprint, st_var_client_host_error_killed_connections, + st_var_set_wait_timeout_commands, + st_var_timeout_terminated_connections, MY_st_var_END }; @@ -281,6 +283,8 @@ struct p_th_counter { hostgroup_locked_set_cmds, hostgroup_locked_queries, mysql_unexpected_frontend_packets, + mysql_set_wait_timeout_commands, + mysql_timeout_terminated_connections, aws_aurora_replicas_skipped_during_query, automatic_detected_sql_injection, mysql_whitelisted_sqli_fingerprint, diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 729f041ff..4b9367ad2 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -6600,6 +6600,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C std::string value = *values++; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Client requested SET wait_timeout = %s\n", value.c_str()); + // Increment counter for SET wait_timeout commands + thread->status_variables.stvar[st_var_set_wait_timeout_commands]++; + unsigned long long client_timeout = 0; try { client_timeout = std::stoull(value) * 1000; diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 9c82b12ce..330c37af0 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -165,6 +165,8 @@ mythr_st_vars_t MySQL_Thread_status_variables_counter_array[] { { st_var_max_connect_timeout_err, p_th_counter::max_connect_timeouts, (char *)"max_connect_timeouts" }, { st_var_generated_pkt_err, p_th_counter::generated_error_packets, (char *)"generated_error_packets" }, { st_var_client_host_error_killed_connections, p_th_counter::client_host_error_killed_connections, (char *)"client_host_error_killed_connections" }, + { st_var_set_wait_timeout_commands, p_th_counter::mysql_set_wait_timeout_commands, (char *)"mysql_set_wait_timeout_commands" }, + { st_var_timeout_terminated_connections, p_th_counter::mysql_timeout_terminated_connections, (char *)"mysql_timeout_terminated_connections" }, }; mythr_g_st_vars_t MySQL_Thread_status_variables_gauge_array[] { @@ -807,6 +809,18 @@ th_metrics_map = std::make_tuple( "proxysql_client_host_error_killed_connections", "Killed client connections because address exceeded 'client_host_error_counts'.", metric_tags {} + ), + std::make_tuple ( + p_th_counter::mysql_set_wait_timeout_commands, + "proxysql_mysql_set_wait_timeout_commands_total", + "Number of SET wait_timeout commands received from clients.", + metric_tags {} + ), + std::make_tuple ( + p_th_counter::mysql_timeout_terminated_connections, + "proxysql_mysql_timeout_terminated_connections_total", + "Number of client connections terminated due to wait_timeout.", + metric_tags {} ) }, th_gauge_vector { @@ -3452,6 +3466,9 @@ void MySQL_Thread::idle_thread_to_kill_idle_sessions() { unsigned long long sess_time = curtime - mysess->idle_since; proxy_warning("Killing client connection %s:%d because inactive for %llums\n", mysess->client_myds->addr.addr, mysess->client_myds->addr.port, sess_time/1000); mysess->killed=true; + + // Increment counter for timeout-terminated connections + mysess->thread->status_variables.stvar[st_var_timeout_terminated_connections]++; } if (mysess->killed==true) { // because idle or for any other reason MySQL_Data_Stream *tmp_myds=mysess->client_myds; @@ -3873,6 +3890,9 @@ void MySQL_Thread::ProcessAllSessions_MaintenanceLoop(MySQL_Session *sess, unsig if (sess->client_myds) { proxy_warning("Killing client connection %s:%d because inactive for %llums\n",sess->client_myds->addr.addr,sess->client_myds->addr.port, sess_time/1000); } + + // Increment counter for timeout-terminated connections + sess->thread->status_variables.stvar[st_var_timeout_terminated_connections]++; } } } else { @@ -4070,6 +4090,9 @@ void MySQL_Thread::process_all_sessions() { sess->killed=true; sess->to_process=1; proxy_warning("Killing client connection %s:%d because inactive for %llums\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, sess_time/1000); + + // Increment counter for timeout-terminated connections + sess->thread->status_variables.stvar[st_var_timeout_terminated_connections]++; } } #endif // IDLE_THREADS @@ -5371,6 +5394,16 @@ unsigned long long MySQL_Threads_Handler::get_status_variable( q+=__sync_fetch_and_add(&thr->status_variables.stvar[v_idx],0); } } +#ifdef IDLE_THREADS + if (GloVars.global.idle_threads) + for (i=0;istatus_variables.stvar[v_idx],0); + } + } +#endif // IDLE_THREADS if (m_idx != p_th_counter::__size) { const auto& cur_val = status_variables.p_counter_array[m_idx]->Value(); double final_val = 0; @@ -5402,6 +5435,16 @@ unsigned long long MySQL_Threads_Handler::get_status_variable( q+=__sync_fetch_and_add(&thr->status_variables.stvar[v_idx],0); } } +#ifdef IDLE_THREADS + if (GloVars.global.idle_threads) + for (i=0;istatus_variables.stvar[v_idx],0); + } + } +#endif // IDLE_THREADS if (m_idx != p_th_gauge::__size) { double final_val = 0;