summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/proxysql
diff options
context:
space:
mode:
Diffstat (limited to '')
l---------src/go/collectors/go.d.plugin/modules/proxysql/README.md1
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/cache.go63
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/charts.go726
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/collect.go308
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/config_schema.json47
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/integrations/proxysql.md274
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/metadata.yaml430
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/proxysql.go114
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/proxysql_test.go1240
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.json5
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.yaml3
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_memory_metrics.txt21
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_commands_counters.txt56
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_connection_pool .txt11
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_global.txt106
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_users.txt6
-rw-r--r--src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/version.txt5
17 files changed, 3416 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/README.md b/src/go/collectors/go.d.plugin/modules/proxysql/README.md
new file mode 120000
index 000000000..06223157d
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/README.md
@@ -0,0 +1 @@
+integrations/proxysql.md \ No newline at end of file
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/cache.go b/src/go/collectors/go.d.plugin/modules/proxysql/cache.go
new file mode 100644
index 000000000..c4fccefff
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/cache.go
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package proxysql
+
+type (
+ cache struct {
+ commands map[string]*commandCache
+ users map[string]*userCache
+ backends map[string]*backendCache
+ }
+ commandCache struct {
+ command string
+ hasCharts, updated bool
+ }
+ userCache struct {
+ user string
+ hasCharts, updated bool
+ }
+ backendCache struct {
+ hg, host, port string
+ hasCharts, updated bool
+ }
+)
+
+func (c *cache) reset() {
+ for k, m := range c.commands {
+ c.commands[k] = &commandCache{command: m.command, hasCharts: m.hasCharts}
+ }
+ for k, m := range c.users {
+ c.users[k] = &userCache{user: m.user, hasCharts: m.hasCharts}
+ }
+ for k, m := range c.backends {
+ c.backends[k] = &backendCache{hg: m.hg, host: m.host, port: m.port, hasCharts: m.hasCharts}
+ }
+}
+
+func (c *cache) getCommand(command string) *commandCache {
+ v, ok := c.commands[command]
+ if !ok {
+ v = &commandCache{command: command}
+ c.commands[command] = v
+ }
+ return v
+}
+
+func (c *cache) getUser(user string) *userCache {
+ v, ok := c.users[user]
+ if !ok {
+ v = &userCache{user: user}
+ c.users[user] = v
+ }
+ return v
+}
+
+func (c *cache) getBackend(hg, host, port string) *backendCache {
+ id := backendID(hg, host, port)
+ v, ok := c.backends[id]
+ if !ok {
+ v = &backendCache{hg: hg, host: host, port: port}
+ c.backends[id] = v
+ }
+ return v
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/charts.go b/src/go/collectors/go.d.plugin/modules/proxysql/charts.go
new file mode 100644
index 000000000..34e012740
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/charts.go
@@ -0,0 +1,726 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package proxysql
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+)
+
+// TODO: check https://github.com/ProxySQL/proxysql-grafana-prometheus/blob/main/grafana/provisioning/dashboards/ProxySQL-Host-Statistics.json
+
+const (
+ prioClientConnectionsCount = module.Priority + iota
+ prioClientConnectionsRate
+ prioServerConnectionsCount
+ prioServerConnectionsRate
+ prioBackendsTraffic
+ prioFrontendsTraffic
+ prioActiveTransactionsCount
+ prioQuestionsRate
+ prioSlowQueriesRate
+ prioQueriesRate
+ prioBackendStatementsCount
+ prioBackendStatementsRate
+ prioFrontendStatementsCount
+ prioFrontendStatementsRate
+ prioCachedStatementsCount
+ prioQueryCacheEntriesCount
+ prioQueryCacheIO
+ prioQueryCacheRequestsRate
+ prioQueryCacheMemoryUsed
+ prioMySQLMonitorWorkersCount
+ prioMySQLMonitorWorkersRate
+ prioMySQLMonitorConnectChecksRate
+ prioMySQLMonitorPingChecksRate
+ prioMySQLMonitorReadOnlyChecksRate
+ prioMySQLMonitorReplicationLagChecksRate
+ prioJemallocMemoryUsed
+ prioMemoryUsed
+ prioMySQLCommandExecutionsRate
+ prioMySQLCommandExecutionTime
+ prioMySQLCommandExecutionDurationHistogram
+ prioMySQLUserConnectionsUtilization
+ prioMySQLUserConnectionsCount
+ prioBackendStatus
+ prioBackendConnectionsUsage
+ prioBackendConnectionsRate
+ prioBackendQueriesRateRate
+ prioBackendTraffic
+ prioBackendLatency
+ prioUptime
+)
+
+var (
+ baseCharts = module.Charts{
+ clientConnectionsCountChart.Copy(),
+ clientConnectionsRateChart.Copy(),
+ serverConnectionsCountChart.Copy(),
+ serverConnectionsRateChart.Copy(),
+ backendsTrafficChart.Copy(),
+ frontendsTrafficChart.Copy(),
+ activeTransactionsCountChart.Copy(),
+ questionsRateChart.Copy(),
+ slowQueriesRateChart.Copy(),
+ queriesRateChart.Copy(),
+ backendStatementsCountChart.Copy(),
+ backendStatementsRateChart.Copy(),
+ clientStatementsCountChart.Copy(),
+ clientStatementsRateChart.Copy(),
+ cachedStatementsCountChart.Copy(),
+ queryCacheEntriesCountChart.Copy(),
+ queryCacheIOChart.Copy(),
+ queryCacheRequestsRateChart.Copy(),
+ queryCacheMemoryUsedChart.Copy(),
+ mySQLMonitorWorkersCountChart.Copy(),
+ mySQLMonitorWorkersRateChart.Copy(),
+ mySQLMonitorConnectChecksRateChart.Copy(),
+ mySQLMonitorPingChecksRateChart.Copy(),
+ mySQLMonitorReadOnlyChecksRateChart.Copy(),
+ mySQLMonitorReplicationLagChecksRateChart.Copy(),
+ jemallocMemoryUsedChart.Copy(),
+ memoryUsedCountChart.Copy(),
+ uptimeChart.Copy(),
+ }
+
+ clientConnectionsCountChart = module.Chart{
+ ID: "client_connections_count",
+ Title: "Client connections",
+ Units: "connections",
+ Fam: "connections",
+ Ctx: "proxysql.client_connections_count",
+ Priority: prioClientConnectionsCount,
+ Dims: module.Dims{
+ {ID: "Client_Connections_connected", Name: "connected"},
+ {ID: "Client_Connections_non_idle", Name: "non_idle"},
+ {ID: "Client_Connections_hostgroup_locked", Name: "hostgroup_locked"},
+ },
+ }
+ clientConnectionsRateChart = module.Chart{
+ ID: "client_connections_rate",
+ Title: "Client connections rate",
+ Units: "connections/s",
+ Fam: "connections",
+ Ctx: "proxysql.client_connections_rate",
+ Priority: prioClientConnectionsRate,
+ Dims: module.Dims{
+ {ID: "Client_Connections_created", Name: "created", Algo: module.Incremental},
+ {ID: "Client_Connections_aborted", Name: "aborted", Algo: module.Incremental},
+ },
+ }
+
+ serverConnectionsCountChart = module.Chart{
+ ID: "server_connections_count",
+ Title: "Server connections",
+ Units: "connections",
+ Fam: "connections",
+ Ctx: "proxysql.server_connections_count",
+ Priority: prioServerConnectionsCount,
+ Dims: module.Dims{
+ {ID: "Server_Connections_connected", Name: "connected"},
+ },
+ }
+ serverConnectionsRateChart = module.Chart{
+ ID: "server_connections_rate",
+ Title: "Server connections rate",
+ Units: "connections/s",
+ Fam: "connections",
+ Ctx: "proxysql.server_connections_rate",
+ Priority: prioServerConnectionsRate,
+ Dims: module.Dims{
+ {ID: "Server_Connections_created", Name: "created", Algo: module.Incremental},
+ {ID: "Server_Connections_aborted", Name: "aborted", Algo: module.Incremental},
+ {ID: "Server_Connections_delayed", Name: "delayed", Algo: module.Incremental},
+ },
+ }
+
+ backendsTrafficChart = module.Chart{
+ ID: "backends_traffic",
+ Title: "Backends traffic",
+ Units: "B/s",
+ Fam: "traffic",
+ Ctx: "proxysql.backends_traffic",
+ Priority: prioBackendsTraffic,
+ Dims: module.Dims{
+ {ID: "Queries_backends_bytes_recv", Name: "recv", Algo: module.Incremental},
+ {ID: "Queries_backends_bytes_sent", Name: "sent", Algo: module.Incremental},
+ },
+ }
+ frontendsTrafficChart = module.Chart{
+ ID: "clients_traffic",
+ Title: "Clients traffic",
+ Units: "B/s",
+ Fam: "traffic",
+ Ctx: "proxysql.clients_traffic",
+ Priority: prioFrontendsTraffic,
+ Dims: module.Dims{
+ {ID: "Queries_frontends_bytes_recv", Name: "recv", Algo: module.Incremental},
+ {ID: "Queries_frontends_bytes_sent", Name: "sent", Algo: module.Incremental},
+ },
+ }
+
+ activeTransactionsCountChart = module.Chart{
+ ID: "active_transactions_count",
+ Title: "Client connections that are currently processing a transaction",
+ Units: "transactions",
+ Fam: "transactions",
+ Ctx: "proxysql.active_transactions_count",
+ Priority: prioActiveTransactionsCount,
+ Dims: module.Dims{
+ {ID: "Active_Transactions", Name: "active"},
+ },
+ }
+ questionsRateChart = module.Chart{
+ ID: "questions_rate",
+ Title: "Client requests / statements executed",
+ Units: "questions/s",
+ Fam: "queries",
+ Ctx: "proxysql.questions_rate",
+ Priority: prioQuestionsRate,
+ Dims: module.Dims{
+ {ID: "Questions", Name: "questions", Algo: module.Incremental},
+ },
+ }
+ slowQueriesRateChart = module.Chart{
+ ID: "slow_queries_rate",
+ Title: "Slow queries",
+ Units: "queries/s",
+ Fam: "queries",
+ Ctx: "proxysql.slow_queries_rate",
+ Priority: prioSlowQueriesRate,
+ Dims: module.Dims{
+ {ID: "Slow_queries", Name: "slow", Algo: module.Incremental},
+ },
+ }
+ queriesRateChart = module.Chart{
+ ID: "queries_rate",
+ Title: "Queries rate",
+ Units: "queries/s",
+ Fam: "queries",
+ Ctx: "proxysql.queries_rate",
+ Priority: prioQueriesRate,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "Com_autocommit", Name: "autocommit", Algo: module.Incremental},
+ {ID: "Com_autocommit_filtered", Name: "autocommit_filtered", Algo: module.Incremental},
+ {ID: "Com_commit", Name: "commit", Algo: module.Incremental},
+ {ID: "Com_commit_filtered", Name: "commit_filtered", Algo: module.Incremental},
+ {ID: "Com_rollback", Name: "rollback", Algo: module.Incremental},
+ {ID: "Com_rollback_filtered", Name: "rollback_filtered", Algo: module.Incremental},
+ {ID: "Com_backend_change_user", Name: "backend_change_user", Algo: module.Incremental},
+ {ID: "Com_backend_init_db", Name: "backend_init_db", Algo: module.Incremental},
+ {ID: "Com_backend_set_names", Name: "backend_set_names", Algo: module.Incremental},
+ {ID: "Com_frontend_init_db", Name: "frontend_init_db", Algo: module.Incremental},
+ {ID: "Com_frontend_set_names", Name: "frontend_set_names", Algo: module.Incremental},
+ {ID: "Com_frontend_use_db", Name: "frontend_use_db", Algo: module.Incremental},
+ },
+ }
+
+ backendStatementsCountChart = module.Chart{
+ ID: "backend_statements_count",
+ Title: "Statements available across all backend connections",
+ Units: "statements",
+ Fam: "statements",
+ Ctx: "proxysql.backend_statements_count",
+ Priority: prioBackendStatementsCount,
+ Dims: module.Dims{
+ {ID: "Stmt_Server_Active_Total", Name: "total"},
+ {ID: "Stmt_Server_Active_Unique", Name: "unique"},
+ },
+ }
+ backendStatementsRateChart = module.Chart{
+ ID: "backend_statements_rate",
+ Title: "Statements executed against the backends",
+ Units: "statements/s",
+ Fam: "statements",
+ Ctx: "proxysql.backend_statements_rate",
+ Priority: prioBackendStatementsRate,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "Com_backend_stmt_prepare", Name: "prepare", Algo: module.Incremental},
+ {ID: "Com_backend_stmt_execute", Name: "execute", Algo: module.Incremental},
+ {ID: "Com_backend_stmt_close", Name: "close", Algo: module.Incremental},
+ },
+ }
+ clientStatementsCountChart = module.Chart{
+ ID: "client_statements_count",
+ Title: "Statements that are in use by clients",
+ Units: "statements",
+ Fam: "statements",
+ Ctx: "proxysql.client_statements_count",
+ Priority: prioFrontendStatementsCount,
+ Dims: module.Dims{
+ {ID: "Stmt_Client_Active_Total", Name: "total"},
+ {ID: "Stmt_Client_Active_Unique", Name: "unique"},
+ },
+ }
+ clientStatementsRateChart = module.Chart{
+ ID: "client_statements_rate",
+ Title: "Statements executed by clients",
+ Units: "statements/s",
+ Fam: "statements",
+ Ctx: "proxysql.client_statements_rate",
+ Priority: prioFrontendStatementsRate,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "Com_frontend_stmt_prepare", Name: "prepare", Algo: module.Incremental},
+ {ID: "Com_frontend_stmt_execute", Name: "execute", Algo: module.Incremental},
+ {ID: "Com_frontend_stmt_close", Name: "close", Algo: module.Incremental},
+ },
+ }
+ cachedStatementsCountChart = module.Chart{
+ ID: "cached_statements_count",
+ Title: "Global prepared statements",
+ Units: "statements",
+ Fam: "statements",
+ Ctx: "proxysql.cached_statements_count",
+ Priority: prioCachedStatementsCount,
+ Dims: module.Dims{
+ {ID: "Stmt_Cached", Name: "cached"},
+ },
+ }
+
+ queryCacheEntriesCountChart = module.Chart{
+ ID: "query_cache_entries_count",
+ Title: "Query Cache entries",
+ Units: "entries",
+ Fam: "query cache",
+ Ctx: "proxysql.query_cache_entries_count",
+ Priority: prioQueryCacheEntriesCount,
+ Dims: module.Dims{
+ {ID: "Query_Cache_Entries", Name: "entries"},
+ },
+ }
+ queryCacheMemoryUsedChart = module.Chart{
+ ID: "query_cache_memory_used",
+ Title: "Query Cache memory used",
+ Units: "B",
+ Fam: "query cache",
+ Ctx: "proxysql.query_cache_memory_used",
+ Priority: prioQueryCacheMemoryUsed,
+ Dims: module.Dims{
+ {ID: "Query_Cache_Memory_bytes", Name: "used"},
+ },
+ }
+ queryCacheIOChart = module.Chart{
+ ID: "query_cache_io",
+ Title: "Query Cache I/O",
+ Units: "B/s",
+ Fam: "query cache",
+ Ctx: "proxysql.query_cache_io",
+ Priority: prioQueryCacheIO,
+ Dims: module.Dims{
+ {ID: "Query_Cache_bytes_IN", Name: "in", Algo: module.Incremental},
+ {ID: "Query_Cache_bytes_OUT", Name: "out", Algo: module.Incremental},
+ },
+ }
+ queryCacheRequestsRateChart = module.Chart{
+ ID: "query_cache_requests_rate",
+ Title: "Query Cache requests",
+ Units: "requests/s",
+ Fam: "query cache",
+ Ctx: "proxysql.query_cache_requests_rate",
+ Priority: prioQueryCacheRequestsRate,
+ Dims: module.Dims{
+ {ID: "Query_Cache_count_GET", Name: "read", Algo: module.Incremental},
+ {ID: "Query_Cache_count_SET", Name: "write", Algo: module.Incremental},
+ {ID: "Query_Cache_count_GET_OK", Name: "read_success", Algo: module.Incremental},
+ },
+ }
+
+ mySQLMonitorWorkersCountChart = module.Chart{
+ ID: "mysql_monitor_workers_count",
+ Title: "MySQL monitor workers",
+ Units: "threads",
+ Fam: "monitor",
+ Ctx: "proxysql.mysql_monitor_workers_count",
+ Priority: prioMySQLMonitorWorkersCount,
+ Dims: module.Dims{
+ {ID: "MySQL_Monitor_Workers", Name: "workers"},
+ {ID: "MySQL_Monitor_Workers_Aux", Name: "auxiliary"},
+ },
+ }
+ mySQLMonitorWorkersRateChart = module.Chart{
+ ID: "mysql_monitor_workers_rate",
+ Title: "MySQL monitor workers rate",
+ Units: "workers/s",
+ Fam: "monitor",
+ Ctx: "proxysql.mysql_monitor_workers_rate",
+ Priority: prioMySQLMonitorWorkersRate,
+ Dims: module.Dims{
+ {ID: "MySQL_Monitor_Workers_Started", Name: "started", Algo: module.Incremental},
+ },
+ }
+ mySQLMonitorConnectChecksRateChart = module.Chart{
+ ID: "mysql_monitor_connect_checks_rate",
+ Title: "MySQL monitor connect checks",
+ Units: "checks/s",
+ Fam: "monitor",
+ Ctx: "proxysql.mysql_monitor_connect_checks_rate",
+ Priority: prioMySQLMonitorConnectChecksRate,
+ Dims: module.Dims{
+ {ID: "MySQL_Monitor_connect_check_OK", Name: "succeed", Algo: module.Incremental},
+ {ID: "MySQL_Monitor_connect_check_ERR", Name: "failed", Algo: module.Incremental},
+ },
+ }
+ mySQLMonitorPingChecksRateChart = module.Chart{
+ ID: "mysql_monitor_ping_checks_rate",
+ Title: "MySQL monitor ping checks",
+ Units: "checks/s",
+ Fam: "monitor",
+ Ctx: "proxysql.mysql_monitor_ping_checks_rate",
+ Priority: prioMySQLMonitorPingChecksRate,
+ Dims: module.Dims{
+ {ID: "MySQL_Monitor_ping_check_OK", Name: "succeed", Algo: module.Incremental},
+ {ID: "MySQL_Monitor_ping_check_ERR", Name: "failed", Algo: module.Incremental},
+ },
+ }
+ mySQLMonitorReadOnlyChecksRateChart = module.Chart{
+ ID: "mysql_monitor_read_only_checks_rate",
+ Title: "MySQL monitor read only checks",
+ Units: "checks/s",
+ Fam: "monitor",
+ Ctx: "proxysql.mysql_monitor_read_only_checks_rate",
+ Priority: prioMySQLMonitorReadOnlyChecksRate,
+ Dims: module.Dims{
+ {ID: "MySQL_Monitor_read_only_check_OK", Name: "succeed", Algo: module.Incremental},
+ {ID: "MySQL_Monitor_read_only_check_ERR", Name: "failed", Algo: module.Incremental},
+ },
+ }
+ mySQLMonitorReplicationLagChecksRateChart = module.Chart{
+ ID: "mysql_monitor_replication_lag_checks_rate",
+ Title: "MySQL monitor replication lag checks",
+ Units: "checks/s",
+ Fam: "monitor",
+ Ctx: "proxysql.mysql_monitor_replication_lag_checks_rate",
+ Priority: prioMySQLMonitorReplicationLagChecksRate,
+ Dims: module.Dims{
+ {ID: "MySQL_Monitor_replication_lag_check_OK", Name: "succeed", Algo: module.Incremental},
+ {ID: "MySQL_Monitor_replication_lag_check_ERR", Name: "failed", Algo: module.Incremental},
+ },
+ }
+
+ jemallocMemoryUsedChart = module.Chart{
+ ID: "jemalloc_memory_used",
+ Title: "Jemalloc used memory",
+ Units: "bytes",
+ Fam: "memory",
+ Ctx: "proxysql.jemalloc_memory_used",
+ Type: module.Stacked,
+ Priority: prioJemallocMemoryUsed,
+ Dims: module.Dims{
+ {ID: "jemalloc_active", Name: "active"},
+ {ID: "jemalloc_allocated", Name: "allocated"},
+ {ID: "jemalloc_mapped", Name: "mapped"},
+ {ID: "jemalloc_metadata", Name: "metadata"},
+ {ID: "jemalloc_resident", Name: "resident"},
+ {ID: "jemalloc_retained", Name: "retained"},
+ },
+ }
+ memoryUsedCountChart = module.Chart{
+ ID: "memory_used",
+ Title: "Memory used",
+ Units: "bytes",
+ Fam: "memory",
+ Ctx: "proxysql.memory_used",
+ Priority: prioMemoryUsed,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "Auth_memory", Name: "auth"},
+ {ID: "SQLite3_memory_bytes", Name: "sqlite3"},
+ {ID: "query_digest_memory", Name: "query_digest"},
+ {ID: "mysql_query_rules_memory", Name: "query_rules"},
+ {ID: "mysql_firewall_users_table", Name: "firewall_users_table"},
+ {ID: "mysql_firewall_users_config", Name: "firewall_users_config"},
+ {ID: "mysql_firewall_rules_table", Name: "firewall_rules_table"},
+ {ID: "mysql_firewall_rules_config", Name: "firewall_rules_config"},
+ {ID: "stack_memory_mysql_threads", Name: "mysql_threads"},
+ {ID: "stack_memory_admin_threads", Name: "admin_threads"},
+ {ID: "stack_memory_cluster_threads", Name: "cluster_threads"},
+ },
+ }
+ uptimeChart = module.Chart{
+ ID: "proxysql_uptime",
+ Title: "Uptime",
+ Units: "seconds",
+ Fam: "uptime",
+ Ctx: "proxysql.uptime",
+ Priority: prioUptime,
+ Dims: module.Dims{
+ {ID: "ProxySQL_Uptime", Name: "uptime"},
+ },
+ }
+)
+
+var (
+ mySQLCommandChartsTmpl = module.Charts{
+ mySQLCommandExecutionRateChartTmpl.Copy(),
+ mySQLCommandExecutionTimeChartTmpl.Copy(),
+ mySQLCommandExecutionDurationHistogramChartTmpl.Copy(),
+ }
+
+ mySQLCommandExecutionRateChartTmpl = module.Chart{
+ ID: "mysql_command_%s_execution_rate",
+ Title: "MySQL command execution",
+ Units: "commands/s",
+ Fam: "command exec",
+ Ctx: "proxysql.mysql_command_execution_rate",
+ Priority: prioMySQLCommandExecutionsRate,
+ Dims: module.Dims{
+ {ID: "mysql_command_%s_Total_cnt", Name: "commands", Algo: module.Incremental},
+ },
+ }
+ mySQLCommandExecutionTimeChartTmpl = module.Chart{
+ ID: "mysql_command_%s_execution_time",
+ Title: "MySQL command execution time",
+ Units: "microseconds",
+ Fam: "command exec time",
+ Ctx: "proxysql.mysql_command_execution_time",
+ Priority: prioMySQLCommandExecutionTime,
+ Dims: module.Dims{
+ {ID: "mysql_command_%s_Total_Time_us", Name: "time", Algo: module.Incremental},
+ },
+ }
+ mySQLCommandExecutionDurationHistogramChartTmpl = module.Chart{
+ ID: "mysql_command_%s_execution_duration",
+ Title: "MySQL command execution duration histogram",
+ Units: "commands/s",
+ Fam: "command exec duration",
+ Ctx: "proxysql.mysql_command_execution_duration",
+ Type: module.Stacked,
+ Priority: prioMySQLCommandExecutionDurationHistogram,
+ Dims: module.Dims{
+ {ID: "mysql_command_%s_cnt_100us", Name: "100us", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_500us", Name: "500us", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_1ms", Name: "1ms", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_5ms", Name: "5ms", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_10ms", Name: "10ms", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_50ms", Name: "50ms", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_100ms", Name: "100ms", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_500ms", Name: "500ms", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_1s", Name: "1s", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_5s", Name: "5s", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_10s", Name: "10s", Algo: module.Incremental},
+ {ID: "mysql_command_%s_cnt_INFs", Name: "+Inf", Algo: module.Incremental},
+ },
+ }
+)
+
+func newMySQLCommandCountersCharts(command string) *module.Charts {
+ charts := mySQLCommandChartsTmpl.Copy()
+
+ for _, chart := range *charts {
+ chart.ID = fmt.Sprintf(chart.ID, strings.ToLower(command))
+ chart.Labels = []module.Label{{Key: "command", Value: command}}
+ for _, dim := range chart.Dims {
+ dim.ID = fmt.Sprintf(dim.ID, command)
+ }
+ }
+
+ return charts
+}
+
+func (p *ProxySQL) addMySQLCommandCountersCharts(command string) {
+ charts := newMySQLCommandCountersCharts(command)
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *ProxySQL) removeMySQLCommandCountersCharts(command string) {
+ prefix := "mysql_command_" + strings.ToLower(command)
+
+ for _, chart := range *p.Charts() {
+ if strings.HasPrefix(chart.ID, prefix) {
+ chart.MarkRemove()
+ chart.MarkNotCreated()
+ }
+ }
+}
+
+var (
+ mySQLUserChartsTmpl = module.Charts{
+ mySQLUserConnectionsUtilizationChartTmpl.Copy(),
+ mySQLUserConnectionsCountChartTmpl.Copy(),
+ }
+
+ mySQLUserConnectionsUtilizationChartTmpl = module.Chart{
+ ID: "mysql_user_%s_connections_utilization",
+ Title: "MySQL user connections utilization",
+ Units: "percentage",
+ Fam: "user conns",
+ Ctx: "proxysql.mysql_user_connections_utilization",
+ Priority: prioMySQLUserConnectionsUtilization,
+ Dims: module.Dims{
+ {ID: "mysql_user_%s_frontend_connections_utilization", Name: "used"},
+ },
+ }
+ mySQLUserConnectionsCountChartTmpl = module.Chart{
+ ID: "mysql_user_%s_connections_count",
+ Title: "MySQL user connections used",
+ Units: "connections",
+ Fam: "user conns",
+ Ctx: "proxysql.mysql_user_connections_count",
+ Priority: prioMySQLUserConnectionsCount,
+ Dims: module.Dims{
+ {ID: "mysql_user_%s_frontend_connections", Name: "used"},
+ },
+ }
+)
+
+func newMySQLUserCharts(username string) *module.Charts {
+ charts := mySQLUserChartsTmpl.Copy()
+
+ for _, chart := range *charts {
+ chart.ID = fmt.Sprintf(chart.ID, username)
+ chart.Labels = []module.Label{{Key: "user", Value: username}}
+ for _, dim := range chart.Dims {
+ dim.ID = fmt.Sprintf(dim.ID, username)
+ }
+ }
+
+ return charts
+}
+
+func (p *ProxySQL) addMySQLUsersCharts(username string) {
+ charts := newMySQLUserCharts(username)
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *ProxySQL) removeMySQLUserCharts(user string) {
+ prefix := "mysql_user_" + user
+
+ for _, chart := range *p.Charts() {
+ if strings.HasPrefix(chart.ID, prefix) {
+ chart.MarkRemove()
+ chart.MarkNotCreated()
+ }
+ }
+}
+
+var (
+ backendChartsTmpl = module.Charts{
+ backendStatusChartTmpl.Copy(),
+ backendConnectionsUsageChartTmpl.Copy(),
+ backendConnectionsRateChartTmpl.Copy(),
+ backendQueriesRateRateChartTmpl.Copy(),
+ backendTrafficChartTmpl.Copy(),
+ backendLatencyChartTmpl.Copy(),
+ }
+
+ backendStatusChartTmpl = module.Chart{
+ ID: "backend_%s_status",
+ Title: "Backend status",
+ Units: "status",
+ Fam: "backend status",
+ Ctx: "proxysql.backend_status",
+ Priority: prioBackendStatus,
+ Dims: module.Dims{
+ {ID: "backend_%s_status_ONLINE", Name: "online"},
+ {ID: "backend_%s_status_SHUNNED", Name: "shunned"},
+ {ID: "backend_%s_status_OFFLINE_SOFT", Name: "offline_soft"},
+ {ID: "backend_%s_status_OFFLINE_HARD", Name: "offline_hard"},
+ },
+ }
+ backendConnectionsUsageChartTmpl = module.Chart{
+ ID: "backend_%s_connections_usage",
+ Title: "Backend connections usage",
+ Units: "connections",
+ Fam: "backend conns usage",
+ Ctx: "proxysql.backend_connections_usage",
+ Type: module.Stacked,
+ Priority: prioBackendConnectionsUsage,
+ Dims: module.Dims{
+ {ID: "backend_%s_ConnFree", Name: "free"},
+ {ID: "backend_%s_ConnUsed", Name: "used"},
+ },
+ }
+ backendConnectionsRateChartTmpl = module.Chart{
+ ID: "backend_%s_connections_rate",
+ Title: "Backend connections established",
+ Units: "connections/s",
+ Fam: "backend conns established",
+ Ctx: "proxysql.backend_connections_rate",
+ Priority: prioBackendConnectionsRate,
+ Dims: module.Dims{
+ {ID: "backend_%s_ConnOK", Name: "succeed", Algo: module.Incremental},
+ {ID: "backend_%s_ConnERR", Name: "failed", Algo: module.Incremental},
+ },
+ }
+ backendQueriesRateRateChartTmpl = module.Chart{
+ ID: "backend_%s_queries_rate",
+ Title: "Backend queries",
+ Units: "queries/s",
+ Fam: "backend queries",
+ Ctx: "proxysql.backend_queries_rate",
+ Priority: prioBackendQueriesRateRate,
+ Dims: module.Dims{
+ {ID: "backend_%s_Queries", Name: "queries", Algo: module.Incremental},
+ },
+ }
+ backendTrafficChartTmpl = module.Chart{
+ ID: "backend_%s_traffic",
+ Title: "Backend traffic",
+ Units: "B/s",
+ Fam: "backend traffic",
+ Ctx: "proxysql.backend_traffic",
+ Priority: prioBackendTraffic,
+ Dims: module.Dims{
+ {ID: "backend_%s_Bytes_data_recv", Name: "recv", Algo: module.Incremental},
+ {ID: "backend_%s_Bytes_data_sent", Name: "sent", Algo: module.Incremental},
+ },
+ }
+ backendLatencyChartTmpl = module.Chart{
+ ID: "backend_%s_latency",
+ Title: "Backend latency",
+ Units: "microseconds",
+ Fam: "backend latency",
+ Ctx: "proxysql.backend_latency",
+ Priority: prioBackendLatency,
+ Dims: module.Dims{
+ {ID: "backend_%s_Latency_us", Name: "latency"},
+ },
+ }
+)
+
+func newBackendCharts(hg, host, port string) *module.Charts {
+ charts := backendChartsTmpl.Copy()
+
+ for _, chart := range *charts {
+ chart.ID = fmt.Sprintf(chart.ID, backendID(hg, host, port))
+ chart.Labels = []module.Label{
+ {Key: "host", Value: host},
+ {Key: "port", Value: port},
+ }
+ for _, dim := range chart.Dims {
+ dim.ID = fmt.Sprintf(dim.ID, backendID(hg, host, port))
+ }
+ }
+
+ return charts
+}
+
+func (p *ProxySQL) addBackendCharts(hg, host, port string) {
+ charts := newBackendCharts(hg, host, port)
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *ProxySQL) removeBackendCharts(hg, host, port string) {
+ prefix := "backend_" + backendID(hg, host, port)
+
+ for _, chart := range *p.Charts() {
+ if strings.HasPrefix(chart.ID, prefix) {
+ chart.MarkRemove()
+ chart.MarkNotCreated()
+ }
+ }
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/collect.go b/src/go/collectors/go.d.plugin/modules/proxysql/collect.go
new file mode 100644
index 000000000..dfc559a97
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/collect.go
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package proxysql
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const (
+ queryVersion = "select version();"
+ queryStatsMySQLGlobal = "SELECT * FROM stats_mysql_global;"
+ queryStatsMySQLMemoryMetrics = "SELECT * FROM stats_memory_metrics;"
+ queryStatsMySQLCommandsCounters = "SELECT * FROM stats_mysql_commands_counters;"
+ queryStatsMySQLUsers = "SELECT * FROM stats_mysql_users;"
+ queryStatsMySQLConnectionPool = "SELECT * FROM stats_mysql_connection_pool;"
+)
+
+func (p *ProxySQL) collect() (map[string]int64, error) {
+ if p.db == nil {
+ if err := p.openConnection(); err != nil {
+ return nil, err
+ }
+ }
+
+ p.once.Do(func() {
+ v, err := p.doQueryVersion()
+ if err != nil {
+ p.Warningf("error on querying version: %v", err)
+ } else {
+ p.Debugf("connected to ProxySQL version: %s", v)
+ }
+ })
+
+ p.cache.reset()
+
+ mx := make(map[string]int64)
+
+ if err := p.collectStatsMySQLGlobal(mx); err != nil {
+ return nil, fmt.Errorf("error on collecting mysql global status: %v", err)
+ }
+ if err := p.collectStatsMySQLMemoryMetrics(mx); err != nil {
+ return nil, fmt.Errorf("error on collecting memory metrics: %v", err)
+ }
+ if err := p.collectStatsMySQLCommandsCounters(mx); err != nil {
+ return nil, fmt.Errorf("error on collecting mysql command counters: %v", err)
+ }
+ if err := p.collectStatsMySQLUsers(mx); err != nil {
+ return nil, fmt.Errorf("error on collecting mysql users: %v", err)
+ }
+ if err := p.collectStatsMySQLConnectionPool(mx); err != nil {
+ return nil, fmt.Errorf("error on collecting mysql connection pool: %v", err)
+ }
+
+ p.updateCharts()
+
+ return mx, nil
+}
+
+func (p *ProxySQL) doQueryVersion() (string, error) {
+ q := queryVersion
+ p.Debugf("executing query: '%s'", q)
+
+ var v string
+ if err := p.doQueryRow(q, &v); err != nil {
+ return "", err
+ }
+
+ return v, nil
+}
+
+func (p *ProxySQL) collectStatsMySQLGlobal(mx map[string]int64) error {
+ // https://proxysql.com/documentation/stats-statistics/#stats_mysql_global
+ q := queryStatsMySQLGlobal
+ p.Debugf("executing query: '%s'", q)
+
+ var name string
+ return p.doQuery(q, func(column, value string, rowEnd bool) {
+ switch column {
+ case "Variable_Name":
+ name = value
+ case "Variable_Value":
+ mx[name] = parseInt(value)
+ }
+ })
+}
+
+func (p *ProxySQL) collectStatsMySQLMemoryMetrics(mx map[string]int64) error {
+ // https://proxysql.com/documentation/stats-statistics/#stats_mysql_memory_metrics
+ q := queryStatsMySQLMemoryMetrics
+ p.Debugf("executing query: '%s'", q)
+
+ var name string
+ return p.doQuery(q, func(column, value string, rowEnd bool) {
+ switch column {
+ case "Variable_Name":
+ name = value
+ case "Variable_Value":
+ mx[name] = parseInt(value)
+ }
+ })
+}
+
+func (p *ProxySQL) collectStatsMySQLCommandsCounters(mx map[string]int64) error {
+ // https://proxysql.com/documentation/stats-statistics/#stats_mysql_commands_counters
+ q := queryStatsMySQLCommandsCounters
+ p.Debugf("executing query: '%s'", q)
+
+ var command string
+ return p.doQuery(q, func(column, value string, rowEnd bool) {
+ switch column {
+ case "Command":
+ command = value
+ p.cache.getCommand(command).updated = true
+ default:
+ mx["mysql_command_"+command+"_"+column] = parseInt(value)
+ }
+ })
+}
+
+func (p *ProxySQL) collectStatsMySQLUsers(mx map[string]int64) error {
+ // https://proxysql.com/documentation/stats-statistics/#stats_mysql_users
+ q := queryStatsMySQLUsers
+ p.Debugf("executing query: '%s'", q)
+
+ var user string
+ var used int64
+ return p.doQuery(q, func(column, value string, rowEnd bool) {
+ switch column {
+ case "username":
+ user = value
+ p.cache.getUser(user).updated = true
+ case "frontend_connections":
+ used = parseInt(value)
+ mx["mysql_user_"+user+"_"+column] = used
+ case "frontend_max_connections":
+ mx["mysql_user_"+user+"_frontend_connections_utilization"] = calcPercentage(used, parseInt(value))
+ }
+ })
+}
+
+func (p *ProxySQL) collectStatsMySQLConnectionPool(mx map[string]int64) error {
+ // https://proxysql.com/documentation/stats-statistics/#stats_mysql_connection_pool
+ q := queryStatsMySQLConnectionPool
+ p.Debugf("executing query: '%s'", q)
+
+ var hg, host, port string
+ var px string
+ return p.doQuery(q, func(column, value string, rowEnd bool) {
+ switch column {
+ case "hg", "hostgroup":
+ hg = value
+ case "srv_host":
+ host = value
+ case "srv_port":
+ port = value
+ p.cache.getBackend(hg, host, port).updated = true
+ px = "backend_" + backendID(hg, host, port) + "_"
+ case "status":
+ mx[px+"status_ONLINE"] = boolToInt(value == "1")
+ mx[px+"status_SHUNNED"] = boolToInt(value == "2")
+ mx[px+"status_OFFLINE_SOFT"] = boolToInt(value == "3")
+ mx[px+"status_OFFLINE_HARD"] = boolToInt(value == "4")
+ default:
+ mx[px+column] = parseInt(value)
+ }
+ })
+}
+
+func (p *ProxySQL) updateCharts() {
+ for k, m := range p.cache.commands {
+ if !m.updated {
+ delete(p.cache.commands, k)
+ p.removeMySQLCommandCountersCharts(m.command)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addMySQLCommandCountersCharts(m.command)
+ }
+ }
+ for k, m := range p.cache.users {
+ if !m.updated {
+ delete(p.cache.users, k)
+ p.removeMySQLUserCharts(m.user)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addMySQLUsersCharts(m.user)
+ }
+ }
+ for k, m := range p.cache.backends {
+ if !m.updated {
+ delete(p.cache.backends, k)
+ p.removeBackendCharts(m.hg, m.host, m.port)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addBackendCharts(m.hg, m.host, m.port)
+ }
+ }
+}
+
+func (p *ProxySQL) openConnection() error {
+ db, err := sql.Open("mysql", p.DSN)
+ if err != nil {
+ return fmt.Errorf("error on opening a connection with the proxysql instance [%s]: %v", p.DSN, err)
+ }
+
+ db.SetConnMaxLifetime(10 * time.Minute)
+
+ if err := db.Ping(); err != nil {
+ _ = db.Close()
+ return fmt.Errorf("error on pinging the proxysql instance [%s]: %v", p.DSN, err)
+ }
+
+ p.db = db
+ return nil
+}
+
+func (p *ProxySQL) doQueryRow(query string, v any) error {
+ ctx, cancel := context.WithTimeout(context.Background(), p.Timeout.Duration())
+ defer cancel()
+
+ return p.db.QueryRowContext(ctx, query).Scan(v)
+}
+
+func (p *ProxySQL) doQuery(query string, assign func(column, value string, rowEnd bool)) error {
+ ctx, cancel := context.WithTimeout(context.Background(), p.Timeout.Duration())
+ defer cancel()
+
+ rows, err := p.db.QueryContext(ctx, query)
+ if err != nil {
+ return err
+ }
+ defer func() { _ = rows.Close() }()
+
+ return readRows(rows, assign)
+}
+
+func readRows(rows *sql.Rows, assign func(column, value string, rowEnd bool)) error {
+ columns, err := rows.Columns()
+ if err != nil {
+ return err
+ }
+
+ values := makeValues(len(columns))
+
+ for rows.Next() {
+ if err := rows.Scan(values...); err != nil {
+ return err
+ }
+ for i, l := 0, len(values); i < l; i++ {
+ assign(columns[i], valueToString(values[i]), i == l-1)
+ }
+ }
+ return rows.Err()
+}
+
+func valueToString(value any) string {
+ v, ok := value.(*sql.NullString)
+ if !ok || !v.Valid {
+ return ""
+ }
+ return v.String
+}
+
+func makeValues(size int) []any {
+ vs := make([]any, size)
+ for i := range vs {
+ vs[i] = &sql.NullString{}
+ }
+ return vs
+}
+
+func parseInt(value string) int64 {
+ v, _ := strconv.ParseInt(value, 10, 64)
+ return v
+}
+
+func calcPercentage(value, total int64) (v int64) {
+ if total == 0 {
+ return 0
+ }
+ if v = value * 100 / total; v < 0 {
+ v = -v
+ }
+ return v
+}
+
+func boolToInt(v bool) int64 {
+ if v {
+ return 1
+ }
+ return 0
+}
+
+func backendID(hg, host, port string) string {
+ hg = strings.ReplaceAll(strings.ToLower(hg), " ", "_")
+ host = strings.ReplaceAll(host, ".", "_")
+ return hg + "_" + host + "_" + port
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/config_schema.json b/src/go/collectors/go.d.plugin/modules/proxysql/config_schema.json
new file mode 100644
index 000000000..c0c880a2e
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/config_schema.json
@@ -0,0 +1,47 @@
+{
+ "jsonSchema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "ProxySQL collector configuration.",
+ "type": "object",
+ "properties": {
+ "update_every": {
+ "title": "Update every",
+ "description": "Data collection interval, measured in seconds.",
+ "type": "integer",
+ "minimum": 1,
+ "default": 1
+ },
+ "dsn": {
+ "title": "DSN",
+ "description": "ProxySQL server [Data Source Name (DSN)](https://github.com/go-sql-driver/mysql#dsn-data-source-name) specifying the connection details.",
+ "type": "string",
+ "default": "stats:stats@tcp(127.0.0.1:6032)/"
+ },
+ "timeout": {
+ "title": "Timeout",
+ "description": "Timeout for queries, in seconds.",
+ "type": "number",
+ "minimum": 0.5,
+ "default": 1
+ }
+ },
+ "required": [
+ "dsn"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^name$": {}
+ }
+ },
+ "uiSchema": {
+ "uiOptions": {
+ "fullPage": true
+ },
+ "dsn": {
+ "ui:placeholder": "username:password@protocol(address)/dbname"
+ },
+ "timeout": {
+ "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
+ }
+ }
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/integrations/proxysql.md b/src/go/collectors/go.d.plugin/modules/proxysql/integrations/proxysql.md
new file mode 100644
index 000000000..2cfb0b065
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/integrations/proxysql.md
@@ -0,0 +1,274 @@
+<!--startmeta
+custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/proxysql/README.md"
+meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/proxysql/metadata.yaml"
+sidebar_label: "ProxySQL"
+learn_status: "Published"
+learn_rel_path: "Collecting Metrics/Databases"
+most_popular: False
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
+endmeta-->
+
+# ProxySQL
+
+
+<img src="https://netdata.cloud/img/proxysql.png" width="150"/>
+
+
+Plugin: go.d.plugin
+Module: proxysql
+
+<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
+
+## Overview
+
+This collector monitors ProxySQL servers.
+
+
+
+
+This collector is supported on all platforms.
+
+This collector supports collecting metrics from multiple instances of this integration, including remote instances.
+
+
+### Default Behavior
+
+#### Auto-Detection
+
+This integration doesn't support auto-detection.
+
+#### Limits
+
+The default configuration for this integration does not impose any limits on data collection.
+
+#### Performance Impact
+
+The default configuration for this integration is not expected to impose a significant performance impact on the system.
+
+
+## Metrics
+
+Metrics grouped by *scope*.
+
+The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
+
+
+
+### Per ProxySQL instance
+
+These metrics refer to the entire monitored application.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| proxysql.client_connections_count | connected, non_idle, hostgroup_locked | connections |
+| proxysql.client_connections_rate | created, aborted | connections/s |
+| proxysql.server_connections_count | connected | connections |
+| proxysql.server_connections_rate | created, aborted, delayed | connections/s |
+| proxysql.backends_traffic | recv, sent | B/s |
+| proxysql.clients_traffic | recv, sent | B/s |
+| proxysql.active_transactions_count | client | connections |
+| proxysql.questions_rate | questions | questions/s |
+| proxysql.slow_queries_rate | slow | queries/s |
+| proxysql.queries_rate | autocommit, autocommit_filtered, commit_filtered, rollback, rollback_filtered, backend_change_user, backend_init_db, backend_set_names, frontend_init_db, frontend_set_names, frontend_use_db | queries/s |
+| proxysql.backend_statements_count | total, unique | statements |
+| proxysql.backend_statements_rate | prepare, execute, close | statements/s |
+| proxysql.client_statements_count | total, unique | statements |
+| proxysql.client_statements_rate | prepare, execute, close | statements/s |
+| proxysql.cached_statements_count | cached | statements |
+| proxysql.query_cache_entries_count | entries | entries |
+| proxysql.query_cache_memory_used | used | B |
+| proxysql.query_cache_io | in, out | B/s |
+| proxysql.query_cache_requests_rate | read, write, read_success | requests/s |
+| proxysql.mysql_monitor_workers_count | workers, auxiliary | threads |
+| proxysql.mysql_monitor_workers_rate | started | workers/s |
+| proxysql.mysql_monitor_connect_checks_rate | succeed, failed | checks/s |
+| proxysql.mysql_monitor_ping_checks_rate | succeed, failed | checks/s |
+| proxysql.mysql_monitor_read_only_checks_rate | succeed, failed | checks/s |
+| proxysql.mysql_monitor_replication_lag_checks_rate | succeed, failed | checks/s |
+| proxysql.jemalloc_memory_used | active, allocated, mapped, metadata, resident, retained | B |
+| proxysql.memory_used | auth, sqlite3, query_digest, query_rules, firewall_users_table, firewall_users_config, firewall_rules_table, firewall_rules_config, mysql_threads, admin_threads, cluster_threads | B |
+| proxysql.uptime | uptime | seconds |
+
+### Per command
+
+These metrics refer to the SQL command.
+
+Labels:
+
+| Label | Description |
+|:-----------|:----------------|
+| command | SQL command. |
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| proxysql.mysql_command_execution_rate | uptime | seconds |
+| proxysql.mysql_command_execution_time | time | microseconds |
+| proxysql.mysql_command_execution_duration | 100us, 500us, 1ms, 5ms, 10ms, 50ms, 100ms, 500ms, 1s, 5s, 10s, +Inf | microseconds |
+
+### Per user
+
+These metrics refer to the user.
+
+Labels:
+
+| Label | Description |
+|:-----------|:----------------|
+| user | username from the mysql_users table |
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| proxysql.mysql_user_connections_utilization | used | percentage |
+| proxysql.mysql_user_connections_count | used | connections |
+
+### Per backend
+
+These metrics refer to the backend server.
+
+Labels:
+
+| Label | Description |
+|:-----------|:----------------|
+| host | backend server host |
+| port | backend server port |
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| proxysql.backend_status | online, shunned, offline_soft, offline_hard | status |
+| proxysql.backend_connections_usage | free, used | connections |
+| proxysql.backend_connections_rate | succeed, failed | connections/s |
+| proxysql.backend_queries_rate | queries | queries/s |
+| proxysql.backend_traffic | recv, send | B/s |
+| proxysql.backend_latency | latency | microseconds |
+
+
+
+## Alerts
+
+There are no alerts configured by default for this integration.
+
+
+## Setup
+
+### Prerequisites
+
+No action required.
+
+### Configuration
+
+#### File
+
+The configuration file name for this integration is `go.d/proxysql.conf`.
+
+
+You can edit the configuration file using the `edit-config` script from the
+Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory).
+
+```bash
+cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
+sudo ./edit-config go.d/proxysql.conf
+```
+#### Options
+
+The following options can be defined globally: update_every, autodetection_retry.
+
+
+<details open><summary>Config options</summary>
+
+| Name | Description | Default | Required |
+|:----|:-----------|:-------|:--------:|
+| update_every | Data collection frequency. | 1 | no |
+| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no |
+| dsn | Data Source Name. See [DSN syntax](https://github.com/go-sql-driver/mysql#dsn-data-source-name). | stats:stats@tcp(127.0.0.1:6032)/ | yes |
+| timeout | Query timeout in seconds. | 1 | no |
+
+</details>
+
+#### Examples
+
+##### TCP socket
+
+An example configuration.
+
+<details open><summary>Config</summary>
+
+```yaml
+jobs:
+ - name: local
+ dsn: stats:stats@tcp(127.0.0.1:6032)/
+
+```
+</details>
+
+##### my.cnf
+
+An example configuration.
+
+<details open><summary>Config</summary>
+
+```yaml
+jobs:
+ - name: local
+ my.cnf: '/etc/my.cnf'
+
+```
+</details>
+
+##### Multi-instance
+
+> **Note**: When you define multiple jobs, their names must be unique.
+
+Local and remote instances.
+
+
+<details open><summary>Config</summary>
+
+```yaml
+jobs:
+ - name: local
+ dsn: stats:stats@tcp(127.0.0.1:6032)/
+
+ - name: remote
+ dsn: stats:stats@tcp(203.0.113.0:6032)/
+
+```
+</details>
+
+
+
+## Troubleshooting
+
+### Debug Mode
+
+To troubleshoot issues with the `proxysql` collector, run the `go.d.plugin` with the debug option enabled. The output
+should give you clues as to why the collector isn't working.
+
+- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on
+ your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`.
+
+ ```bash
+ cd /usr/libexec/netdata/plugins.d/
+ ```
+
+- Switch to the `netdata` user.
+
+ ```bash
+ sudo -u netdata -s
+ ```
+
+- Run the `go.d.plugin` to debug the collector:
+
+ ```bash
+ ./go.d.plugin -d -m proxysql
+ ```
+
+
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/metadata.yaml b/src/go/collectors/go.d.plugin/modules/proxysql/metadata.yaml
new file mode 100644
index 000000000..2c9562d99
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/metadata.yaml
@@ -0,0 +1,430 @@
+plugin_name: go.d.plugin
+modules:
+ - meta:
+ id: collector-go.d.plugin-proxysql
+ plugin_name: go.d.plugin
+ module_name: proxysql
+ monitored_instance:
+ name: ProxySQL
+ link: https://www.proxysql.com/
+ icon_filename: proxysql.png
+ categories:
+ - data-collection.database-servers
+ keywords:
+ - proxysql
+ - databases
+ - sql
+ related_resources:
+ integrations:
+ list: []
+ info_provided_to_referring_integrations:
+ description: ""
+ most_popular: false
+ overview:
+ data_collection:
+ metrics_description: |
+ This collector monitors ProxySQL servers.
+ method_description: ""
+ supported_platforms:
+ include: []
+ exclude: []
+ multi_instance: true
+ additional_permissions:
+ description: ""
+ default_behavior:
+ auto_detection:
+ description: ""
+ limits:
+ description: ""
+ performance_impact:
+ description: ""
+ setup:
+ prerequisites:
+ list: []
+ configuration:
+ file:
+ name: go.d/proxysql.conf
+ options:
+ description: |
+ The following options can be defined globally: update_every, autodetection_retry.
+ folding:
+ title: Config options
+ enabled: true
+ list:
+ - name: update_every
+ description: Data collection frequency.
+ default_value: 1
+ required: false
+ - name: autodetection_retry
+ description: Recheck interval in seconds. Zero means no recheck will be scheduled.
+ default_value: 0
+ required: false
+ - name: dsn
+ description: Data Source Name. See [DSN syntax](https://github.com/go-sql-driver/mysql#dsn-data-source-name).
+ default_value: stats:stats@tcp(127.0.0.1:6032)/
+ required: true
+ - name: timeout
+ description: Query timeout in seconds.
+ default_value: 1
+ required: false
+ examples:
+ folding:
+ title: Config
+ enabled: true
+ list:
+ - name: TCP socket
+ description: An example configuration.
+ config: |
+ jobs:
+ - name: local
+ dsn: stats:stats@tcp(127.0.0.1:6032)/
+ - name: my.cnf
+ description: An example configuration.
+ config: |
+ jobs:
+ - name: local
+ my.cnf: '/etc/my.cnf'
+ - name: Multi-instance
+ description: |
+ > **Note**: When you define multiple jobs, their names must be unique.
+
+ Local and remote instances.
+ config: |
+ jobs:
+ - name: local
+ dsn: stats:stats@tcp(127.0.0.1:6032)/
+
+ - name: remote
+ dsn: stats:stats@tcp(203.0.113.0:6032)/
+ troubleshooting:
+ problems:
+ list: []
+ alerts: []
+ metrics:
+ folding:
+ title: Metrics
+ enabled: false
+ description: ""
+ availability: []
+ scopes:
+ - name: global
+ description: These metrics refer to the entire monitored application.
+ labels: []
+ metrics:
+ - name: proxysql.client_connections_count
+ description: Client connections
+ unit: connections
+ chart_type: line
+ dimensions:
+ - name: connected
+ - name: non_idle
+ - name: hostgroup_locked
+ - name: proxysql.client_connections_rate
+ description: Client connections rate
+ unit: connections/s
+ chart_type: line
+ dimensions:
+ - name: created
+ - name: aborted
+ - name: proxysql.server_connections_count
+ description: Server connections
+ unit: connections
+ chart_type: line
+ dimensions:
+ - name: connected
+ - name: proxysql.server_connections_rate
+ description: Server connections rate
+ unit: connections/s
+ chart_type: line
+ dimensions:
+ - name: created
+ - name: aborted
+ - name: delayed
+ - name: proxysql.backends_traffic
+ description: Backends traffic
+ unit: B/s
+ chart_type: line
+ dimensions:
+ - name: recv
+ - name: sent
+ - name: proxysql.clients_traffic
+ description: Clients traffic
+ unit: B/s
+ chart_type: line
+ dimensions:
+ - name: recv
+ - name: sent
+ - name: proxysql.active_transactions_count
+ description: Client connections that are currently processing a transaction
+ unit: connections
+ chart_type: line
+ dimensions:
+ - name: client
+ - name: proxysql.questions_rate
+ description: Client requests / statements executed
+ unit: questions/s
+ chart_type: line
+ dimensions:
+ - name: questions
+ - name: proxysql.slow_queries_rate
+ description: Slow queries
+ unit: queries/s
+ chart_type: line
+ dimensions:
+ - name: slow
+ - name: proxysql.queries_rate
+ description: Queries rate
+ unit: queries/s
+ chart_type: stacked
+ dimensions:
+ - name: autocommit
+ - name: autocommit_filtered
+ - name: commit_filtered
+ - name: rollback
+ - name: rollback_filtered
+ - name: backend_change_user
+ - name: backend_init_db
+ - name: backend_set_names
+ - name: frontend_init_db
+ - name: frontend_set_names
+ - name: frontend_use_db
+ - name: proxysql.backend_statements_count
+ description: Statements available across all backend connections
+ unit: statements
+ chart_type: line
+ dimensions:
+ - name: total
+ - name: unique
+ - name: proxysql.backend_statements_rate
+ description: Statements executed against the backends
+ unit: statements/s
+ chart_type: stacked
+ dimensions:
+ - name: prepare
+ - name: execute
+ - name: close
+ - name: proxysql.client_statements_count
+ description: Statements that are in use by clients
+ unit: statements
+ chart_type: line
+ dimensions:
+ - name: total
+ - name: unique
+ - name: proxysql.client_statements_rate
+ description: Statements executed by clients
+ unit: statements/s
+ chart_type: stacked
+ dimensions:
+ - name: prepare
+ - name: execute
+ - name: close
+ - name: proxysql.cached_statements_count
+ description: Global prepared statements
+ unit: statements
+ chart_type: line
+ dimensions:
+ - name: cached
+ - name: proxysql.query_cache_entries_count
+ description: Query Cache entries
+ unit: entries
+ chart_type: line
+ dimensions:
+ - name: entries
+ - name: proxysql.query_cache_memory_used
+ description: Query Cache memory used
+ unit: B
+ chart_type: line
+ dimensions:
+ - name: used
+ - name: proxysql.query_cache_io
+ description: Query Cache I/O
+ unit: B/s
+ chart_type: line
+ dimensions:
+ - name: in
+ - name: out
+ - name: proxysql.query_cache_requests_rate
+ description: Query Cache requests
+ unit: requests/s
+ chart_type: line
+ dimensions:
+ - name: read
+ - name: write
+ - name: read_success
+ - name: proxysql.mysql_monitor_workers_count
+ description: MySQL monitor workers
+ unit: threads
+ chart_type: line
+ dimensions:
+ - name: workers
+ - name: auxiliary
+ - name: proxysql.mysql_monitor_workers_rate
+ description: MySQL monitor workers rate
+ unit: workers/s
+ chart_type: line
+ dimensions:
+ - name: started
+ - name: proxysql.mysql_monitor_connect_checks_rate
+ description: MySQL monitor connect checks
+ unit: checks/s
+ chart_type: line
+ dimensions:
+ - name: succeed
+ - name: failed
+ - name: proxysql.mysql_monitor_ping_checks_rate
+ description: MySQL monitor ping checks
+ unit: checks/s
+ chart_type: line
+ dimensions:
+ - name: succeed
+ - name: failed
+ - name: proxysql.mysql_monitor_read_only_checks_rate
+ description: MySQL monitor read only checks
+ unit: checks/s
+ chart_type: line
+ dimensions:
+ - name: succeed
+ - name: failed
+ - name: proxysql.mysql_monitor_replication_lag_checks_rate
+ description: MySQL monitor replication lag checks
+ unit: checks/s
+ chart_type: line
+ dimensions:
+ - name: succeed
+ - name: failed
+ - name: proxysql.jemalloc_memory_used
+ description: Jemalloc used memory
+ unit: B
+ chart_type: stacked
+ dimensions:
+ - name: active
+ - name: allocated
+ - name: mapped
+ - name: metadata
+ - name: resident
+ - name: retained
+ - name: proxysql.memory_used
+ description: Memory used
+ unit: B
+ chart_type: stacked
+ dimensions:
+ - name: auth
+ - name: sqlite3
+ - name: query_digest
+ - name: query_rules
+ - name: firewall_users_table
+ - name: firewall_users_config
+ - name: firewall_rules_table
+ - name: firewall_rules_config
+ - name: mysql_threads
+ - name: admin_threads
+ - name: cluster_threads
+ - name: proxysql.uptime
+ description: Uptime
+ unit: seconds
+ chart_type: line
+ dimensions:
+ - name: uptime
+ - name: command
+ description: These metrics refer to the SQL command.
+ labels:
+ - name: command
+ description: SQL command.
+ metrics:
+ - name: proxysql.mysql_command_execution_rate
+ description: MySQL command execution
+ unit: seconds
+ chart_type: line
+ dimensions:
+ - name: uptime
+ - name: proxysql.mysql_command_execution_time
+ description: MySQL command execution time
+ unit: microseconds
+ chart_type: line
+ dimensions:
+ - name: time
+ - name: proxysql.mysql_command_execution_duration
+ description: MySQL command execution duration histogram
+ unit: microseconds
+ chart_type: stacked
+ dimensions:
+ - name: 100us
+ - name: 500us
+ - name: 1ms
+ - name: 5ms
+ - name: 10ms
+ - name: 50ms
+ - name: 100ms
+ - name: 500ms
+ - name: 1s
+ - name: 5s
+ - name: 10s
+ - name: +Inf
+ - name: user
+ description: These metrics refer to the user.
+ labels:
+ - name: user
+ description: username from the mysql_users table
+ metrics:
+ - name: proxysql.mysql_user_connections_utilization
+ description: MySQL user connections utilization
+ unit: percentage
+ chart_type: line
+ dimensions:
+ - name: used
+ - name: proxysql.mysql_user_connections_count
+ description: MySQL user connections used
+ unit: connections
+ chart_type: line
+ dimensions:
+ - name: used
+ - name: backend
+ description: These metrics refer to the backend server.
+ labels:
+ - name: host
+ description: backend server host
+ - name: port
+ description: backend server port
+ metrics:
+ - name: proxysql.backend_status
+ description: Backend status
+ unit: status
+ chart_type: line
+ dimensions:
+ - name: online
+ - name: shunned
+ - name: offline_soft
+ - name: offline_hard
+ - name: proxysql.backend_connections_usage
+ description: Backend connections usage
+ unit: connections
+ chart_type: line
+ dimensions:
+ - name: free
+ - name: used
+ - name: proxysql.backend_connections_rate
+ description: Backend connections established
+ unit: connections/s
+ chart_type: line
+ dimensions:
+ - name: succeed
+ - name: failed
+ - name: proxysql.backend_queries_rate
+ description: Backend queries
+ unit: queries/s
+ chart_type: line
+ dimensions:
+ - name: queries
+ - name: proxysql.backend_traffic
+ description: Backend traffic
+ unit: B/s
+ chart_type: line
+ dimensions:
+ - name: recv
+ - name: send
+ - name: proxysql.backend_latency
+ description: Backend latency
+ unit: microseconds
+ chart_type: line
+ dimensions:
+ - name: latency
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/proxysql.go b/src/go/collectors/go.d.plugin/modules/proxysql/proxysql.go
new file mode 100644
index 000000000..4fe08b8b0
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/proxysql.go
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package proxysql
+
+import (
+ "database/sql"
+ _ "embed"
+ "errors"
+ _ "github.com/go-sql-driver/mysql"
+ "sync"
+ "time"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/web"
+)
+
+//go:embed "config_schema.json"
+var configSchema string
+
+func init() {
+ module.Register("proxysql", module.Creator{
+ JobConfigSchema: configSchema,
+ Create: func() module.Module { return New() },
+ Config: func() any { return &Config{} },
+ })
+}
+
+func New() *ProxySQL {
+ return &ProxySQL{
+ Config: Config{
+ DSN: "stats:stats@tcp(127.0.0.1:6032)/",
+ Timeout: web.Duration(time.Second),
+ },
+
+ charts: baseCharts.Copy(),
+ once: &sync.Once{},
+ cache: &cache{
+ commands: make(map[string]*commandCache),
+ users: make(map[string]*userCache),
+ backends: make(map[string]*backendCache),
+ },
+ }
+}
+
+type Config struct {
+ UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
+ DSN string `yaml:"dsn" json:"dsn"`
+ Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"`
+}
+
+type ProxySQL struct {
+ module.Base
+ Config `yaml:",inline" json:""`
+
+ charts *module.Charts
+
+ db *sql.DB
+
+ once *sync.Once
+ cache *cache
+}
+
+func (p *ProxySQL) Configuration() any {
+ return p.Config
+}
+
+func (p *ProxySQL) Init() error {
+ if p.DSN == "" {
+ p.Error("dsn not set")
+ return errors.New("dsn not set")
+ }
+
+ p.Debugf("using DSN [%s]", p.DSN)
+
+ return nil
+}
+
+func (p *ProxySQL) Check() error {
+ mx, err := p.collect()
+ if err != nil {
+ p.Error(err)
+ return err
+ }
+ if len(mx) == 0 {
+ return errors.New("no metrics collected")
+ }
+ return nil
+}
+
+func (p *ProxySQL) Charts() *module.Charts {
+ return p.charts
+}
+
+func (p *ProxySQL) Collect() map[string]int64 {
+ mx, err := p.collect()
+ if err != nil {
+ p.Error(err)
+ }
+
+ if len(mx) == 0 {
+ return nil
+ }
+ return mx
+}
+
+func (p *ProxySQL) Cleanup() {
+ if p.db == nil {
+ return
+ }
+ if err := p.db.Close(); err != nil {
+ p.Errorf("cleanup: error on closing the ProxySQL instance [%s]: %v", p.DSN, err)
+ }
+ p.db = nil
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/proxysql_test.go b/src/go/collectors/go.d.plugin/modules/proxysql/proxysql_test.go
new file mode 100644
index 000000000..3dfaf1bf3
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/proxysql_test.go
@@ -0,0 +1,1240 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package proxysql
+
+import (
+ "bufio"
+ "bytes"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+
+ "github.com/DATA-DOG/go-sqlmock"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+var (
+ dataConfigJSON, _ = os.ReadFile("testdata/config.json")
+ dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
+
+ dataVer2010Version, _ = os.ReadFile("testdata/v2.0.10/version.txt")
+ dataVer2010StatsMySQLGlobal, _ = os.ReadFile("testdata/v2.0.10/stats_mysql_global.txt")
+ dataVer2010StatsMemoryMetrics, _ = os.ReadFile("testdata/v2.0.10/stats_memory_metrics.txt")
+ dataVer2010StatsMySQLCommandsCounters, _ = os.ReadFile("testdata/v2.0.10/stats_mysql_commands_counters.txt")
+ dataVer2010StatsMySQLUsers, _ = os.ReadFile("testdata/v2.0.10/stats_mysql_users.txt")
+ dataVer2010StatsMySQLConnectionPool, _ = os.ReadFile("testdata/v2.0.10/stats_mysql_connection_pool .txt")
+)
+
+func Test_testDataIsValid(t *testing.T) {
+ for name, data := range map[string][]byte{
+ "dataConfigJSON": dataConfigJSON,
+ "dataConfigYAML": dataConfigYAML,
+ "dataVer2010Version": dataVer2010Version,
+ "dataVer2010StatsMySQLGlobal": dataVer2010StatsMySQLGlobal,
+ "dataVer2010StatsMemoryMetrics": dataVer2010StatsMemoryMetrics,
+ "dataVer2010StatsMySQLCommandsCounters": dataVer2010StatsMySQLCommandsCounters,
+ "dataVer2010StatsMySQLUsers": dataVer2010StatsMySQLUsers,
+ "dataVer2010StatsMySQLConnectionPool": dataVer2010StatsMySQLConnectionPool,
+ } {
+ require.NotNil(t, data, name)
+ _, err := prepareMockRows(data)
+ require.NoError(t, err, name)
+ }
+}
+
+func TestProxySQL_ConfigurationSerialize(t *testing.T) {
+ module.TestConfigurationSerialize(t, &ProxySQL{}, dataConfigJSON, dataConfigYAML)
+}
+
+func TestProxySQL_Init(t *testing.T) {
+ tests := map[string]struct {
+ config Config
+ wantFail bool
+ }{
+ "default": {
+ wantFail: false,
+ config: New().Config,
+ },
+ "empty DSN": {
+ wantFail: true,
+ config: Config{DSN: ""},
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ proxySQL := New()
+ proxySQL.Config = test.config
+
+ if test.wantFail {
+ assert.Error(t, proxySQL.Init())
+ } else {
+ assert.NoError(t, proxySQL.Init())
+ }
+ })
+ }
+}
+
+func TestProxySQL_Cleanup(t *testing.T) {
+ tests := map[string]func(t *testing.T) (proxySQL *ProxySQL, cleanup func()){
+ "db connection not initialized": func(t *testing.T) (proxySQL *ProxySQL, cleanup func()) {
+ return New(), func() {}
+ },
+ "db connection initialized": func(t *testing.T) (proxySQL *ProxySQL, cleanup func()) {
+ db, mock, err := sqlmock.New()
+ require.NoError(t, err)
+
+ mock.ExpectClose()
+ proxySQL = New()
+ proxySQL.db = db
+ cleanup = func() { _ = db.Close() }
+
+ return proxySQL, cleanup
+ },
+ }
+
+ for name, prepare := range tests {
+ t.Run(name, func(t *testing.T) {
+ proxySQL, cleanup := prepare(t)
+ defer cleanup()
+
+ assert.NotPanics(t, proxySQL.Cleanup)
+ assert.Nil(t, proxySQL.db)
+ })
+ }
+}
+
+func TestProxySQL_Charts(t *testing.T) {
+ assert.NotNil(t, New().Charts())
+}
+
+func TestProxySQL_Check(t *testing.T) {
+ tests := map[string]struct {
+ prepareMock func(t *testing.T, m sqlmock.Sqlmock)
+ wantFail bool
+ }{
+ "success on all queries": {
+ wantFail: false,
+ prepareMock: func(t *testing.T, m sqlmock.Sqlmock) {
+ mockExpect(t, m, queryVersion, dataVer2010Version)
+ mockExpect(t, m, queryStatsMySQLGlobal, dataVer2010StatsMySQLGlobal)
+ mockExpect(t, m, queryStatsMySQLMemoryMetrics, dataVer2010StatsMemoryMetrics)
+ mockExpect(t, m, queryStatsMySQLCommandsCounters, dataVer2010StatsMySQLCommandsCounters)
+ mockExpect(t, m, queryStatsMySQLUsers, dataVer2010StatsMySQLUsers)
+ mockExpect(t, m, queryStatsMySQLConnectionPool, dataVer2010StatsMySQLConnectionPool)
+ },
+ },
+ "fails when error on querying global stats": {
+ wantFail: true,
+ prepareMock: func(t *testing.T, m sqlmock.Sqlmock) {
+ mockExpect(t, m, queryVersion, dataVer2010Version)
+ mockExpectErr(m, queryStatsMySQLGlobal)
+ },
+ },
+ "fails when error on querying memory metrics": {
+ wantFail: true,
+ prepareMock: func(t *testing.T, m sqlmock.Sqlmock) {
+ mockExpect(t, m, queryVersion, dataVer2010Version)
+ mockExpect(t, m, queryStatsMySQLGlobal, dataVer2010StatsMySQLGlobal)
+ mockExpectErr(m, queryStatsMySQLMemoryMetrics)
+ },
+ },
+ "fails when error on querying mysql command counters": {
+ wantFail: true,
+ prepareMock: func(t *testing.T, m sqlmock.Sqlmock) {
+ mockExpect(t, m, queryVersion, dataVer2010Version)
+ mockExpect(t, m, queryStatsMySQLGlobal, dataVer2010StatsMySQLGlobal)
+ mockExpect(t, m, queryStatsMySQLMemoryMetrics, dataVer2010StatsMemoryMetrics)
+ mockExpectErr(m, queryStatsMySQLCommandsCounters)
+ },
+ },
+ "fails when error on querying mysql users": {
+ wantFail: true,
+ prepareMock: func(t *testing.T, m sqlmock.Sqlmock) {
+ mockExpect(t, m, queryVersion, dataVer2010Version)
+ mockExpect(t, m, queryStatsMySQLGlobal, dataVer2010StatsMySQLGlobal)
+ mockExpect(t, m, queryStatsMySQLMemoryMetrics, dataVer2010StatsMemoryMetrics)
+ mockExpect(t, m, queryStatsMySQLCommandsCounters, dataVer2010StatsMySQLCommandsCounters)
+ mockExpectErr(m, queryStatsMySQLUsers)
+ },
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ db, mock, err := sqlmock.New(
+ sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual),
+ )
+ require.NoError(t, err)
+ proxySQL := New()
+ proxySQL.db = db
+ defer func() { _ = db.Close() }()
+
+ require.NoError(t, proxySQL.Init())
+
+ test.prepareMock(t, mock)
+
+ if test.wantFail {
+ assert.Error(t, proxySQL.Check())
+ } else {
+ assert.NoError(t, proxySQL.Check())
+ }
+ assert.NoError(t, mock.ExpectationsWereMet())
+ })
+ }
+}
+
+func TestProxySQL_Collect(t *testing.T) {
+ type testCaseStep struct {
+ prepareMock func(t *testing.T, m sqlmock.Sqlmock)
+ check func(t *testing.T, my *ProxySQL)
+ }
+ tests := map[string][]testCaseStep{
+
+ "success on all queries (v2.0.10)": {
+ {
+ prepareMock: func(t *testing.T, m sqlmock.Sqlmock) {
+ mockExpect(t, m, queryVersion, dataVer2010Version)
+ mockExpect(t, m, queryStatsMySQLGlobal, dataVer2010StatsMySQLGlobal)
+ mockExpect(t, m, queryStatsMySQLMemoryMetrics, dataVer2010StatsMemoryMetrics)
+ mockExpect(t, m, queryStatsMySQLCommandsCounters, dataVer2010StatsMySQLCommandsCounters)
+ mockExpect(t, m, queryStatsMySQLUsers, dataVer2010StatsMySQLUsers)
+ mockExpect(t, m, queryStatsMySQLConnectionPool, dataVer2010StatsMySQLConnectionPool)
+ },
+ check: func(t *testing.T, my *ProxySQL) {
+ mx := my.Collect()
+
+ expected := map[string]int64{
+ "Access_Denied_Max_Connections": 0,
+ "Access_Denied_Max_User_Connections": 0,
+ "Access_Denied_Wrong_Password": 2,
+ "Active_Transactions": 0,
+ "Auth_memory": 1044,
+ "Backend_query_time_nsec": 0,
+ "Client_Connections_aborted": 2,
+ "Client_Connections_connected": 3,
+ "Client_Connections_created": 5458991,
+ "Client_Connections_hostgroup_locked": 0,
+ "Client_Connections_non_idle": 3,
+ "Com_autocommit": 0,
+ "Com_autocommit_filtered": 0,
+ "Com_backend_change_user": 188694,
+ "Com_backend_init_db": 0,
+ "Com_backend_set_names": 1517893,
+ "Com_backend_stmt_close": 0,
+ "Com_backend_stmt_execute": 36303146,
+ "Com_backend_stmt_prepare": 16858208,
+ "Com_commit": 0,
+ "Com_commit_filtered": 0,
+ "Com_frontend_init_db": 2,
+ "Com_frontend_set_names": 0,
+ "Com_frontend_stmt_close": 32137933,
+ "Com_frontend_stmt_execute": 36314138,
+ "Com_frontend_stmt_prepare": 32185987,
+ "Com_frontend_use_db": 0,
+ "Com_rollback": 0,
+ "Com_rollback_filtered": 0,
+ "ConnPool_get_conn_failure": 212943,
+ "ConnPool_get_conn_immediate": 13361,
+ "ConnPool_get_conn_latency_awareness": 0,
+ "ConnPool_get_conn_success": 36319474,
+ "ConnPool_memory_bytes": 932248,
+ "GTID_consistent_queries": 0,
+ "GTID_session_collected": 0,
+ "Mirror_concurrency": 0,
+ "Mirror_queue_length": 0,
+ "MyHGM_myconnpoll_destroy": 15150,
+ "MyHGM_myconnpoll_get": 36519056,
+ "MyHGM_myconnpoll_get_ok": 36306113,
+ "MyHGM_myconnpoll_push": 37358734,
+ "MyHGM_myconnpoll_reset": 2,
+ "MySQL_Monitor_Workers": 10,
+ "MySQL_Monitor_Workers_Aux": 0,
+ "MySQL_Monitor_Workers_Started": 10,
+ "MySQL_Monitor_connect_check_ERR": 130,
+ "MySQL_Monitor_connect_check_OK": 3548306,
+ "MySQL_Monitor_ping_check_ERR": 108271,
+ "MySQL_Monitor_ping_check_OK": 21289849,
+ "MySQL_Monitor_read_only_check_ERR": 19610,
+ "MySQL_Monitor_read_only_check_OK": 106246409,
+ "MySQL_Monitor_replication_lag_check_ERR": 482,
+ "MySQL_Monitor_replication_lag_check_OK": 28702388,
+ "MySQL_Thread_Workers": 4,
+ "ProxySQL_Uptime": 26748286,
+ "Queries_backends_bytes_recv": 5896210168,
+ "Queries_backends_bytes_sent": 4329581500,
+ "Queries_frontends_bytes_recv": 7434816962,
+ "Queries_frontends_bytes_sent": 11643634097,
+ "Query_Cache_Entries": 0,
+ "Query_Cache_Memory_bytes": 0,
+ "Query_Cache_Purged": 0,
+ "Query_Cache_bytes_IN": 0,
+ "Query_Cache_bytes_OUT": 0,
+ "Query_Cache_count_GET": 0,
+ "Query_Cache_count_GET_OK": 0,
+ "Query_Cache_count_SET": 0,
+ "Query_Processor_time_nsec": 0,
+ "Questions": 100638067,
+ "SQLite3_memory_bytes": 6017144,
+ "Selects_for_update__autocommit0": 0,
+ "Server_Connections_aborted": 9979,
+ "Server_Connections_connected": 13,
+ "Server_Connections_created": 2122254,
+ "Server_Connections_delayed": 0,
+ "Servers_table_version": 37,
+ "Slow_queries": 405818,
+ "Stmt_Cached": 65,
+ "Stmt_Client_Active_Total": 18,
+ "Stmt_Client_Active_Unique": 18,
+ "Stmt_Max_Stmt_id": 66,
+ "Stmt_Server_Active_Total": 101,
+ "Stmt_Server_Active_Unique": 39,
+ "automatic_detected_sql_injection": 0,
+ "aws_aurora_replicas_skipped_during_query": 0,
+ "backend_10_back001-db-master_6001_Bytes_data_recv": 145193069937,
+ "backend_10_back001-db-master_6001_Bytes_data_sent": 9858463664,
+ "backend_10_back001-db-master_6001_ConnERR": 0,
+ "backend_10_back001-db-master_6001_ConnFree": 423,
+ "backend_10_back001-db-master_6001_ConnOK": 524,
+ "backend_10_back001-db-master_6001_ConnUsed": 69,
+ "backend_10_back001-db-master_6001_Latency_us": 17684,
+ "backend_10_back001-db-master_6001_Queries": 8970367,
+ "backend_10_back001-db-master_6001_status_OFFLINE_HARD": 0,
+ "backend_10_back001-db-master_6001_status_OFFLINE_SOFT": 0,
+ "backend_10_back001-db-master_6001_status_ONLINE": 0,
+ "backend_10_back001-db-master_6001_status_SHUNNED": 0,
+ "backend_11_back001-db-master_6002_Bytes_data_recv": 2903,
+ "backend_11_back001-db-master_6002_Bytes_data_sent": 187675,
+ "backend_11_back001-db-master_6002_ConnERR": 0,
+ "backend_11_back001-db-master_6002_ConnFree": 1,
+ "backend_11_back001-db-master_6002_ConnOK": 1,
+ "backend_11_back001-db-master_6002_ConnUsed": 0,
+ "backend_11_back001-db-master_6002_Latency_us": 17684,
+ "backend_11_back001-db-master_6002_Queries": 69,
+ "backend_11_back001-db-master_6002_status_OFFLINE_HARD": 0,
+ "backend_11_back001-db-master_6002_status_OFFLINE_SOFT": 0,
+ "backend_11_back001-db-master_6002_status_ONLINE": 0,
+ "backend_11_back001-db-master_6002_status_SHUNNED": 0,
+ "backend_11_back001-db-reader_6003_Bytes_data_recv": 4994101,
+ "backend_11_back001-db-reader_6003_Bytes_data_sent": 163690013,
+ "backend_11_back001-db-reader_6003_ConnERR": 0,
+ "backend_11_back001-db-reader_6003_ConnFree": 11,
+ "backend_11_back001-db-reader_6003_ConnOK": 11,
+ "backend_11_back001-db-reader_6003_ConnUsed": 0,
+ "backend_11_back001-db-reader_6003_Latency_us": 113,
+ "backend_11_back001-db-reader_6003_Queries": 63488,
+ "backend_11_back001-db-reader_6003_status_OFFLINE_HARD": 0,
+ "backend_11_back001-db-reader_6003_status_OFFLINE_SOFT": 0,
+ "backend_11_back001-db-reader_6003_status_ONLINE": 0,
+ "backend_11_back001-db-reader_6003_status_SHUNNED": 0,
+ "backend_20_back002-db-master_6004_Bytes_data_recv": 266034339,
+ "backend_20_back002-db-master_6004_Bytes_data_sent": 1086994186,
+ "backend_20_back002-db-master_6004_ConnERR": 2,
+ "backend_20_back002-db-master_6004_ConnFree": 188,
+ "backend_20_back002-db-master_6004_ConnOK": 197,
+ "backend_20_back002-db-master_6004_ConnUsed": 9,
+ "backend_20_back002-db-master_6004_Latency_us": 101981,
+ "backend_20_back002-db-master_6004_Queries": 849461,
+ "backend_20_back002-db-master_6004_status_OFFLINE_HARD": 0,
+ "backend_20_back002-db-master_6004_status_OFFLINE_SOFT": 0,
+ "backend_20_back002-db-master_6004_status_ONLINE": 0,
+ "backend_20_back002-db-master_6004_status_SHUNNED": 0,
+ "backend_21_back002-db-reader_6005_Bytes_data_recv": 984,
+ "backend_21_back002-db-reader_6005_Bytes_data_sent": 6992,
+ "backend_21_back002-db-reader_6005_ConnERR": 0,
+ "backend_21_back002-db-reader_6005_ConnFree": 1,
+ "backend_21_back002-db-reader_6005_ConnOK": 1,
+ "backend_21_back002-db-reader_6005_ConnUsed": 0,
+ "backend_21_back002-db-reader_6005_Latency_us": 230,
+ "backend_21_back002-db-reader_6005_Queries": 8,
+ "backend_21_back002-db-reader_6005_status_OFFLINE_HARD": 0,
+ "backend_21_back002-db-reader_6005_status_OFFLINE_SOFT": 0,
+ "backend_21_back002-db-reader_6005_status_ONLINE": 0,
+ "backend_21_back002-db-reader_6005_status_SHUNNED": 0,
+ "backend_31_back003-db-master_6006_Bytes_data_recv": 81438709,
+ "backend_31_back003-db-master_6006_Bytes_data_sent": 712803,
+ "backend_31_back003-db-master_6006_ConnERR": 0,
+ "backend_31_back003-db-master_6006_ConnFree": 3,
+ "backend_31_back003-db-master_6006_ConnOK": 3,
+ "backend_31_back003-db-master_6006_ConnUsed": 0,
+ "backend_31_back003-db-master_6006_Latency_us": 231,
+ "backend_31_back003-db-master_6006_Queries": 3276,
+ "backend_31_back003-db-master_6006_status_OFFLINE_HARD": 0,
+ "backend_31_back003-db-master_6006_status_OFFLINE_SOFT": 0,
+ "backend_31_back003-db-master_6006_status_ONLINE": 0,
+ "backend_31_back003-db-master_6006_status_SHUNNED": 0,
+ "backend_31_back003-db-reader_6007_Bytes_data_recv": 115810708275,
+ "backend_31_back003-db-reader_6007_Bytes_data_sent": 411900849,
+ "backend_31_back003-db-reader_6007_ConnERR": 0,
+ "backend_31_back003-db-reader_6007_ConnFree": 70,
+ "backend_31_back003-db-reader_6007_ConnOK": 71,
+ "backend_31_back003-db-reader_6007_ConnUsed": 1,
+ "backend_31_back003-db-reader_6007_Latency_us": 230,
+ "backend_31_back003-db-reader_6007_Queries": 2356904,
+ "backend_31_back003-db-reader_6007_status_OFFLINE_HARD": 0,
+ "backend_31_back003-db-reader_6007_status_OFFLINE_SOFT": 0,
+ "backend_31_back003-db-reader_6007_status_ONLINE": 0,
+ "backend_31_back003-db-reader_6007_status_SHUNNED": 0,
+ "backend_lagging_during_query": 8880,
+ "backend_offline_during_query": 8,
+ "generated_error_packets": 231,
+ "hostgroup_locked_queries": 0,
+ "hostgroup_locked_set_cmds": 0,
+ "jemalloc_active": 385101824,
+ "jemalloc_allocated": 379402432,
+ "jemalloc_mapped": 430993408,
+ "jemalloc_metadata": 17418872,
+ "jemalloc_resident": 403759104,
+ "jemalloc_retained": 260542464,
+ "max_connect_timeouts": 227,
+ "mysql_backend_buffers_bytes": 0,
+ "mysql_command_ALTER_TABLE_Total_Time_us": 0,
+ "mysql_command_ALTER_TABLE_Total_cnt": 0,
+ "mysql_command_ALTER_TABLE_cnt_100ms": 0,
+ "mysql_command_ALTER_TABLE_cnt_100us": 0,
+ "mysql_command_ALTER_TABLE_cnt_10ms": 0,
+ "mysql_command_ALTER_TABLE_cnt_10s": 0,
+ "mysql_command_ALTER_TABLE_cnt_1ms": 0,
+ "mysql_command_ALTER_TABLE_cnt_1s": 0,
+ "mysql_command_ALTER_TABLE_cnt_500ms": 0,
+ "mysql_command_ALTER_TABLE_cnt_500us": 0,
+ "mysql_command_ALTER_TABLE_cnt_50ms": 0,
+ "mysql_command_ALTER_TABLE_cnt_5ms": 0,
+ "mysql_command_ALTER_TABLE_cnt_5s": 0,
+ "mysql_command_ALTER_TABLE_cnt_INFs": 0,
+ "mysql_command_ALTER_VIEW_Total_Time_us": 0,
+ "mysql_command_ALTER_VIEW_Total_cnt": 0,
+ "mysql_command_ALTER_VIEW_cnt_100ms": 0,
+ "mysql_command_ALTER_VIEW_cnt_100us": 0,
+ "mysql_command_ALTER_VIEW_cnt_10ms": 0,
+ "mysql_command_ALTER_VIEW_cnt_10s": 0,
+ "mysql_command_ALTER_VIEW_cnt_1ms": 0,
+ "mysql_command_ALTER_VIEW_cnt_1s": 0,
+ "mysql_command_ALTER_VIEW_cnt_500ms": 0,
+ "mysql_command_ALTER_VIEW_cnt_500us": 0,
+ "mysql_command_ALTER_VIEW_cnt_50ms": 0,
+ "mysql_command_ALTER_VIEW_cnt_5ms": 0,
+ "mysql_command_ALTER_VIEW_cnt_5s": 0,
+ "mysql_command_ALTER_VIEW_cnt_INFs": 0,
+ "mysql_command_ANALYZE_TABLE_Total_Time_us": 0,
+ "mysql_command_ANALYZE_TABLE_Total_cnt": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_100ms": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_100us": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_10ms": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_10s": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_1ms": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_1s": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_500ms": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_500us": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_50ms": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_5ms": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_5s": 0,
+ "mysql_command_ANALYZE_TABLE_cnt_INFs": 0,
+ "mysql_command_BEGIN_Total_Time_us": 0,
+ "mysql_command_BEGIN_Total_cnt": 0,
+ "mysql_command_BEGIN_cnt_100ms": 0,
+ "mysql_command_BEGIN_cnt_100us": 0,
+ "mysql_command_BEGIN_cnt_10ms": 0,
+ "mysql_command_BEGIN_cnt_10s": 0,
+ "mysql_command_BEGIN_cnt_1ms": 0,
+ "mysql_command_BEGIN_cnt_1s": 0,
+ "mysql_command_BEGIN_cnt_500ms": 0,
+ "mysql_command_BEGIN_cnt_500us": 0,
+ "mysql_command_BEGIN_cnt_50ms": 0,
+ "mysql_command_BEGIN_cnt_5ms": 0,
+ "mysql_command_BEGIN_cnt_5s": 0,
+ "mysql_command_BEGIN_cnt_INFs": 0,
+ "mysql_command_CALL_Total_Time_us": 0,
+ "mysql_command_CALL_Total_cnt": 0,
+ "mysql_command_CALL_cnt_100ms": 0,
+ "mysql_command_CALL_cnt_100us": 0,
+ "mysql_command_CALL_cnt_10ms": 0,
+ "mysql_command_CALL_cnt_10s": 0,
+ "mysql_command_CALL_cnt_1ms": 0,
+ "mysql_command_CALL_cnt_1s": 0,
+ "mysql_command_CALL_cnt_500ms": 0,
+ "mysql_command_CALL_cnt_500us": 0,
+ "mysql_command_CALL_cnt_50ms": 0,
+ "mysql_command_CALL_cnt_5ms": 0,
+ "mysql_command_CALL_cnt_5s": 0,
+ "mysql_command_CALL_cnt_INFs": 0,
+ "mysql_command_CHANGE_MASTER_Total_Time_us": 0,
+ "mysql_command_CHANGE_MASTER_Total_cnt": 0,
+ "mysql_command_CHANGE_MASTER_cnt_100ms": 0,
+ "mysql_command_CHANGE_MASTER_cnt_100us": 0,
+ "mysql_command_CHANGE_MASTER_cnt_10ms": 0,
+ "mysql_command_CHANGE_MASTER_cnt_10s": 0,
+ "mysql_command_CHANGE_MASTER_cnt_1ms": 0,
+ "mysql_command_CHANGE_MASTER_cnt_1s": 0,
+ "mysql_command_CHANGE_MASTER_cnt_500ms": 0,
+ "mysql_command_CHANGE_MASTER_cnt_500us": 0,
+ "mysql_command_CHANGE_MASTER_cnt_50ms": 0,
+ "mysql_command_CHANGE_MASTER_cnt_5ms": 0,
+ "mysql_command_CHANGE_MASTER_cnt_5s": 0,
+ "mysql_command_CHANGE_MASTER_cnt_INFs": 0,
+ "mysql_command_COMMIT_Total_Time_us": 0,
+ "mysql_command_COMMIT_Total_cnt": 0,
+ "mysql_command_COMMIT_cnt_100ms": 0,
+ "mysql_command_COMMIT_cnt_100us": 0,
+ "mysql_command_COMMIT_cnt_10ms": 0,
+ "mysql_command_COMMIT_cnt_10s": 0,
+ "mysql_command_COMMIT_cnt_1ms": 0,
+ "mysql_command_COMMIT_cnt_1s": 0,
+ "mysql_command_COMMIT_cnt_500ms": 0,
+ "mysql_command_COMMIT_cnt_500us": 0,
+ "mysql_command_COMMIT_cnt_50ms": 0,
+ "mysql_command_COMMIT_cnt_5ms": 0,
+ "mysql_command_COMMIT_cnt_5s": 0,
+ "mysql_command_COMMIT_cnt_INFs": 0,
+ "mysql_command_CREATE_DATABASE_Total_Time_us": 0,
+ "mysql_command_CREATE_DATABASE_Total_cnt": 0,
+ "mysql_command_CREATE_DATABASE_cnt_100ms": 0,
+ "mysql_command_CREATE_DATABASE_cnt_100us": 0,
+ "mysql_command_CREATE_DATABASE_cnt_10ms": 0,
+ "mysql_command_CREATE_DATABASE_cnt_10s": 0,
+ "mysql_command_CREATE_DATABASE_cnt_1ms": 0,
+ "mysql_command_CREATE_DATABASE_cnt_1s": 0,
+ "mysql_command_CREATE_DATABASE_cnt_500ms": 0,
+ "mysql_command_CREATE_DATABASE_cnt_500us": 0,
+ "mysql_command_CREATE_DATABASE_cnt_50ms": 0,
+ "mysql_command_CREATE_DATABASE_cnt_5ms": 0,
+ "mysql_command_CREATE_DATABASE_cnt_5s": 0,
+ "mysql_command_CREATE_DATABASE_cnt_INFs": 0,
+ "mysql_command_CREATE_INDEX_Total_Time_us": 0,
+ "mysql_command_CREATE_INDEX_Total_cnt": 0,
+ "mysql_command_CREATE_INDEX_cnt_100ms": 0,
+ "mysql_command_CREATE_INDEX_cnt_100us": 0,
+ "mysql_command_CREATE_INDEX_cnt_10ms": 0,
+ "mysql_command_CREATE_INDEX_cnt_10s": 0,
+ "mysql_command_CREATE_INDEX_cnt_1ms": 0,
+ "mysql_command_CREATE_INDEX_cnt_1s": 0,
+ "mysql_command_CREATE_INDEX_cnt_500ms": 0,
+ "mysql_command_CREATE_INDEX_cnt_500us": 0,
+ "mysql_command_CREATE_INDEX_cnt_50ms": 0,
+ "mysql_command_CREATE_INDEX_cnt_5ms": 0,
+ "mysql_command_CREATE_INDEX_cnt_5s": 0,
+ "mysql_command_CREATE_INDEX_cnt_INFs": 0,
+ "mysql_command_CREATE_TABLE_Total_Time_us": 0,
+ "mysql_command_CREATE_TABLE_Total_cnt": 0,
+ "mysql_command_CREATE_TABLE_cnt_100ms": 0,
+ "mysql_command_CREATE_TABLE_cnt_100us": 0,
+ "mysql_command_CREATE_TABLE_cnt_10ms": 0,
+ "mysql_command_CREATE_TABLE_cnt_10s": 0,
+ "mysql_command_CREATE_TABLE_cnt_1ms": 0,
+ "mysql_command_CREATE_TABLE_cnt_1s": 0,
+ "mysql_command_CREATE_TABLE_cnt_500ms": 0,
+ "mysql_command_CREATE_TABLE_cnt_500us": 0,
+ "mysql_command_CREATE_TABLE_cnt_50ms": 0,
+ "mysql_command_CREATE_TABLE_cnt_5ms": 0,
+ "mysql_command_CREATE_TABLE_cnt_5s": 0,
+ "mysql_command_CREATE_TABLE_cnt_INFs": 0,
+ "mysql_command_CREATE_TEMPORARY_Total_Time_us": 0,
+ "mysql_command_CREATE_TEMPORARY_Total_cnt": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_100ms": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_100us": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_10ms": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_10s": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_1ms": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_1s": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_500ms": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_500us": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_50ms": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_5ms": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_5s": 0,
+ "mysql_command_CREATE_TEMPORARY_cnt_INFs": 0,
+ "mysql_command_CREATE_TRIGGER_Total_Time_us": 0,
+ "mysql_command_CREATE_TRIGGER_Total_cnt": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_100ms": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_100us": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_10ms": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_10s": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_1ms": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_1s": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_500ms": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_500us": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_50ms": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_5ms": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_5s": 0,
+ "mysql_command_CREATE_TRIGGER_cnt_INFs": 0,
+ "mysql_command_CREATE_USER_Total_Time_us": 0,
+ "mysql_command_CREATE_USER_Total_cnt": 0,
+ "mysql_command_CREATE_USER_cnt_100ms": 0,
+ "mysql_command_CREATE_USER_cnt_100us": 0,
+ "mysql_command_CREATE_USER_cnt_10ms": 0,
+ "mysql_command_CREATE_USER_cnt_10s": 0,
+ "mysql_command_CREATE_USER_cnt_1ms": 0,
+ "mysql_command_CREATE_USER_cnt_1s": 0,
+ "mysql_command_CREATE_USER_cnt_500ms": 0,
+ "mysql_command_CREATE_USER_cnt_500us": 0,
+ "mysql_command_CREATE_USER_cnt_50ms": 0,
+ "mysql_command_CREATE_USER_cnt_5ms": 0,
+ "mysql_command_CREATE_USER_cnt_5s": 0,
+ "mysql_command_CREATE_USER_cnt_INFs": 0,
+ "mysql_command_CREATE_VIEW_Total_Time_us": 0,
+ "mysql_command_CREATE_VIEW_Total_cnt": 0,
+ "mysql_command_CREATE_VIEW_cnt_100ms": 0,
+ "mysql_command_CREATE_VIEW_cnt_100us": 0,
+ "mysql_command_CREATE_VIEW_cnt_10ms": 0,
+ "mysql_command_CREATE_VIEW_cnt_10s": 0,
+ "mysql_command_CREATE_VIEW_cnt_1ms": 0,
+ "mysql_command_CREATE_VIEW_cnt_1s": 0,
+ "mysql_command_CREATE_VIEW_cnt_500ms": 0,
+ "mysql_command_CREATE_VIEW_cnt_500us": 0,
+ "mysql_command_CREATE_VIEW_cnt_50ms": 0,
+ "mysql_command_CREATE_VIEW_cnt_5ms": 0,
+ "mysql_command_CREATE_VIEW_cnt_5s": 0,
+ "mysql_command_CREATE_VIEW_cnt_INFs": 0,
+ "mysql_command_DEALLOCATE_Total_Time_us": 0,
+ "mysql_command_DEALLOCATE_Total_cnt": 0,
+ "mysql_command_DEALLOCATE_cnt_100ms": 0,
+ "mysql_command_DEALLOCATE_cnt_100us": 0,
+ "mysql_command_DEALLOCATE_cnt_10ms": 0,
+ "mysql_command_DEALLOCATE_cnt_10s": 0,
+ "mysql_command_DEALLOCATE_cnt_1ms": 0,
+ "mysql_command_DEALLOCATE_cnt_1s": 0,
+ "mysql_command_DEALLOCATE_cnt_500ms": 0,
+ "mysql_command_DEALLOCATE_cnt_500us": 0,
+ "mysql_command_DEALLOCATE_cnt_50ms": 0,
+ "mysql_command_DEALLOCATE_cnt_5ms": 0,
+ "mysql_command_DEALLOCATE_cnt_5s": 0,
+ "mysql_command_DEALLOCATE_cnt_INFs": 0,
+ "mysql_command_DELETE_Total_Time_us": 0,
+ "mysql_command_DELETE_Total_cnt": 0,
+ "mysql_command_DELETE_cnt_100ms": 0,
+ "mysql_command_DELETE_cnt_100us": 0,
+ "mysql_command_DELETE_cnt_10ms": 0,
+ "mysql_command_DELETE_cnt_10s": 0,
+ "mysql_command_DELETE_cnt_1ms": 0,
+ "mysql_command_DELETE_cnt_1s": 0,
+ "mysql_command_DELETE_cnt_500ms": 0,
+ "mysql_command_DELETE_cnt_500us": 0,
+ "mysql_command_DELETE_cnt_50ms": 0,
+ "mysql_command_DELETE_cnt_5ms": 0,
+ "mysql_command_DELETE_cnt_5s": 0,
+ "mysql_command_DELETE_cnt_INFs": 0,
+ "mysql_command_DESCRIBE_Total_Time_us": 0,
+ "mysql_command_DESCRIBE_Total_cnt": 0,
+ "mysql_command_DESCRIBE_cnt_100ms": 0,
+ "mysql_command_DESCRIBE_cnt_100us": 0,
+ "mysql_command_DESCRIBE_cnt_10ms": 0,
+ "mysql_command_DESCRIBE_cnt_10s": 0,
+ "mysql_command_DESCRIBE_cnt_1ms": 0,
+ "mysql_command_DESCRIBE_cnt_1s": 0,
+ "mysql_command_DESCRIBE_cnt_500ms": 0,
+ "mysql_command_DESCRIBE_cnt_500us": 0,
+ "mysql_command_DESCRIBE_cnt_50ms": 0,
+ "mysql_command_DESCRIBE_cnt_5ms": 0,
+ "mysql_command_DESCRIBE_cnt_5s": 0,
+ "mysql_command_DESCRIBE_cnt_INFs": 0,
+ "mysql_command_DROP_DATABASE_Total_Time_us": 0,
+ "mysql_command_DROP_DATABASE_Total_cnt": 0,
+ "mysql_command_DROP_DATABASE_cnt_100ms": 0,
+ "mysql_command_DROP_DATABASE_cnt_100us": 0,
+ "mysql_command_DROP_DATABASE_cnt_10ms": 0,
+ "mysql_command_DROP_DATABASE_cnt_10s": 0,
+ "mysql_command_DROP_DATABASE_cnt_1ms": 0,
+ "mysql_command_DROP_DATABASE_cnt_1s": 0,
+ "mysql_command_DROP_DATABASE_cnt_500ms": 0,
+ "mysql_command_DROP_DATABASE_cnt_500us": 0,
+ "mysql_command_DROP_DATABASE_cnt_50ms": 0,
+ "mysql_command_DROP_DATABASE_cnt_5ms": 0,
+ "mysql_command_DROP_DATABASE_cnt_5s": 0,
+ "mysql_command_DROP_DATABASE_cnt_INFs": 0,
+ "mysql_command_DROP_INDEX_Total_Time_us": 0,
+ "mysql_command_DROP_INDEX_Total_cnt": 0,
+ "mysql_command_DROP_INDEX_cnt_100ms": 0,
+ "mysql_command_DROP_INDEX_cnt_100us": 0,
+ "mysql_command_DROP_INDEX_cnt_10ms": 0,
+ "mysql_command_DROP_INDEX_cnt_10s": 0,
+ "mysql_command_DROP_INDEX_cnt_1ms": 0,
+ "mysql_command_DROP_INDEX_cnt_1s": 0,
+ "mysql_command_DROP_INDEX_cnt_500ms": 0,
+ "mysql_command_DROP_INDEX_cnt_500us": 0,
+ "mysql_command_DROP_INDEX_cnt_50ms": 0,
+ "mysql_command_DROP_INDEX_cnt_5ms": 0,
+ "mysql_command_DROP_INDEX_cnt_5s": 0,
+ "mysql_command_DROP_INDEX_cnt_INFs": 0,
+ "mysql_command_DROP_TABLE_Total_Time_us": 0,
+ "mysql_command_DROP_TABLE_Total_cnt": 0,
+ "mysql_command_DROP_TABLE_cnt_100ms": 0,
+ "mysql_command_DROP_TABLE_cnt_100us": 0,
+ "mysql_command_DROP_TABLE_cnt_10ms": 0,
+ "mysql_command_DROP_TABLE_cnt_10s": 0,
+ "mysql_command_DROP_TABLE_cnt_1ms": 0,
+ "mysql_command_DROP_TABLE_cnt_1s": 0,
+ "mysql_command_DROP_TABLE_cnt_500ms": 0,
+ "mysql_command_DROP_TABLE_cnt_500us": 0,
+ "mysql_command_DROP_TABLE_cnt_50ms": 0,
+ "mysql_command_DROP_TABLE_cnt_5ms": 0,
+ "mysql_command_DROP_TABLE_cnt_5s": 0,
+ "mysql_command_DROP_TABLE_cnt_INFs": 0,
+ "mysql_command_DROP_TRIGGER_Total_Time_us": 0,
+ "mysql_command_DROP_TRIGGER_Total_cnt": 0,
+ "mysql_command_DROP_TRIGGER_cnt_100ms": 0,
+ "mysql_command_DROP_TRIGGER_cnt_100us": 0,
+ "mysql_command_DROP_TRIGGER_cnt_10ms": 0,
+ "mysql_command_DROP_TRIGGER_cnt_10s": 0,
+ "mysql_command_DROP_TRIGGER_cnt_1ms": 0,
+ "mysql_command_DROP_TRIGGER_cnt_1s": 0,
+ "mysql_command_DROP_TRIGGER_cnt_500ms": 0,
+ "mysql_command_DROP_TRIGGER_cnt_500us": 0,
+ "mysql_command_DROP_TRIGGER_cnt_50ms": 0,
+ "mysql_command_DROP_TRIGGER_cnt_5ms": 0,
+ "mysql_command_DROP_TRIGGER_cnt_5s": 0,
+ "mysql_command_DROP_TRIGGER_cnt_INFs": 0,
+ "mysql_command_DROP_USER_Total_Time_us": 0,
+ "mysql_command_DROP_USER_Total_cnt": 0,
+ "mysql_command_DROP_USER_cnt_100ms": 0,
+ "mysql_command_DROP_USER_cnt_100us": 0,
+ "mysql_command_DROP_USER_cnt_10ms": 0,
+ "mysql_command_DROP_USER_cnt_10s": 0,
+ "mysql_command_DROP_USER_cnt_1ms": 0,
+ "mysql_command_DROP_USER_cnt_1s": 0,
+ "mysql_command_DROP_USER_cnt_500ms": 0,
+ "mysql_command_DROP_USER_cnt_500us": 0,
+ "mysql_command_DROP_USER_cnt_50ms": 0,
+ "mysql_command_DROP_USER_cnt_5ms": 0,
+ "mysql_command_DROP_USER_cnt_5s": 0,
+ "mysql_command_DROP_USER_cnt_INFs": 0,
+ "mysql_command_DROP_VIEW_Total_Time_us": 0,
+ "mysql_command_DROP_VIEW_Total_cnt": 0,
+ "mysql_command_DROP_VIEW_cnt_100ms": 0,
+ "mysql_command_DROP_VIEW_cnt_100us": 0,
+ "mysql_command_DROP_VIEW_cnt_10ms": 0,
+ "mysql_command_DROP_VIEW_cnt_10s": 0,
+ "mysql_command_DROP_VIEW_cnt_1ms": 0,
+ "mysql_command_DROP_VIEW_cnt_1s": 0,
+ "mysql_command_DROP_VIEW_cnt_500ms": 0,
+ "mysql_command_DROP_VIEW_cnt_500us": 0,
+ "mysql_command_DROP_VIEW_cnt_50ms": 0,
+ "mysql_command_DROP_VIEW_cnt_5ms": 0,
+ "mysql_command_DROP_VIEW_cnt_5s": 0,
+ "mysql_command_DROP_VIEW_cnt_INFs": 0,
+ "mysql_command_EXECUTE_Total_Time_us": 0,
+ "mysql_command_EXECUTE_Total_cnt": 0,
+ "mysql_command_EXECUTE_cnt_100ms": 0,
+ "mysql_command_EXECUTE_cnt_100us": 0,
+ "mysql_command_EXECUTE_cnt_10ms": 0,
+ "mysql_command_EXECUTE_cnt_10s": 0,
+ "mysql_command_EXECUTE_cnt_1ms": 0,
+ "mysql_command_EXECUTE_cnt_1s": 0,
+ "mysql_command_EXECUTE_cnt_500ms": 0,
+ "mysql_command_EXECUTE_cnt_500us": 0,
+ "mysql_command_EXECUTE_cnt_50ms": 0,
+ "mysql_command_EXECUTE_cnt_5ms": 0,
+ "mysql_command_EXECUTE_cnt_5s": 0,
+ "mysql_command_EXECUTE_cnt_INFs": 0,
+ "mysql_command_EXPLAIN_Total_Time_us": 0,
+ "mysql_command_EXPLAIN_Total_cnt": 0,
+ "mysql_command_EXPLAIN_cnt_100ms": 0,
+ "mysql_command_EXPLAIN_cnt_100us": 0,
+ "mysql_command_EXPLAIN_cnt_10ms": 0,
+ "mysql_command_EXPLAIN_cnt_10s": 0,
+ "mysql_command_EXPLAIN_cnt_1ms": 0,
+ "mysql_command_EXPLAIN_cnt_1s": 0,
+ "mysql_command_EXPLAIN_cnt_500ms": 0,
+ "mysql_command_EXPLAIN_cnt_500us": 0,
+ "mysql_command_EXPLAIN_cnt_50ms": 0,
+ "mysql_command_EXPLAIN_cnt_5ms": 0,
+ "mysql_command_EXPLAIN_cnt_5s": 0,
+ "mysql_command_EXPLAIN_cnt_INFs": 0,
+ "mysql_command_FLUSH_Total_Time_us": 0,
+ "mysql_command_FLUSH_Total_cnt": 0,
+ "mysql_command_FLUSH_cnt_100ms": 0,
+ "mysql_command_FLUSH_cnt_100us": 0,
+ "mysql_command_FLUSH_cnt_10ms": 0,
+ "mysql_command_FLUSH_cnt_10s": 0,
+ "mysql_command_FLUSH_cnt_1ms": 0,
+ "mysql_command_FLUSH_cnt_1s": 0,
+ "mysql_command_FLUSH_cnt_500ms": 0,
+ "mysql_command_FLUSH_cnt_500us": 0,
+ "mysql_command_FLUSH_cnt_50ms": 0,
+ "mysql_command_FLUSH_cnt_5ms": 0,
+ "mysql_command_FLUSH_cnt_5s": 0,
+ "mysql_command_FLUSH_cnt_INFs": 0,
+ "mysql_command_GRANT_Total_Time_us": 0,
+ "mysql_command_GRANT_Total_cnt": 0,
+ "mysql_command_GRANT_cnt_100ms": 0,
+ "mysql_command_GRANT_cnt_100us": 0,
+ "mysql_command_GRANT_cnt_10ms": 0,
+ "mysql_command_GRANT_cnt_10s": 0,
+ "mysql_command_GRANT_cnt_1ms": 0,
+ "mysql_command_GRANT_cnt_1s": 0,
+ "mysql_command_GRANT_cnt_500ms": 0,
+ "mysql_command_GRANT_cnt_500us": 0,
+ "mysql_command_GRANT_cnt_50ms": 0,
+ "mysql_command_GRANT_cnt_5ms": 0,
+ "mysql_command_GRANT_cnt_5s": 0,
+ "mysql_command_GRANT_cnt_INFs": 0,
+ "mysql_command_INSERT_Total_Time_us": 0,
+ "mysql_command_INSERT_Total_cnt": 0,
+ "mysql_command_INSERT_cnt_100ms": 0,
+ "mysql_command_INSERT_cnt_100us": 0,
+ "mysql_command_INSERT_cnt_10ms": 0,
+ "mysql_command_INSERT_cnt_10s": 0,
+ "mysql_command_INSERT_cnt_1ms": 0,
+ "mysql_command_INSERT_cnt_1s": 0,
+ "mysql_command_INSERT_cnt_500ms": 0,
+ "mysql_command_INSERT_cnt_500us": 0,
+ "mysql_command_INSERT_cnt_50ms": 0,
+ "mysql_command_INSERT_cnt_5ms": 0,
+ "mysql_command_INSERT_cnt_5s": 0,
+ "mysql_command_INSERT_cnt_INFs": 0,
+ "mysql_command_KILL_Total_Time_us": 0,
+ "mysql_command_KILL_Total_cnt": 0,
+ "mysql_command_KILL_cnt_100ms": 0,
+ "mysql_command_KILL_cnt_100us": 0,
+ "mysql_command_KILL_cnt_10ms": 0,
+ "mysql_command_KILL_cnt_10s": 0,
+ "mysql_command_KILL_cnt_1ms": 0,
+ "mysql_command_KILL_cnt_1s": 0,
+ "mysql_command_KILL_cnt_500ms": 0,
+ "mysql_command_KILL_cnt_500us": 0,
+ "mysql_command_KILL_cnt_50ms": 0,
+ "mysql_command_KILL_cnt_5ms": 0,
+ "mysql_command_KILL_cnt_5s": 0,
+ "mysql_command_KILL_cnt_INFs": 0,
+ "mysql_command_LOAD_Total_Time_us": 0,
+ "mysql_command_LOAD_Total_cnt": 0,
+ "mysql_command_LOAD_cnt_100ms": 0,
+ "mysql_command_LOAD_cnt_100us": 0,
+ "mysql_command_LOAD_cnt_10ms": 0,
+ "mysql_command_LOAD_cnt_10s": 0,
+ "mysql_command_LOAD_cnt_1ms": 0,
+ "mysql_command_LOAD_cnt_1s": 0,
+ "mysql_command_LOAD_cnt_500ms": 0,
+ "mysql_command_LOAD_cnt_500us": 0,
+ "mysql_command_LOAD_cnt_50ms": 0,
+ "mysql_command_LOAD_cnt_5ms": 0,
+ "mysql_command_LOAD_cnt_5s": 0,
+ "mysql_command_LOAD_cnt_INFs": 0,
+ "mysql_command_LOCK_TABLE_Total_Time_us": 0,
+ "mysql_command_LOCK_TABLE_Total_cnt": 0,
+ "mysql_command_LOCK_TABLE_cnt_100ms": 0,
+ "mysql_command_LOCK_TABLE_cnt_100us": 0,
+ "mysql_command_LOCK_TABLE_cnt_10ms": 0,
+ "mysql_command_LOCK_TABLE_cnt_10s": 0,
+ "mysql_command_LOCK_TABLE_cnt_1ms": 0,
+ "mysql_command_LOCK_TABLE_cnt_1s": 0,
+ "mysql_command_LOCK_TABLE_cnt_500ms": 0,
+ "mysql_command_LOCK_TABLE_cnt_500us": 0,
+ "mysql_command_LOCK_TABLE_cnt_50ms": 0,
+ "mysql_command_LOCK_TABLE_cnt_5ms": 0,
+ "mysql_command_LOCK_TABLE_cnt_5s": 0,
+ "mysql_command_LOCK_TABLE_cnt_INFs": 0,
+ "mysql_command_OPTIMIZE_Total_Time_us": 0,
+ "mysql_command_OPTIMIZE_Total_cnt": 0,
+ "mysql_command_OPTIMIZE_cnt_100ms": 0,
+ "mysql_command_OPTIMIZE_cnt_100us": 0,
+ "mysql_command_OPTIMIZE_cnt_10ms": 0,
+ "mysql_command_OPTIMIZE_cnt_10s": 0,
+ "mysql_command_OPTIMIZE_cnt_1ms": 0,
+ "mysql_command_OPTIMIZE_cnt_1s": 0,
+ "mysql_command_OPTIMIZE_cnt_500ms": 0,
+ "mysql_command_OPTIMIZE_cnt_500us": 0,
+ "mysql_command_OPTIMIZE_cnt_50ms": 0,
+ "mysql_command_OPTIMIZE_cnt_5ms": 0,
+ "mysql_command_OPTIMIZE_cnt_5s": 0,
+ "mysql_command_OPTIMIZE_cnt_INFs": 0,
+ "mysql_command_PREPARE_Total_Time_us": 0,
+ "mysql_command_PREPARE_Total_cnt": 0,
+ "mysql_command_PREPARE_cnt_100ms": 0,
+ "mysql_command_PREPARE_cnt_100us": 0,
+ "mysql_command_PREPARE_cnt_10ms": 0,
+ "mysql_command_PREPARE_cnt_10s": 0,
+ "mysql_command_PREPARE_cnt_1ms": 0,
+ "mysql_command_PREPARE_cnt_1s": 0,
+ "mysql_command_PREPARE_cnt_500ms": 0,
+ "mysql_command_PREPARE_cnt_500us": 0,
+ "mysql_command_PREPARE_cnt_50ms": 0,
+ "mysql_command_PREPARE_cnt_5ms": 0,
+ "mysql_command_PREPARE_cnt_5s": 0,
+ "mysql_command_PREPARE_cnt_INFs": 0,
+ "mysql_command_PURGE_Total_Time_us": 0,
+ "mysql_command_PURGE_Total_cnt": 0,
+ "mysql_command_PURGE_cnt_100ms": 0,
+ "mysql_command_PURGE_cnt_100us": 0,
+ "mysql_command_PURGE_cnt_10ms": 0,
+ "mysql_command_PURGE_cnt_10s": 0,
+ "mysql_command_PURGE_cnt_1ms": 0,
+ "mysql_command_PURGE_cnt_1s": 0,
+ "mysql_command_PURGE_cnt_500ms": 0,
+ "mysql_command_PURGE_cnt_500us": 0,
+ "mysql_command_PURGE_cnt_50ms": 0,
+ "mysql_command_PURGE_cnt_5ms": 0,
+ "mysql_command_PURGE_cnt_5s": 0,
+ "mysql_command_PURGE_cnt_INFs": 0,
+ "mysql_command_RENAME_TABLE_Total_Time_us": 0,
+ "mysql_command_RENAME_TABLE_Total_cnt": 0,
+ "mysql_command_RENAME_TABLE_cnt_100ms": 0,
+ "mysql_command_RENAME_TABLE_cnt_100us": 0,
+ "mysql_command_RENAME_TABLE_cnt_10ms": 0,
+ "mysql_command_RENAME_TABLE_cnt_10s": 0,
+ "mysql_command_RENAME_TABLE_cnt_1ms": 0,
+ "mysql_command_RENAME_TABLE_cnt_1s": 0,
+ "mysql_command_RENAME_TABLE_cnt_500ms": 0,
+ "mysql_command_RENAME_TABLE_cnt_500us": 0,
+ "mysql_command_RENAME_TABLE_cnt_50ms": 0,
+ "mysql_command_RENAME_TABLE_cnt_5ms": 0,
+ "mysql_command_RENAME_TABLE_cnt_5s": 0,
+ "mysql_command_RENAME_TABLE_cnt_INFs": 0,
+ "mysql_command_REPLACE_Total_Time_us": 0,
+ "mysql_command_REPLACE_Total_cnt": 0,
+ "mysql_command_REPLACE_cnt_100ms": 0,
+ "mysql_command_REPLACE_cnt_100us": 0,
+ "mysql_command_REPLACE_cnt_10ms": 0,
+ "mysql_command_REPLACE_cnt_10s": 0,
+ "mysql_command_REPLACE_cnt_1ms": 0,
+ "mysql_command_REPLACE_cnt_1s": 0,
+ "mysql_command_REPLACE_cnt_500ms": 0,
+ "mysql_command_REPLACE_cnt_500us": 0,
+ "mysql_command_REPLACE_cnt_50ms": 0,
+ "mysql_command_REPLACE_cnt_5ms": 0,
+ "mysql_command_REPLACE_cnt_5s": 0,
+ "mysql_command_REPLACE_cnt_INFs": 0,
+ "mysql_command_RESET_MASTER_Total_Time_us": 0,
+ "mysql_command_RESET_MASTER_Total_cnt": 0,
+ "mysql_command_RESET_MASTER_cnt_100ms": 0,
+ "mysql_command_RESET_MASTER_cnt_100us": 0,
+ "mysql_command_RESET_MASTER_cnt_10ms": 0,
+ "mysql_command_RESET_MASTER_cnt_10s": 0,
+ "mysql_command_RESET_MASTER_cnt_1ms": 0,
+ "mysql_command_RESET_MASTER_cnt_1s": 0,
+ "mysql_command_RESET_MASTER_cnt_500ms": 0,
+ "mysql_command_RESET_MASTER_cnt_500us": 0,
+ "mysql_command_RESET_MASTER_cnt_50ms": 0,
+ "mysql_command_RESET_MASTER_cnt_5ms": 0,
+ "mysql_command_RESET_MASTER_cnt_5s": 0,
+ "mysql_command_RESET_MASTER_cnt_INFs": 0,
+ "mysql_command_RESET_SLAVE_Total_Time_us": 0,
+ "mysql_command_RESET_SLAVE_Total_cnt": 0,
+ "mysql_command_RESET_SLAVE_cnt_100ms": 0,
+ "mysql_command_RESET_SLAVE_cnt_100us": 0,
+ "mysql_command_RESET_SLAVE_cnt_10ms": 0,
+ "mysql_command_RESET_SLAVE_cnt_10s": 0,
+ "mysql_command_RESET_SLAVE_cnt_1ms": 0,
+ "mysql_command_RESET_SLAVE_cnt_1s": 0,
+ "mysql_command_RESET_SLAVE_cnt_500ms": 0,
+ "mysql_command_RESET_SLAVE_cnt_500us": 0,
+ "mysql_command_RESET_SLAVE_cnt_50ms": 0,
+ "mysql_command_RESET_SLAVE_cnt_5ms": 0,
+ "mysql_command_RESET_SLAVE_cnt_5s": 0,
+ "mysql_command_RESET_SLAVE_cnt_INFs": 0,
+ "mysql_command_REVOKE_Total_Time_us": 0,
+ "mysql_command_REVOKE_Total_cnt": 0,
+ "mysql_command_REVOKE_cnt_100ms": 0,
+ "mysql_command_REVOKE_cnt_100us": 0,
+ "mysql_command_REVOKE_cnt_10ms": 0,
+ "mysql_command_REVOKE_cnt_10s": 0,
+ "mysql_command_REVOKE_cnt_1ms": 0,
+ "mysql_command_REVOKE_cnt_1s": 0,
+ "mysql_command_REVOKE_cnt_500ms": 0,
+ "mysql_command_REVOKE_cnt_500us": 0,
+ "mysql_command_REVOKE_cnt_50ms": 0,
+ "mysql_command_REVOKE_cnt_5ms": 0,
+ "mysql_command_REVOKE_cnt_5s": 0,
+ "mysql_command_REVOKE_cnt_INFs": 0,
+ "mysql_command_ROLLBACK_Total_Time_us": 0,
+ "mysql_command_ROLLBACK_Total_cnt": 0,
+ "mysql_command_ROLLBACK_cnt_100ms": 0,
+ "mysql_command_ROLLBACK_cnt_100us": 0,
+ "mysql_command_ROLLBACK_cnt_10ms": 0,
+ "mysql_command_ROLLBACK_cnt_10s": 0,
+ "mysql_command_ROLLBACK_cnt_1ms": 0,
+ "mysql_command_ROLLBACK_cnt_1s": 0,
+ "mysql_command_ROLLBACK_cnt_500ms": 0,
+ "mysql_command_ROLLBACK_cnt_500us": 0,
+ "mysql_command_ROLLBACK_cnt_50ms": 0,
+ "mysql_command_ROLLBACK_cnt_5ms": 0,
+ "mysql_command_ROLLBACK_cnt_5s": 0,
+ "mysql_command_ROLLBACK_cnt_INFs": 0,
+ "mysql_command_SAVEPOINT_Total_Time_us": 0,
+ "mysql_command_SAVEPOINT_Total_cnt": 0,
+ "mysql_command_SAVEPOINT_cnt_100ms": 0,
+ "mysql_command_SAVEPOINT_cnt_100us": 0,
+ "mysql_command_SAVEPOINT_cnt_10ms": 0,
+ "mysql_command_SAVEPOINT_cnt_10s": 0,
+ "mysql_command_SAVEPOINT_cnt_1ms": 0,
+ "mysql_command_SAVEPOINT_cnt_1s": 0,
+ "mysql_command_SAVEPOINT_cnt_500ms": 0,
+ "mysql_command_SAVEPOINT_cnt_500us": 0,
+ "mysql_command_SAVEPOINT_cnt_50ms": 0,
+ "mysql_command_SAVEPOINT_cnt_5ms": 0,
+ "mysql_command_SAVEPOINT_cnt_5s": 0,
+ "mysql_command_SAVEPOINT_cnt_INFs": 0,
+ "mysql_command_SELECT_FOR_UPDATE_Total_Time_us": 0,
+ "mysql_command_SELECT_FOR_UPDATE_Total_cnt": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_100ms": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_100us": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_10ms": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_10s": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_1ms": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_1s": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_500ms": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_500us": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_50ms": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_5ms": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_5s": 0,
+ "mysql_command_SELECT_FOR_UPDATE_cnt_INFs": 0,
+ "mysql_command_SELECT_Total_Time_us": 4673958076637,
+ "mysql_command_SELECT_Total_cnt": 68490650,
+ "mysql_command_SELECT_cnt_100ms": 4909816,
+ "mysql_command_SELECT_cnt_100us": 32185976,
+ "mysql_command_SELECT_cnt_10ms": 2955830,
+ "mysql_command_SELECT_cnt_10s": 497,
+ "mysql_command_SELECT_cnt_1ms": 481335,
+ "mysql_command_SELECT_cnt_1s": 1321917,
+ "mysql_command_SELECT_cnt_500ms": 11123900,
+ "mysql_command_SELECT_cnt_500us": 36650,
+ "mysql_command_SELECT_cnt_50ms": 10468460,
+ "mysql_command_SELECT_cnt_5ms": 4600948,
+ "mysql_command_SELECT_cnt_5s": 403451,
+ "mysql_command_SELECT_cnt_INFs": 1870,
+ "mysql_command_SET_Total_Time_us": 0,
+ "mysql_command_SET_Total_cnt": 0,
+ "mysql_command_SET_cnt_100ms": 0,
+ "mysql_command_SET_cnt_100us": 0,
+ "mysql_command_SET_cnt_10ms": 0,
+ "mysql_command_SET_cnt_10s": 0,
+ "mysql_command_SET_cnt_1ms": 0,
+ "mysql_command_SET_cnt_1s": 0,
+ "mysql_command_SET_cnt_500ms": 0,
+ "mysql_command_SET_cnt_500us": 0,
+ "mysql_command_SET_cnt_50ms": 0,
+ "mysql_command_SET_cnt_5ms": 0,
+ "mysql_command_SET_cnt_5s": 0,
+ "mysql_command_SET_cnt_INFs": 0,
+ "mysql_command_SHOW_TABLE_STATUS_Total_Time_us": 0,
+ "mysql_command_SHOW_TABLE_STATUS_Total_cnt": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_100ms": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_100us": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_10ms": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_10s": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_1ms": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_1s": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_500ms": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_500us": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_50ms": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_5ms": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_5s": 0,
+ "mysql_command_SHOW_TABLE_STATUS_cnt_INFs": 0,
+ "mysql_command_SHOW_Total_Time_us": 2158,
+ "mysql_command_SHOW_Total_cnt": 1,
+ "mysql_command_SHOW_cnt_100ms": 0,
+ "mysql_command_SHOW_cnt_100us": 0,
+ "mysql_command_SHOW_cnt_10ms": 0,
+ "mysql_command_SHOW_cnt_10s": 0,
+ "mysql_command_SHOW_cnt_1ms": 0,
+ "mysql_command_SHOW_cnt_1s": 0,
+ "mysql_command_SHOW_cnt_500ms": 0,
+ "mysql_command_SHOW_cnt_500us": 0,
+ "mysql_command_SHOW_cnt_50ms": 0,
+ "mysql_command_SHOW_cnt_5ms": 1,
+ "mysql_command_SHOW_cnt_5s": 0,
+ "mysql_command_SHOW_cnt_INFs": 0,
+ "mysql_command_START_TRANSACTION_Total_Time_us": 0,
+ "mysql_command_START_TRANSACTION_Total_cnt": 0,
+ "mysql_command_START_TRANSACTION_cnt_100ms": 0,
+ "mysql_command_START_TRANSACTION_cnt_100us": 0,
+ "mysql_command_START_TRANSACTION_cnt_10ms": 0,
+ "mysql_command_START_TRANSACTION_cnt_10s": 0,
+ "mysql_command_START_TRANSACTION_cnt_1ms": 0,
+ "mysql_command_START_TRANSACTION_cnt_1s": 0,
+ "mysql_command_START_TRANSACTION_cnt_500ms": 0,
+ "mysql_command_START_TRANSACTION_cnt_500us": 0,
+ "mysql_command_START_TRANSACTION_cnt_50ms": 0,
+ "mysql_command_START_TRANSACTION_cnt_5ms": 0,
+ "mysql_command_START_TRANSACTION_cnt_5s": 0,
+ "mysql_command_START_TRANSACTION_cnt_INFs": 0,
+ "mysql_command_TRUNCATE_TABLE_Total_Time_us": 0,
+ "mysql_command_TRUNCATE_TABLE_Total_cnt": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_100ms": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_100us": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_10ms": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_10s": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_1ms": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_1s": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_500ms": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_500us": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_50ms": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_5ms": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_5s": 0,
+ "mysql_command_TRUNCATE_TABLE_cnt_INFs": 0,
+ "mysql_command_UNKNOWN_Total_Time_us": 0,
+ "mysql_command_UNKNOWN_Total_cnt": 0,
+ "mysql_command_UNKNOWN_cnt_100ms": 0,
+ "mysql_command_UNKNOWN_cnt_100us": 0,
+ "mysql_command_UNKNOWN_cnt_10ms": 0,
+ "mysql_command_UNKNOWN_cnt_10s": 0,
+ "mysql_command_UNKNOWN_cnt_1ms": 0,
+ "mysql_command_UNKNOWN_cnt_1s": 0,
+ "mysql_command_UNKNOWN_cnt_500ms": 0,
+ "mysql_command_UNKNOWN_cnt_500us": 0,
+ "mysql_command_UNKNOWN_cnt_50ms": 0,
+ "mysql_command_UNKNOWN_cnt_5ms": 0,
+ "mysql_command_UNKNOWN_cnt_5s": 0,
+ "mysql_command_UNKNOWN_cnt_INFs": 0,
+ "mysql_command_UNLOCK_TABLES_Total_Time_us": 0,
+ "mysql_command_UNLOCK_TABLES_Total_cnt": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_100ms": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_100us": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_10ms": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_10s": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_1ms": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_1s": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_500ms": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_500us": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_50ms": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_5ms": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_5s": 0,
+ "mysql_command_UNLOCK_TABLES_cnt_INFs": 0,
+ "mysql_command_UPDATE_Total_Time_us": 0,
+ "mysql_command_UPDATE_Total_cnt": 0,
+ "mysql_command_UPDATE_cnt_100ms": 0,
+ "mysql_command_UPDATE_cnt_100us": 0,
+ "mysql_command_UPDATE_cnt_10ms": 0,
+ "mysql_command_UPDATE_cnt_10s": 0,
+ "mysql_command_UPDATE_cnt_1ms": 0,
+ "mysql_command_UPDATE_cnt_1s": 0,
+ "mysql_command_UPDATE_cnt_500ms": 0,
+ "mysql_command_UPDATE_cnt_500us": 0,
+ "mysql_command_UPDATE_cnt_50ms": 0,
+ "mysql_command_UPDATE_cnt_5ms": 0,
+ "mysql_command_UPDATE_cnt_5s": 0,
+ "mysql_command_UPDATE_cnt_INFs": 0,
+ "mysql_command_USE_Total_Time_us": 0,
+ "mysql_command_USE_Total_cnt": 0,
+ "mysql_command_USE_cnt_100ms": 0,
+ "mysql_command_USE_cnt_100us": 0,
+ "mysql_command_USE_cnt_10ms": 0,
+ "mysql_command_USE_cnt_10s": 0,
+ "mysql_command_USE_cnt_1ms": 0,
+ "mysql_command_USE_cnt_1s": 0,
+ "mysql_command_USE_cnt_500ms": 0,
+ "mysql_command_USE_cnt_500us": 0,
+ "mysql_command_USE_cnt_50ms": 0,
+ "mysql_command_USE_cnt_5ms": 0,
+ "mysql_command_USE_cnt_5s": 0,
+ "mysql_command_USE_cnt_INFs": 0,
+ "mysql_firewall_rules_config": 329,
+ "mysql_firewall_rules_table": 0,
+ "mysql_firewall_users_config": 0,
+ "mysql_firewall_users_table": 0,
+ "mysql_frontend_buffers_bytes": 196608,
+ "mysql_killed_backend_connections": 0,
+ "mysql_killed_backend_queries": 0,
+ "mysql_query_rules_memory": 22825,
+ "mysql_session_internal_bytes": 20232,
+ "mysql_unexpected_frontend_com_quit": 0,
+ "mysql_unexpected_frontend_packets": 0,
+ "mysql_user_first_user_frontend_connections": 0,
+ "mysql_user_first_user_frontend_connections_utilization": 0,
+ "mysql_user_second_user_frontend_connections": 3,
+ "mysql_user_second_user_frontend_connections_utilization": 20,
+ "queries_with_max_lag_ms": 0,
+ "queries_with_max_lag_ms__delayed": 0,
+ "queries_with_max_lag_ms__total_wait_time_us": 0,
+ "query_digest_memory": 13688,
+ "stack_memory_admin_threads": 16777216,
+ "stack_memory_cluster_threads": 0,
+ "stack_memory_mysql_threads": 33554432,
+ "whitelisted_sqli_fingerprint": 0,
+ }
+
+ require.Equal(t, expected, mx)
+ },
+ },
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ db, mock, err := sqlmock.New(
+ sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual),
+ )
+ require.NoError(t, err)
+ my := New()
+ my.db = db
+ defer func() { _ = db.Close() }()
+
+ require.NoError(t, my.Init())
+
+ for i, step := range test {
+ t.Run(fmt.Sprintf("step[%d]", i), func(t *testing.T) {
+ step.prepareMock(t, mock)
+ step.check(t, my)
+ })
+ }
+ assert.NoError(t, mock.ExpectationsWereMet())
+ })
+ }
+}
+
+func mustMockRows(t *testing.T, data []byte) *sqlmock.Rows {
+ rows, err := prepareMockRows(data)
+ require.NoError(t, err)
+ return rows
+}
+
+func mockExpect(t *testing.T, mock sqlmock.Sqlmock, query string, rows []byte) {
+ mock.ExpectQuery(query).WillReturnRows(mustMockRows(t, rows)).RowsWillBeClosed()
+}
+
+func mockExpectErr(mock sqlmock.Sqlmock, query string) {
+ mock.ExpectQuery(query).WillReturnError(fmt.Errorf("mock error (%s)", query))
+}
+
+func prepareMockRows(data []byte) (*sqlmock.Rows, error) {
+ if len(data) == 0 {
+ return sqlmock.NewRows(nil), nil
+ }
+
+ r := bytes.NewReader(data)
+ sc := bufio.NewScanner(r)
+
+ var numColumns int
+ var rows *sqlmock.Rows
+
+ for sc.Scan() {
+ s := strings.TrimSpace(strings.Trim(sc.Text(), "|"))
+ switch {
+ case s == "",
+ strings.HasPrefix(s, "+"),
+ strings.HasPrefix(s, "ft_boolean_syntax"):
+ continue
+ }
+
+ parts := strings.Split(s, "|")
+ for i, v := range parts {
+ parts[i] = strings.TrimSpace(v)
+ }
+
+ if rows == nil {
+ numColumns = len(parts)
+ rows = sqlmock.NewRows(parts)
+ continue
+ }
+
+ if len(parts) != numColumns {
+ return nil, fmt.Errorf("prepareMockRows(): columns != values (%d/%d)", numColumns, len(parts))
+ }
+
+ values := make([]driver.Value, len(parts))
+ for i, v := range parts {
+ values[i] = v
+ }
+ rows.AddRow(values...)
+ }
+
+ if rows == nil {
+ return nil, errors.New("prepareMockRows(): nil rows result")
+ }
+
+ return rows, sc.Err()
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.json b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.json
new file mode 100644
index 000000000..ed8b72dcb
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.json
@@ -0,0 +1,5 @@
+{
+ "update_every": 123,
+ "dsn": "ok",
+ "timeout": 123.123
+}
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.yaml
new file mode 100644
index 000000000..caff49039
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/config.yaml
@@ -0,0 +1,3 @@
+update_every: 123
+dsn: "ok"
+timeout: 123.123
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_memory_metrics.txt b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_memory_metrics.txt
new file mode 100644
index 000000000..99ec093e1
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_memory_metrics.txt
@@ -0,0 +1,21 @@
++------------------------------+----------------+
+| Variable_Name | Variable_Value |
++------------------------------+----------------+
+| SQLite3_memory_bytes | 6017144 |
+| jemalloc_resident | 403759104 |
+| jemalloc_active | 385101824 |
+| jemalloc_allocated | 379402432 |
+| jemalloc_mapped | 430993408 |
+| jemalloc_metadata | 17418872 |
+| jemalloc_retained | 260542464 |
+| Auth_memory | 1044 |
+| query_digest_memory | 13688 |
+| mysql_query_rules_memory | 22825 |
+| mysql_firewall_users_table | 0 |
+| mysql_firewall_users_config | 0 |
+| mysql_firewall_rules_table | 0 |
+| mysql_firewall_rules_config | 329 |
+| stack_memory_mysql_threads | 33554432 |
+| stack_memory_admin_threads | 16777216 |
+| stack_memory_cluster_threads | 0 |
++------------------------------+----------------+ \ No newline at end of file
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_commands_counters.txt b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_commands_counters.txt
new file mode 100644
index 000000000..6ab6bb830
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_commands_counters.txt
@@ -0,0 +1,56 @@
++-------------------+---------------+-----------+-----------+-----------+---------+---------+----------+----------+-----------+-----------+---------+--------+---------+----------+
+| Command | Total_Time_us | Total_cnt | cnt_100us | cnt_500us | cnt_1ms | cnt_5ms | cnt_10ms | cnt_50ms | cnt_100ms | cnt_500ms | cnt_1s | cnt_5s | cnt_10s | cnt_INFs |
++-------------------+---------------+-----------+-----------+-----------+---------+---------+----------+----------+-----------+-----------+---------+--------+---------+----------+
+| ALTER_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| ALTER_VIEW | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| ANALYZE_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| BEGIN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CALL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CHANGE_MASTER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| COMMIT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_DATABASE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_INDEX | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_TEMPORARY | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_TRIGGER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_USER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| CREATE_VIEW | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DEALLOCATE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DELETE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DESCRIBE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DROP_DATABASE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DROP_INDEX | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DROP_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DROP_TRIGGER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DROP_USER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| DROP_VIEW | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| GRANT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| EXECUTE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| EXPLAIN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| FLUSH | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| INSERT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| KILL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| LOAD | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| LOCK_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| OPTIMIZE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| PREPARE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| PURGE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| RENAME_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| RESET_MASTER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| RESET_SLAVE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| REPLACE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| REVOKE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| ROLLBACK | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| SAVEPOINT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| SELECT | 4673958076637 | 68490650 | 32185976 | 36650 | 481335 | 4600948 | 2955830 | 10468460 | 4909816 | 11123900 | 1321917 | 403451 | 497 | 1870 |
+| SELECT_FOR_UPDATE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| SET | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| SHOW_TABLE_STATUS | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| START_TRANSACTION | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| TRUNCATE_TABLE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| UNLOCK_TABLES | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| UPDATE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| USE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| SHOW | 2158 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| UNKNOWN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
++-------------------+---------------+-----------+-----------+-----------+---------+---------+----------+----------+-----------+-----------+---------+--------+---------+----------+
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_connection_pool .txt b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_connection_pool .txt
new file mode 100644
index 000000000..80b53e1af
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_connection_pool .txt
@@ -0,0 +1,11 @@
++----+-------------------+--------+--------+----------+----------+--------+---------+---------+-----------------+-----------------+------------+
+| hostgroup | srv_host | srv_port | status | ConnUsed | ConnFree | ConnOK | ConnERR | Queries | Bytes_data_sent | Bytes_data_recv | Latency_us |
++-----------+-------------------+----------+--------+----------+----------+--------+---------+---------+-----------------+-----------------+------------+
+| 10 | back001-db-master | 6001 | ONLINE | 69 | 423 | 524 | 0 | 8970367 | 9858463664 | 145193069937 | 17684 |
+| 11 | back001-db-master | 6002 | ONLINE | 0 | 1 | 1 | 0 | 69 | 187675 | 2903 | 17684 |
+| 11 | back001-db-reader | 6003 | ONLINE | 0 | 11 | 11 | 0 | 63488 | 163690013 | 4994101 | 113 |
+| 20 | back002-db-master | 6004 | ONLINE | 9 | 188 | 197 | 2 | 849461 | 1086994186 | 266034339 | 101981 |
+| 21 | back002-db-reader | 6005 | ONLINE | 0 | 1 | 1 | 0 | 8 | 6992 | 984 | 230 |
+| 31 | back003-db-master | 6006 | ONLINE | 0 | 3 | 3 | 0 | 3276 | 712803 | 81438709 | 231 |
+| 31 | back003-db-reader | 6007 | ONLINE | 1 | 70 | 71 | 0 | 2356904 | 411900849 | 115810708275 | 230 |
++-----------+-------------------+--------+--------+----------+----------+--------+---------+---------+-----------------+-----------------+--------------+ \ No newline at end of file
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_global.txt b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_global.txt
new file mode 100644
index 000000000..442266c45
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_global.txt
@@ -0,0 +1,106 @@
++---------------------------------------------+----------------+
+| Variable_Name | Variable_Value |
++---------------------------------------------+----------------+
+| ProxySQL_Uptime | 26748286 |
+| Active_Transactions | 0 |
+| Client_Connections_aborted | 2 |
+| Client_Connections_connected | 3 |
+| Client_Connections_created | 5458991 |
+| Server_Connections_aborted | 9979 |
+| Server_Connections_connected | 13 |
+| Server_Connections_created | 2122254 |
+| Server_Connections_delayed | 0 |
+| Client_Connections_non_idle | 3 |
+| Queries_backends_bytes_recv | 5896210168 |
+| Queries_backends_bytes_sent | 4329581500 |
+| Queries_frontends_bytes_recv | 7434816962 |
+| Queries_frontends_bytes_sent | 11643634097 |
+| Query_Processor_time_nsec | 0 |
+| Backend_query_time_nsec | 0 |
+| mysql_backend_buffers_bytes | 0 |
+| mysql_frontend_buffers_bytes | 196608 |
+| mysql_session_internal_bytes | 20232 |
+| Com_autocommit | 0 |
+| Com_autocommit_filtered | 0 |
+| Com_commit | 0 |
+| Com_commit_filtered | 0 |
+| Com_rollback | 0 |
+| Com_rollback_filtered | 0 |
+| Com_backend_change_user | 188694 |
+| Com_backend_init_db | 0 |
+| Com_backend_set_names | 1517893 |
+| Com_frontend_init_db | 2 |
+| Com_frontend_set_names | 0 |
+| Com_frontend_use_db | 0 |
+| Com_backend_stmt_prepare | 16858208 |
+| Com_backend_stmt_execute | 36303146 |
+| Com_backend_stmt_close | 0 |
+| Com_frontend_stmt_prepare | 32185987 |
+| Com_frontend_stmt_execute | 36314138 |
+| Com_frontend_stmt_close | 32137933 |
+| Mirror_concurrency | 0 |
+| Mirror_queue_length | 0 |
+| Questions | 100638067 |
+| Selects_for_update__autocommit0 | 0 |
+| Slow_queries | 405818 |
+| GTID_consistent_queries | 0 |
+| GTID_session_collected | 0 |
+| Servers_table_version | 37 |
+| MySQL_Thread_Workers | 4 |
+| Access_Denied_Wrong_Password | 2 |
+| Access_Denied_Max_Connections | 0 |
+| Access_Denied_Max_User_Connections | 0 |
+| MySQL_Monitor_Workers | 10 |
+| MySQL_Monitor_Workers_Aux | 0 |
+| MySQL_Monitor_Workers_Started | 10 |
+| MySQL_Monitor_connect_check_OK | 3548306 |
+| MySQL_Monitor_connect_check_ERR | 130 |
+| MySQL_Monitor_ping_check_OK | 21289849 |
+| MySQL_Monitor_ping_check_ERR | 108271 |
+| MySQL_Monitor_read_only_check_OK | 106246409 |
+| MySQL_Monitor_read_only_check_ERR | 19610 |
+| MySQL_Monitor_replication_lag_check_OK | 28702388 |
+| MySQL_Monitor_replication_lag_check_ERR | 482 |
+| ConnPool_get_conn_latency_awareness | 0 |
+| ConnPool_get_conn_immediate | 13361 |
+| ConnPool_get_conn_success | 36319474 |
+| ConnPool_get_conn_failure | 212943 |
+| generated_error_packets | 231 |
+| max_connect_timeouts | 227 |
+| backend_lagging_during_query | 8880 |
+| backend_offline_during_query | 8 |
+| queries_with_max_lag_ms | 0 |
+| queries_with_max_lag_ms__delayed | 0 |
+| queries_with_max_lag_ms__total_wait_time_us | 0 |
+| mysql_unexpected_frontend_com_quit | 0 |
+| Client_Connections_hostgroup_locked | 0 |
+| hostgroup_locked_set_cmds | 0 |
+| hostgroup_locked_queries | 0 |
+| mysql_unexpected_frontend_packets | 0 |
+| aws_aurora_replicas_skipped_during_query | 0 |
+| automatic_detected_sql_injection | 0 |
+| whitelisted_sqli_fingerprint | 0 |
+| mysql_killed_backend_connections | 0 |
+| mysql_killed_backend_queries | 0 |
+| MyHGM_myconnpoll_get | 36519056 |
+| MyHGM_myconnpoll_get_ok | 36306113 |
+| MyHGM_myconnpoll_push | 37358734 |
+| MyHGM_myconnpoll_destroy | 15150 |
+| MyHGM_myconnpoll_reset | 2 |
+| SQLite3_memory_bytes | 6021248 |
+| ConnPool_memory_bytes | 932248 |
+| Stmt_Client_Active_Total | 18 |
+| Stmt_Client_Active_Unique | 18 |
+| Stmt_Server_Active_Total | 101 |
+| Stmt_Server_Active_Unique | 39 |
+| Stmt_Max_Stmt_id | 66 |
+| Stmt_Cached | 65 |
+| Query_Cache_Memory_bytes | 0 |
+| Query_Cache_count_GET | 0 |
+| Query_Cache_count_GET_OK | 0 |
+| Query_Cache_count_SET | 0 |
+| Query_Cache_bytes_IN | 0 |
+| Query_Cache_bytes_OUT | 0 |
+| Query_Cache_Purged | 0 |
+| Query_Cache_Entries | 0 |
++---------------------------------------------+----------------+
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_users.txt b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_users.txt
new file mode 100644
index 000000000..900776b76
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/stats_mysql_users.txt
@@ -0,0 +1,6 @@
++-------------------------+----------------------+--------------------------+
+| username | frontend_connections | frontend_max_connections |
++-------------------------+----------------------+--------------------------+
+| first_user | 0 | 200 |
+| second_user | 3 | 15 |
++-------------------------+----------------------+--------------------------+
diff --git a/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/version.txt b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/version.txt
new file mode 100644
index 000000000..429a880b7
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/proxysql/testdata/v2.0.10/version.txt
@@ -0,0 +1,5 @@
++---------------------+
+| version() |
++---------------------+
+| 2.0.10-27-g5b319972 |
++---------------------+ \ No newline at end of file