From ca1daa583d2c24652b178b4798c89297645a66a4 Mon Sep 17 00:00:00 2001 From: Filip Chabik Date: Thu, 12 Jan 2017 12:09:53 +0100 Subject: [PATCH 1/4] Collect more useful MySQL data Source: https://github.com/matejzero/grafana-dashboards/blob/master/mysql/collectd-mysql.py --- mysql.py | 79 +++++++++++++++++++++----------------------------------- 1 file changed, 29 insertions(+), 50 deletions(-) diff --git a/mysql.py b/mysql.py index 95f9bb1..9027803 100644 --- a/mysql.py +++ b/mysql.py @@ -9,17 +9,18 @@ # Configuration: # Import mysql # -# Host localhost -# Port 3306 (optional) -# User root -# Password xxxx -# HeartbeatTable percona.heartbeat (optional, if using pt-heartbeat) +# Host localhost +# Port 3306 (optional) +# User root +# Password xxxx +# HeartbeatTable percona.heartbeat (optional, if using pt-heartbeat) # Verbose true (optional, to enable debugging) # # # Requires "MySQLdb" for Python # # Author: Chris Boulton +# Added metrics for Grafana Dashboards by Matej Zerovnik # License: MIT (http://www.opensource.org/licenses/mit-license.php) # @@ -55,11 +56,14 @@ 'Created_tmp_disk_tables': 'counter', 'Created_tmp_files': 'counter', 'Created_tmp_tables': 'counter', + 'Innodb_buffer_pool_bytes_data': 'gauge', + 'Innodb_buffer_pool_bytes_dirty': 'gauge', 'Innodb_buffer_pool_pages_data': 'gauge', 'Innodb_buffer_pool_pages_dirty': 'gauge', 'Innodb_buffer_pool_pages_free': 'gauge', 'Innodb_buffer_pool_pages_total': 'gauge', 'Innodb_buffer_pool_read_requests': 'counter', + 'Innodb_buffer_pool_write_requests': 'counter', 'Innodb_buffer_pool_reads': 'counter', 'Innodb_checkpoint_age': 'gauge', 'Innodb_checkpoint_max_age': 'gauge', @@ -82,6 +86,7 @@ 'Innodb_ibuf_size': 'gauge', 'Innodb_lsn_current': 'counter', 'Innodb_lsn_flushed': 'counter', + 'Innodb_log_writes': 'counter', 'Innodb_max_trx_id': 'counter', 'Innodb_mem_adaptive_hash': 'gauge', 'Innodb_mem_dictionary': 'gauge', @@ -90,9 +95,11 @@ 'Innodb_mutex_spin_rounds': 'counter', 'Innodb_mutex_spin_waits': 'counter', 'Innodb_os_log_pending_fsyncs': 'gauge', + 'Innodb_os_log_written': 'counter', 'Innodb_pages_created': 'counter', 'Innodb_pages_read': 'counter', 'Innodb_pages_written': 'counter', + 'Innodb_page_size': 'gauge', 'Innodb_row_lock_time': 'counter', 'Innodb_row_lock_time_avg': 'gauge', 'Innodb_row_lock_time_max': 'gauge', @@ -132,6 +139,7 @@ 'Qcache_not_cached': 'counter', 'Qcache_queries_in_cache': 'counter', 'Qcache_total_blocks': 'counter', + 'Queries': 'counter', 'Questions': 'counter', 'Select_full_join': 'counter', 'Select_full_range_join': 'counter', @@ -158,41 +166,6 @@ 'Threads_created': 'counter', 'Threads_running': 'gauge', 'Uptime': 'gauge', - 'wsrep_apply_oooe': 'gauge', - 'wsrep_apply_oool': 'gauge', - 'wsrep_apply_window': 'gauge', - 'wsrep_causal_reads': 'gauge', - 'wsrep_cert_deps_distance': 'gauge', - 'wsrep_cert_index_size': 'gauge', - 'wsrep_cert_interval': 'gauge', - 'wsrep_cluster_size': 'gauge', - 'wsrep_commit_oooe': 'gauge', - 'wsrep_commit_oool': 'gauge', - 'wsrep_commit_window': 'gauge', - 'wsrep_flow_control_paused': 'gauge', - 'wsrep_flow_control_paused_ns': 'counter', - 'wsrep_flow_control_recv': 'counter', - 'wsrep_flow_control_sent': 'counter', - 'wsrep_local_bf_aborts': 'counter', - 'wsrep_local_cert_failures': 'counter', - 'wsrep_local_commits': 'counter', - 'wsrep_local_recv_queue': 'gauge', - 'wsrep_local_recv_queue_avg': 'gauge', - 'wsrep_local_recv_queue_max': 'gauge', - 'wsrep_local_recv_queue_min': 'gauge', - 'wsrep_local_replays': 'gauge', - 'wsrep_local_send_queue': 'gauge', - 'wsrep_local_send_queue_avg': 'gauge', - 'wsrep_local_send_queue_max': 'gauge', - 'wsrep_local_send_queue_min': 'gauge', - 'wsrep_received': 'counter', - 'wsrep_received_bytes': 'counter', - 'wsrep_repl_data_bytes': 'counter', - 'wsrep_repl_keys': 'counter', - 'wsrep_repl_keys_bytes': 'counter', - 'wsrep_repl_other_bytes': 'counter', - 'wsrep_replicated': 'counter', - 'wsrep_replicated_bytes': 'counter', } MYSQL_VARS = [ @@ -203,15 +176,20 @@ 'innodb_io_capacity', 'innodb_log_buffer_size', 'innodb_log_file_size', + 'innodb_log_files_in_group', + 'innodb_max_purge_lag', 'innodb_open_files', 'innodb_open_files', 'join_buffer_size', + 'key_buffer_size', + 'key_cache_block_size', 'max_connections', 'open_files_limit', 'query_cache_limit', 'query_cache_size', 'query_cache_size', 'read_buffer_size', + 'read_only', 'table_cache', 'table_definition_cache', 'table_open_cache', @@ -301,11 +279,11 @@ 'Page hash ': { 'page_hash_memory': 2, }, - # File system 657820264 (812272 + 657007992) + # File system 657820264 (812272 + 657007992) 'File system ': { 'file_system_memory': 2, }, - # Lock system 143820296 (143819576 + 720) + # Lock system 143820296 (143819576 + 720) 'Lock system ': { 'lock_system_memory': 2, }, @@ -317,7 +295,7 @@ # --Thread 139954487744256 has waited at dict0dict.cc line 472 for 0.0000 seconds the semaphore: 'seconds the semaphore': { 'innodb_sem_waits': lambda row, stats: stats['innodb_sem_waits'] + 1, - 'innodb_sem_wait_time_ms': lambda row, stats: int(float(row[9]) * 1000), + 'innodb_sem_wait_time_ms': lambda row, stats: float(row[9]) * 1000, }, # mysql tables in use 1, locked 1 'mysql tables in use': { @@ -384,6 +362,7 @@ def fetch_mysql_slave_stats(conn): status = { 'relay_log_space': slave_row['Relay_Log_Space'], + 'last_errno': slave_row['Last_Errno'], 'slave_lag': slave_row['Seconds_Behind_Master'] if slave_row['Seconds_Behind_Master'] != None else 0, } @@ -398,8 +377,8 @@ def fetch_mysql_slave_stats(conn): if 'delay' in row and row['delay'] != None: status['slave_lag'] = row['delay'] - status['slave_running'] = 1 if slave_row['Slave_SQL_Running'] == 'Yes' else 0 - status['slave_stopped'] = 1 if slave_row['Slave_SQL_Running'] != 'Yes' else 0 + status['slave_sql_running'] = 1 if slave_row['Slave_SQL_Running'] == 'Yes' else 0 + status['slave_io_running'] = 1 if slave_row['Slave_IO_Running'] == 'Yes' else 0 return status def fetch_mysql_process_states(conn): @@ -422,7 +401,10 @@ def fetch_mysql_variables(conn): variables = {} for row in result.fetchall(): if row['Variable_name'] in MYSQL_VARS: - variables[row['Variable_name']] = row['Value'] + if row['Variable_name'] == 'read_only': + variables[row['Variable_name']] = 1 if row['Value'] == 'ON' else 0 + else: + variables[row['Variable_name']] = row['Value'] return variables @@ -510,10 +492,7 @@ def dispatch_value(prefix, key, value, type, type_instance=None): log_verbose('Sending value: %s/%s=%s' % (prefix, type_instance, value)) if value is None: return - try: - value = int(value) - except ValueError: - value = float(value) + value = int(value) # safety check if COLLECTD_ENABLED: val = collectd.Values(plugin='mysql', plugin_instance=prefix) From 562a4694855d6050396ed25ba7225667cd1c9390 Mon Sep 17 00:00:00 2001 From: Jan Kunzmann Date: Wed, 18 Jan 2017 19:19:32 +0100 Subject: [PATCH 2/4] Collect MariaDB's "Memory_used" status value --- mysql.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql.py b/mysql.py index 9027803..740f66a 100644 --- a/mysql.py +++ b/mysql.py @@ -125,6 +125,7 @@ 'Key_write_requests': 'counter', 'Key_writes': 'counter', 'Max_used_connections': 'gauge', + 'Memory_used': 'gauge', 'Open_files': 'gauge', 'Open_table_definitions': 'gauge', 'Open_tables': 'gauge', From c7ae56506f2c3bb04340ba501726cbe599a502ac Mon Sep 17 00:00:00 2001 From: Filip Chabik Date: Fri, 18 Nov 2016 13:38:43 +0100 Subject: [PATCH 3/4] Allow to collect more than one mysql instance per host (Currently requires a copy/link of this module per instance) --- mysql.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/mysql.py b/mysql.py index 740f66a..5693e97 100644 --- a/mysql.py +++ b/mysql.py @@ -13,6 +13,7 @@ # Port 3306 (optional) # User root # Password xxxx +# Instance xxxx # HeartbeatTable percona.heartbeat (optional, if using pt-heartbeat) # Verbose true (optional, to enable debugging) # @@ -21,6 +22,7 @@ # # Author: Chris Boulton # Added metrics for Grafana Dashboards by Matej Zerovnik +# Added support for multiple instances by Filip Chabik # License: MIT (http://www.opensource.org/licenses/mit-license.php) # @@ -43,6 +45,7 @@ 'Password': '', 'HeartbeatTable': '', 'Verbose': False, + 'Instance': '', } MYSQL_STATUS_VARS = { @@ -493,14 +496,18 @@ def dispatch_value(prefix, key, value, type, type_instance=None): log_verbose('Sending value: %s/%s=%s' % (prefix, type_instance, value)) if value is None: return - value = int(value) # safety check - if COLLECTD_ENABLED: - val = collectd.Values(plugin='mysql', plugin_instance=prefix) - val.type = type - val.type_instance = type_instance - val.values = [value] - val.dispatch() + if not COLLECTD_ENABLED: + return + + value = int(value) # safety check + val = collectd.Values(plugin='mysql', plugin_instance=prefix) + val.plugin = 'mysql.%s' % MYSQL_CONFIG['Instance'] + val.plugin_instance = prefix + val.type = type + val.type_instance = type_instance + val.values = [value] + val.dispatch() def configure_callback(conf): global MYSQL_CONFIG From 335f7ca84f2c1008617dcdfae64d714e85a1d1bc Mon Sep 17 00:00:00 2001 From: Jan Kunzmann Date: Thu, 12 Jan 2017 16:03:16 +0100 Subject: [PATCH 4/4] Allow to collect multiple instances per host (as inspired by https://github.com/powdahound/redis-collectd-plugin/blob/master/redis_info.py) --- README.md | 3 + mysql.py | 1041 ++++++++++++++++++++++++++++------------------------- 2 files changed, 553 insertions(+), 491 deletions(-) diff --git a/README.md b/README.md index df02a08..16cf9b2 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,14 @@ You should then configure the MySQL plugin: Port 3306 (default: 3306) User "root" (default: root) Password "xxxx" (default: empty) + Instance "" (default: empty instance identifier) HeartbeatTable "percona.heartbeat" (if using pt-heartbeat to track slave lag) Verbose false (default: false) +Repeat the "Module" section for multiple instances + ## Metrics ### MySQL Status diff --git a/mysql.py b/mysql.py index 5693e97..a4cc678 100644 --- a/mysql.py +++ b/mysql.py @@ -6,7 +6,7 @@ # all of the legacy compatibility, and favors metrics from SHOW GLOBAL STATUS # as opposed to SHOW ENGINE INNODB STATUS where possible. # -# Configuration: +# Configuration (repeat Module section for multiple instances): # Import mysql # # Host localhost @@ -28,557 +28,616 @@ import sys -COLLECTD_ENABLED=True +COLLECTD_ENABLED = True try: - import collectd + import collectd except ImportError: - # We're not running in CollectD, set this to False so we can make some changes - # accordingly for testing/development. - COLLECTD_ENABLED=False + # We're not running in CollectD, set this to False so we can make some changes + # accordingly for testing/development. + COLLECTD_ENABLED = False import re import MySQLdb +import copy -MYSQL_CONFIG = { - 'Host': 'localhost', - 'Port': 3306, - 'User': 'root', - 'Password': '', - 'HeartbeatTable': '', - 'Verbose': False, - 'Instance': '', -} +# Verbose logging on/off. Override in config by specifying 'Verbose'. +VERBOSE_LOGGING = False + +CONFIGS = [] MYSQL_STATUS_VARS = { - 'Aborted_clients': 'counter', - 'Aborted_connects': 'counter', - 'Binlog_cache_disk_use': 'counter', - 'Binlog_cache_use': 'counter', - 'Bytes_received': 'counter', - 'Bytes_sent': 'counter', - 'Connections': 'counter', - 'Created_tmp_disk_tables': 'counter', - 'Created_tmp_files': 'counter', - 'Created_tmp_tables': 'counter', - 'Innodb_buffer_pool_bytes_data': 'gauge', - 'Innodb_buffer_pool_bytes_dirty': 'gauge', - 'Innodb_buffer_pool_pages_data': 'gauge', - 'Innodb_buffer_pool_pages_dirty': 'gauge', - 'Innodb_buffer_pool_pages_free': 'gauge', - 'Innodb_buffer_pool_pages_total': 'gauge', - 'Innodb_buffer_pool_read_requests': 'counter', - 'Innodb_buffer_pool_write_requests': 'counter', - 'Innodb_buffer_pool_reads': 'counter', - 'Innodb_checkpoint_age': 'gauge', - 'Innodb_checkpoint_max_age': 'gauge', - 'Innodb_data_fsyncs': 'counter', - 'Innodb_data_pending_fsyncs': 'gauge', - 'Innodb_data_pending_reads': 'gauge', - 'Innodb_data_pending_writes': 'gauge', - 'Innodb_data_read': 'counter', - 'Innodb_data_reads': 'counter', - 'Innodb_data_writes': 'counter', - 'Innodb_data_written': 'counter', - 'Innodb_deadlocks': 'counter', - 'Innodb_history_list_length': 'gauge', - 'Innodb_ibuf_free_list': 'gauge', - 'Innodb_ibuf_merged_delete_marks': 'counter', - 'Innodb_ibuf_merged_deletes': 'counter', - 'Innodb_ibuf_merged_inserts': 'counter', - 'Innodb_ibuf_merges': 'counter', - 'Innodb_ibuf_segment_size': 'gauge', - 'Innodb_ibuf_size': 'gauge', - 'Innodb_lsn_current': 'counter', - 'Innodb_lsn_flushed': 'counter', - 'Innodb_log_writes': 'counter', - 'Innodb_max_trx_id': 'counter', - 'Innodb_mem_adaptive_hash': 'gauge', - 'Innodb_mem_dictionary': 'gauge', - 'Innodb_mem_total': 'gauge', - 'Innodb_mutex_os_waits': 'counter', - 'Innodb_mutex_spin_rounds': 'counter', - 'Innodb_mutex_spin_waits': 'counter', - 'Innodb_os_log_pending_fsyncs': 'gauge', - 'Innodb_os_log_written': 'counter', - 'Innodb_pages_created': 'counter', - 'Innodb_pages_read': 'counter', - 'Innodb_pages_written': 'counter', - 'Innodb_page_size': 'gauge', - 'Innodb_row_lock_time': 'counter', - 'Innodb_row_lock_time_avg': 'gauge', - 'Innodb_row_lock_time_max': 'gauge', - 'Innodb_row_lock_waits': 'counter', - 'Innodb_rows_deleted': 'counter', - 'Innodb_rows_inserted': 'counter', - 'Innodb_rows_read': 'counter', - 'Innodb_rows_updated': 'counter', - 'Innodb_s_lock_os_waits': 'counter', - 'Innodb_s_lock_spin_rounds': 'counter', - 'Innodb_s_lock_spin_waits': 'counter', - 'Innodb_uncheckpointed_bytes': 'gauge', - 'Innodb_unflushed_log': 'gauge', - 'Innodb_unpurged_txns': 'gauge', - 'Innodb_x_lock_os_waits': 'counter', - 'Innodb_x_lock_spin_rounds': 'counter', - 'Innodb_x_lock_spin_waits': 'counter', - 'Key_blocks_not_flushed': 'gauge', - 'Key_blocks_unused': 'gauge', - 'Key_blocks_used': 'gauge', - 'Key_read_requests': 'counter', - 'Key_reads': 'counter', - 'Key_write_requests': 'counter', - 'Key_writes': 'counter', - 'Max_used_connections': 'gauge', - 'Memory_used': 'gauge', - 'Open_files': 'gauge', - 'Open_table_definitions': 'gauge', - 'Open_tables': 'gauge', - 'Opened_files': 'counter', - 'Opened_table_definitions': 'counter', - 'Opened_tables': 'counter', - 'Qcache_free_blocks': 'gauge', - 'Qcache_free_memory': 'gauge', - 'Qcache_hits': 'counter', - 'Qcache_inserts': 'counter', - 'Qcache_lowmem_prunes': 'counter', - 'Qcache_not_cached': 'counter', - 'Qcache_queries_in_cache': 'counter', - 'Qcache_total_blocks': 'counter', - 'Queries': 'counter', - 'Questions': 'counter', - 'Select_full_join': 'counter', - 'Select_full_range_join': 'counter', - 'Select_range': 'counter', - 'Select_range_check': 'counter', - 'Select_scan': 'counter', - 'Slave_open_temp_tables': 'gauge', - 'Slave_retried_transactions': 'counter', - 'Slow_launch_threads': 'counter', - 'Slow_queries': 'counter', - 'Sort_merge_passes': 'counter', - 'Sort_range': 'counter', - 'Sort_rows': 'counter', - 'Sort_scan': 'counter', - 'Table_locks_immediate': 'counter', - 'Table_locks_waited': 'counter', - 'Table_open_cache_hits': 'counter', - 'Table_open_cache_misses': 'counter', - 'Table_open_cache_overflows': 'counter', - 'Threadpool_idle_threads': 'gauge', - 'Threadpool_threads': 'gauge', - 'Threads_cached': 'gauge', - 'Threads_connected': 'gauge', - 'Threads_created': 'counter', - 'Threads_running': 'gauge', - 'Uptime': 'gauge', + 'Aborted_clients': 'counter', + 'Aborted_connects': 'counter', + 'Binlog_cache_disk_use': 'counter', + 'Binlog_cache_use': 'counter', + 'Bytes_received': 'counter', + 'Bytes_sent': 'counter', + 'Connections': 'counter', + 'Created_tmp_disk_tables': 'counter', + 'Created_tmp_files': 'counter', + 'Created_tmp_tables': 'counter', + 'Innodb_buffer_pool_bytes_data': 'gauge', + 'Innodb_buffer_pool_bytes_dirty': 'gauge', + 'Innodb_buffer_pool_pages_data': 'gauge', + 'Innodb_buffer_pool_pages_dirty': 'gauge', + 'Innodb_buffer_pool_pages_free': 'gauge', + 'Innodb_buffer_pool_pages_total': 'gauge', + 'Innodb_buffer_pool_read_requests': 'counter', + 'Innodb_buffer_pool_write_requests': 'counter', + 'Innodb_buffer_pool_reads': 'counter', + 'Innodb_checkpoint_age': 'gauge', + 'Innodb_checkpoint_max_age': 'gauge', + 'Innodb_data_fsyncs': 'counter', + 'Innodb_data_pending_fsyncs': 'gauge', + 'Innodb_data_pending_reads': 'gauge', + 'Innodb_data_pending_writes': 'gauge', + 'Innodb_data_read': 'counter', + 'Innodb_data_reads': 'counter', + 'Innodb_data_writes': 'counter', + 'Innodb_data_written': 'counter', + 'Innodb_deadlocks': 'counter', + 'Innodb_history_list_length': 'gauge', + 'Innodb_ibuf_free_list': 'gauge', + 'Innodb_ibuf_merged_delete_marks': 'counter', + 'Innodb_ibuf_merged_deletes': 'counter', + 'Innodb_ibuf_merged_inserts': 'counter', + 'Innodb_ibuf_merges': 'counter', + 'Innodb_ibuf_segment_size': 'gauge', + 'Innodb_ibuf_size': 'gauge', + 'Innodb_lsn_current': 'counter', + 'Innodb_lsn_flushed': 'counter', + 'Innodb_log_writes': 'counter', + 'Innodb_max_trx_id': 'counter', + 'Innodb_mem_adaptive_hash': 'gauge', + 'Innodb_mem_dictionary': 'gauge', + 'Innodb_mem_total': 'gauge', + 'Innodb_mutex_os_waits': 'counter', + 'Innodb_mutex_spin_rounds': 'counter', + 'Innodb_mutex_spin_waits': 'counter', + 'Innodb_os_log_pending_fsyncs': 'gauge', + 'Innodb_os_log_written': 'counter', + 'Innodb_pages_created': 'counter', + 'Innodb_pages_read': 'counter', + 'Innodb_pages_written': 'counter', + 'Innodb_page_size': 'gauge', + 'Innodb_row_lock_time': 'counter', + 'Innodb_row_lock_time_avg': 'gauge', + 'Innodb_row_lock_time_max': 'gauge', + 'Innodb_row_lock_waits': 'counter', + 'Innodb_rows_deleted': 'counter', + 'Innodb_rows_inserted': 'counter', + 'Innodb_rows_read': 'counter', + 'Innodb_rows_updated': 'counter', + 'Innodb_s_lock_os_waits': 'counter', + 'Innodb_s_lock_spin_rounds': 'counter', + 'Innodb_s_lock_spin_waits': 'counter', + 'Innodb_uncheckpointed_bytes': 'gauge', + 'Innodb_unflushed_log': 'gauge', + 'Innodb_unpurged_txns': 'gauge', + 'Innodb_x_lock_os_waits': 'counter', + 'Innodb_x_lock_spin_rounds': 'counter', + 'Innodb_x_lock_spin_waits': 'counter', + 'Key_blocks_not_flushed': 'gauge', + 'Key_blocks_unused': 'gauge', + 'Key_blocks_used': 'gauge', + 'Key_read_requests': 'counter', + 'Key_reads': 'counter', + 'Key_write_requests': 'counter', + 'Key_writes': 'counter', + 'Max_used_connections': 'gauge', + 'Memory_used': 'gauge', + 'Open_files': 'gauge', + 'Open_table_definitions': 'gauge', + 'Open_tables': 'gauge', + 'Opened_files': 'counter', + 'Opened_table_definitions': 'counter', + 'Opened_tables': 'counter', + 'Qcache_free_blocks': 'gauge', + 'Qcache_free_memory': 'gauge', + 'Qcache_hits': 'counter', + 'Qcache_inserts': 'counter', + 'Qcache_lowmem_prunes': 'counter', + 'Qcache_not_cached': 'counter', + 'Qcache_queries_in_cache': 'counter', + 'Qcache_total_blocks': 'counter', + 'Queries': 'counter', + 'Questions': 'counter', + 'Select_full_join': 'counter', + 'Select_full_range_join': 'counter', + 'Select_range': 'counter', + 'Select_range_check': 'counter', + 'Select_scan': 'counter', + 'Slave_open_temp_tables': 'gauge', + 'Slave_retried_transactions': 'counter', + 'Slow_launch_threads': 'counter', + 'Slow_queries': 'counter', + 'Sort_merge_passes': 'counter', + 'Sort_range': 'counter', + 'Sort_rows': 'counter', + 'Sort_scan': 'counter', + 'Table_locks_immediate': 'counter', + 'Table_locks_waited': 'counter', + 'Table_open_cache_hits': 'counter', + 'Table_open_cache_misses': 'counter', + 'Table_open_cache_overflows': 'counter', + 'Threadpool_idle_threads': 'gauge', + 'Threadpool_threads': 'gauge', + 'Threads_cached': 'gauge', + 'Threads_connected': 'gauge', + 'Threads_created': 'counter', + 'Threads_running': 'gauge', + 'Uptime': 'gauge', } MYSQL_VARS = [ - 'binlog_stmt_cache_size', - 'innodb_additional_mem_pool_size', - 'innodb_buffer_pool_size', - 'innodb_concurrency_tickets', - 'innodb_io_capacity', - 'innodb_log_buffer_size', - 'innodb_log_file_size', - 'innodb_log_files_in_group', - 'innodb_max_purge_lag', - 'innodb_open_files', - 'innodb_open_files', - 'join_buffer_size', - 'key_buffer_size', - 'key_cache_block_size', - 'max_connections', - 'open_files_limit', - 'query_cache_limit', - 'query_cache_size', - 'query_cache_size', - 'read_buffer_size', - 'read_only', - 'table_cache', - 'table_definition_cache', - 'table_open_cache', - 'thread_cache_size', - 'thread_cache_size', - 'thread_concurrency', - 'tmp_table_size', + 'binlog_stmt_cache_size', + 'innodb_additional_mem_pool_size', + 'innodb_buffer_pool_size', + 'innodb_concurrency_tickets', + 'innodb_io_capacity', + 'innodb_log_buffer_size', + 'innodb_log_file_size', + 'innodb_log_files_in_group', + 'innodb_max_purge_lag', + 'innodb_open_files', + 'innodb_open_files', + 'join_buffer_size', + 'key_buffer_size', + 'key_cache_block_size', + 'max_connections', + 'open_files_limit', + 'query_cache_limit', + 'query_cache_size', + 'query_cache_size', + 'read_buffer_size', + 'read_only', + 'table_cache', + 'table_definition_cache', + 'table_open_cache', + 'thread_cache_size', + 'thread_cache_size', + 'thread_concurrency', + 'tmp_table_size', ] MYSQL_PROCESS_STATES = { - 'closing_tables': 0, - 'copying_to_tmp_table': 0, - 'end': 0, - 'freeing_items': 0, - 'init': 0, - 'locked': 0, - 'login': 0, - 'none': 0, - 'other': 0, - 'preparing': 0, - 'reading_from_net': 0, - 'sending_data': 0, - 'sorting_result': 0, - 'statistics': 0, - 'updating': 0, - 'writing_to_net': 0, - 'creating_table': 0, - 'opening_tables': 0, + 'closing_tables': 0, + 'copying_to_tmp_table': 0, + 'end': 0, + 'freeing_items': 0, + 'init': 0, + 'locked': 0, + 'login': 0, + 'none': 0, + 'other': 0, + 'preparing': 0, + 'reading_from_net': 0, + 'sending_data': 0, + 'sorting_result': 0, + 'statistics': 0, + 'updating': 0, + 'writing_to_net': 0, + 'creating_table': 0, + 'opening_tables': 0, } MYSQL_INNODB_STATUS_VARS = { - 'active_transactions': 'gauge', - 'current_transactions': 'gauge', - 'file_reads': 'counter', - 'file_system_memory': 'gauge', - 'file_writes': 'counter', - 'innodb_lock_structs': 'gauge', - 'innodb_lock_wait_secs': 'gauge', - 'innodb_locked_tables': 'gauge', - 'innodb_sem_wait_time_ms': 'gauge', - 'innodb_sem_waits': 'gauge', - 'innodb_tables_in_use': 'gauge', - 'lock_system_memory': 'gauge', - 'locked_transactions': 'gauge', - 'log_writes': 'counter', - 'page_hash_memory': 'gauge', - 'pending_aio_log_ios': 'gauge', - 'pending_buf_pool_flushes': 'gauge', - 'pending_chkp_writes': 'gauge', - 'pending_ibuf_aio_reads': 'gauge', - 'pending_log_writes':'gauge', - 'queries_inside': 'gauge', - 'queries_queued': 'gauge', - 'read_views': 'gauge', + 'active_transactions': 'gauge', + 'current_transactions': 'gauge', + 'file_reads': 'counter', + 'file_system_memory': 'gauge', + 'file_writes': 'counter', + 'innodb_lock_structs': 'gauge', + 'innodb_lock_wait_secs': 'gauge', + 'innodb_locked_tables': 'gauge', + 'innodb_sem_wait_time_ms': 'gauge', + 'innodb_sem_waits': 'gauge', + 'innodb_tables_in_use': 'gauge', + 'lock_system_memory': 'gauge', + 'locked_transactions': 'gauge', + 'log_writes': 'counter', + 'page_hash_memory': 'gauge', + 'pending_aio_log_ios': 'gauge', + 'pending_buf_pool_flushes': 'gauge', + 'pending_chkp_writes': 'gauge', + 'pending_ibuf_aio_reads': 'gauge', + 'pending_log_writes': 'gauge', + 'queries_inside': 'gauge', + 'queries_queued': 'gauge', + 'read_views': 'gauge', } MYSQL_INNODB_STATUS_MATCHES = { - # 0 read views open inside InnoDB - 'read views open inside InnoDB': { - 'read_views': 0, - }, - # 5635328 OS file reads, 27018072 OS file writes, 20170883 OS fsyncs - ' OS file reads, ': { - 'file_reads': 0, - 'file_writes': 4, - }, - # ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0 - 'ibuf aio reads': { - 'pending_ibuf_aio_reads': 3, - 'pending_aio_log_ios': 6, - 'pending_aio_sync_ios': 9, - }, - # Pending flushes (fsync) log: 0; buffer pool: 0 - 'Pending flushes (fsync)': { - 'pending_buf_pool_flushes': 7, - }, - # 16086708 log i/o's done, 106.07 log i/o's/second - " log i/o's done, ": { - 'log_writes': 0, - }, - # 0 pending log writes, 0 pending chkp writes - ' pending log writes, ': { - 'pending_log_writes': 0, - 'pending_chkp_writes': 4, - }, - # Page hash 2302856 (buffer pool 0 only) - 'Page hash ': { - 'page_hash_memory': 2, - }, - # File system 657820264 (812272 + 657007992) - 'File system ': { - 'file_system_memory': 2, - }, - # Lock system 143820296 (143819576 + 720) - 'Lock system ': { - 'lock_system_memory': 2, - }, - # 0 queries inside InnoDB, 0 queries in queue - 'queries inside InnoDB, ': { - 'queries_inside': 0, - 'queries_queued': 4, - }, - # --Thread 139954487744256 has waited at dict0dict.cc line 472 for 0.0000 seconds the semaphore: - 'seconds the semaphore': { - 'innodb_sem_waits': lambda row, stats: stats['innodb_sem_waits'] + 1, - 'innodb_sem_wait_time_ms': lambda row, stats: float(row[9]) * 1000, - }, - # mysql tables in use 1, locked 1 - 'mysql tables in use': { - 'innodb_tables_in_use': lambda row, stats: stats['innodb_tables_in_use'] + int(row[4]), - 'innodb_locked_tables': lambda row, stats: stats['innodb_locked_tables'] + int(row[6]), - }, - "------- TRX HAS BEEN": { - "innodb_lock_wait_secs": lambda row, stats: stats['innodb_lock_wait_secs'] + int(row[5]), - }, + # 0 read views open inside InnoDB + 'read views open inside InnoDB': { + 'read_views': 0, + }, + # 5635328 OS file reads, 27018072 OS file writes, 20170883 OS fsyncs + ' OS file reads, ': { + 'file_reads': 0, + 'file_writes': 4, + }, + # ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0 + 'ibuf aio reads': { + 'pending_ibuf_aio_reads': 3, + 'pending_aio_log_ios': 6, + 'pending_aio_sync_ios': 9, + }, + # Pending flushes (fsync) log: 0; buffer pool: 0 + 'Pending flushes (fsync)': { + 'pending_buf_pool_flushes': 7, + }, + # 16086708 log i/o's done, 106.07 log i/o's/second + " log i/o's done, ": { + 'log_writes': 0, + }, + # 0 pending log writes, 0 pending chkp writes + ' pending log writes, ': { + 'pending_log_writes': 0, + 'pending_chkp_writes': 4, + }, + # Page hash 2302856 (buffer pool 0 only) + 'Page hash ': { + 'page_hash_memory': 2, + }, + # File system 657820264 (812272 + 657007992) + 'File system ': { + 'file_system_memory': 2, + }, + # Lock system 143820296 (143819576 + 720) + 'Lock system ': { + 'lock_system_memory': 2, + }, + # 0 queries inside InnoDB, 0 queries in queue + 'queries inside InnoDB, ': { + 'queries_inside': 0, + 'queries_queued': 4, + }, + # --Thread 139954487744256 has waited at dict0dict.cc line 472 for 0.0000 seconds the semaphore: + 'seconds the semaphore': { + 'innodb_sem_waits': lambda row, stats: stats['innodb_sem_waits'] + 1, + 'innodb_sem_wait_time_ms': lambda row, stats: float(row[9]) * 1000, + }, + # mysql tables in use 1, locked 1 + 'mysql tables in use': { + 'innodb_tables_in_use': lambda row, stats: stats['innodb_tables_in_use'] + int(row[4]), + 'innodb_locked_tables': lambda row, stats: stats['innodb_locked_tables'] + int(row[6]), + }, + "------- TRX HAS BEEN": { + "innodb_lock_wait_secs": lambda row, stats: stats['innodb_lock_wait_secs'] + int(row[5]), + }, } -def get_mysql_conn(): - return MySQLdb.connect( - host=MYSQL_CONFIG['Host'], - port=MYSQL_CONFIG['Port'], - user=MYSQL_CONFIG['User'], - passwd=MYSQL_CONFIG['Password'] - ) + +def get_mysql_conn(conf): + return MySQLdb.connect( + host=conf['host'], + port=conf['port'], + user=conf['user'], + passwd=conf['password'] + ) + def mysql_query(conn, query): - cur = conn.cursor(MySQLdb.cursors.DictCursor) - cur.execute(query) - return cur + cur = conn.cursor(MySQLdb.cursors.DictCursor) + cur.execute(query) + return cur + def fetch_mysql_status(conn): - result = mysql_query(conn, 'SHOW GLOBAL STATUS') - status = {} - for row in result.fetchall(): - status[row['Variable_name']] = row['Value'] + result = mysql_query(conn, 'SHOW GLOBAL STATUS') + status = {} + for row in result.fetchall(): + status[row['Variable_name']] = row['Value'] + + # calculate the number of unpurged txns from existing variables + if 'Innodb_max_trx_id' in status: + status['Innodb_unpurged_txns'] = int(status['Innodb_max_trx_id']) - int(status['Innodb_purge_trx_id']) - # calculate the number of unpurged txns from existing variables - if 'Innodb_max_trx_id' in status: - status['Innodb_unpurged_txns'] = int(status['Innodb_max_trx_id']) - int(status['Innodb_purge_trx_id']) + if 'Innodb_lsn_last_checkpoint' in status: + status['Innodb_uncheckpointed_bytes'] = int(status['Innodb_lsn_current']) - int( + status['Innodb_lsn_last_checkpoint']) - if 'Innodb_lsn_last_checkpoint' in status: - status['Innodb_uncheckpointed_bytes'] = int(status['Innodb_lsn_current'])- int(status['Innodb_lsn_last_checkpoint']) + if 'Innodb_lsn_flushed' in status: + status['Innodb_unflushed_log'] = int(status['Innodb_lsn_current']) - int(status['Innodb_lsn_flushed']) - if 'Innodb_lsn_flushed' in status: - status['Innodb_unflushed_log'] = int(status['Innodb_lsn_current']) - int(status['Innodb_lsn_flushed']) + return status - return status def fetch_mysql_master_stats(conn): - try: - result = mysql_query(conn, 'SHOW BINARY LOGS') - except MySQLdb.OperationalError: - return {} - - stats = { - 'binary_log_space': 0, - } - - for row in result.fetchall(): - if 'File_size' in row and row['File_size'] > 0: - stats['binary_log_space'] += int(row['File_size']) - - return stats - -def fetch_mysql_slave_stats(conn): - result = mysql_query(conn, 'SHOW SLAVE STATUS') - slave_row = result.fetchone() - if slave_row is None: - return {} - - status = { - 'relay_log_space': slave_row['Relay_Log_Space'], - 'last_errno': slave_row['Last_Errno'], - 'slave_lag': slave_row['Seconds_Behind_Master'] if slave_row['Seconds_Behind_Master'] != None else 0, - } - - if MYSQL_CONFIG['HeartbeatTable']: - query = """ + try: + result = mysql_query(conn, 'SHOW BINARY LOGS') + except MySQLdb.OperationalError: + return {} + + stats = { + 'binary_log_space': 0, + } + + for row in result.fetchall(): + if 'File_size' in row and row['File_size'] > 0: + stats['binary_log_space'] += int(row['File_size']) + + return stats + + +def fetch_mysql_slave_stats(conf, conn): + result = mysql_query(conn, 'SHOW SLAVE STATUS') + slave_row = result.fetchone() + if slave_row is None: + return {} + + status = { + 'relay_log_space': slave_row['Relay_Log_Space'], + 'last_errno': slave_row['Last_Errno'], + 'slave_lag': slave_row['Seconds_Behind_Master'] if slave_row['Seconds_Behind_Master'] != None else 0, + } + + if conf['heartbeattable']: + query = """ SELECT MAX(UNIX_TIMESTAMP() - UNIX_TIMESTAMP(ts)) AS delay FROM %s WHERE server_id = %s - """ % (MYSQL_CONFIG['HeartbeatTable'], slave_row['Master_Server_Id']) - result = mysql_query(conn, query) - row = result.fetchone() - if 'delay' in row and row['delay'] != None: - status['slave_lag'] = row['delay'] + """ % (conf['heartbeattable'], slave_row['Master_Server_Id']) + result = mysql_query(conn, query) + row = result.fetchone() + if 'delay' in row and row['delay'] != None: + status['slave_lag'] = row['delay'] + + status['slave_sql_running'] = 1 if slave_row['Slave_SQL_Running'] == 'Yes' else 0 + status['slave_io_running'] = 1 if slave_row['Slave_IO_Running'] == 'Yes' else 0 + return status - status['slave_sql_running'] = 1 if slave_row['Slave_SQL_Running'] == 'Yes' else 0 - status['slave_io_running'] = 1 if slave_row['Slave_IO_Running'] == 'Yes' else 0 - return status def fetch_mysql_process_states(conn): - global MYSQL_PROCESS_STATES - result = mysql_query(conn, 'SHOW PROCESSLIST') - states = MYSQL_PROCESS_STATES.copy() - for row in result.fetchall(): - state = row['State'] - if state == '' or state == None: state = 'none' - state = re.sub(r'^(Table lock|Waiting for .*lock)$', "Locked", state) - state = state.lower().replace(" ", "_") - if state not in states: state = 'other' - states[state] += 1 - - return states + global MYSQL_PROCESS_STATES + result = mysql_query(conn, 'SHOW PROCESSLIST') + states = MYSQL_PROCESS_STATES.copy() + for row in result.fetchall(): + state = row['State'] + if state == '' or state == None: state = 'none' + state = re.sub(r'^(Table lock|Waiting for .*lock)$', "Locked", state) + state = state.lower().replace(" ", "_") + if state not in states: state = 'other' + states[state] += 1 + + return states + def fetch_mysql_variables(conn): - global MYSQL_VARS - result = mysql_query(conn, 'SHOW GLOBAL VARIABLES') - variables = {} - for row in result.fetchall(): - if row['Variable_name'] in MYSQL_VARS: - if row['Variable_name'] == 'read_only': - variables[row['Variable_name']] = 1 if row['Value'] == 'ON' else 0 - else: - variables[row['Variable_name']] = row['Value'] - - return variables + global MYSQL_VARS + result = mysql_query(conn, 'SHOW GLOBAL VARIABLES') + variables = {} + for row in result.fetchall(): + if row['Variable_name'] in MYSQL_VARS: + if row['Variable_name'] == 'read_only': + variables[row['Variable_name']] = 1 if row['Value'] == 'ON' else 0 + else: + variables[row['Variable_name']] = row['Value'] + + return variables + def fetch_mysql_response_times(conn): - response_times = {} - try: - result = mysql_query(conn, """ + response_times = {} + try: + result = mysql_query(conn, """ SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME WHERE `time` != 'TOO LONG' ORDER BY `time` """) - except MySQLdb.OperationalError: - return {} + except MySQLdb.OperationalError: + return {} + + for i in range(1, 14): + row = result.fetchone() - for i in range(1, 14): - row = result.fetchone() + # fill in missing rows with zeros + if not row: + row = {'count': 0, 'total': 0} - # fill in missing rows with zeros - if not row: - row = { 'count': 0, 'total': 0 } + row = {key.lower(): val for key, val in row.items()} - row = {key.lower(): val for key, val in row.items()} + response_times[i] = { + 'time': float(row['time']), + 'count': int(row['count']), + 'total': round(float(row['total']) * 1000000, 0), + } - response_times[i] = { - 'time': float(row['time']), - 'count': int(row['count']), - 'total': round(float(row['total']) * 1000000, 0), - } + return response_times - return response_times def fetch_innodb_stats(conn): - global MYSQL_INNODB_STATUS_MATCHES, MYSQL_INNODB_STATUS_VARS - result = mysql_query(conn, 'SHOW ENGINE INNODB STATUS') - row = result.fetchone() - status = row['Status'] - stats = dict.fromkeys(MYSQL_INNODB_STATUS_VARS.keys(), 0) - - for line in status.split("\n"): - line = line.strip() - row = re.split(r' +', re.sub(r'[,;] ', ' ', line)) - if line == '': continue - - # ---TRANSACTION 124324402462, not started - # ---TRANSACTION 124324402468, ACTIVE 0 sec committing - if line.find("---TRANSACTION") != -1: - stats['current_transactions'] += 1 - if line.find("ACTIVE") != -1: - stats['active_transactions'] += 1 - # LOCK WAIT 228 lock struct(s), heap size 46632, 65 row lock(s), undo log entries 1 - # 205 lock struct(s), heap size 30248, 37 row lock(s), undo log entries 1 - elif line.find("lock struct(s)") != -1: - if line.find("LOCK WAIT") != -1: - stats['innodb_lock_structs'] += int(row[2]) - stats['locked_transactions'] += 1 - else: - stats['innodb_lock_structs'] += int(row[0]) - else: - for match in MYSQL_INNODB_STATUS_MATCHES: - if line.find(match) == -1: continue - for key in MYSQL_INNODB_STATUS_MATCHES[match]: - value = MYSQL_INNODB_STATUS_MATCHES[match][key] - if type(value) is int: - if value < len(row) and row[value].isdigit(): - stats[key] = int(row[value]) - else: - stats[key] = value(row, stats) - break - - return stats + global MYSQL_INNODB_STATUS_MATCHES, MYSQL_INNODB_STATUS_VARS + result = mysql_query(conn, 'SHOW ENGINE INNODB STATUS') + row = result.fetchone() + status = row['Status'] + stats = dict.fromkeys(MYSQL_INNODB_STATUS_VARS.keys(), 0) + + for line in status.split("\n"): + line = line.strip() + row = re.split(r' +', re.sub(r'[,;] ', ' ', line)) + if line == '': continue + + # ---TRANSACTION 124324402462, not started + # ---TRANSACTION 124324402468, ACTIVE 0 sec committing + if line.find("---TRANSACTION") != -1: + stats['current_transactions'] += 1 + if line.find("ACTIVE") != -1: + stats['active_transactions'] += 1 + # LOCK WAIT 228 lock struct(s), heap size 46632, 65 row lock(s), undo log entries 1 + # 205 lock struct(s), heap size 30248, 37 row lock(s), undo log entries 1 + elif line.find("lock struct(s)") != -1: + if line.find("LOCK WAIT") != -1: + stats['innodb_lock_structs'] += int(row[2]) + stats['locked_transactions'] += 1 + else: + stats['innodb_lock_structs'] += int(row[0]) + else: + for match in MYSQL_INNODB_STATUS_MATCHES: + if line.find(match) == -1: continue + for key in MYSQL_INNODB_STATUS_MATCHES[match]: + value = MYSQL_INNODB_STATUS_MATCHES[match][key] + if type(value) is int: + if value < len(row) and row[value].isdigit(): + stats[key] = int(row[value]) + else: + stats[key] = value(row, stats) + break + + return stats + def log_verbose(msg): - if not MYSQL_CONFIG['Verbose']: - return - if COLLECTD_ENABLED: - collectd.info('mysql plugin: %s' % msg) - else: - print('mysql plugin: %s' % msg) - -def dispatch_value(prefix, key, value, type, type_instance=None): - if not type_instance: - type_instance = key - - log_verbose('Sending value: %s/%s=%s' % (prefix, type_instance, value)) - if value is None: - return - - if not COLLECTD_ENABLED: - return - - value = int(value) # safety check - val = collectd.Values(plugin='mysql', plugin_instance=prefix) - val.plugin = 'mysql.%s' % MYSQL_CONFIG['Instance'] - val.plugin_instance = prefix - val.type = type - val.type_instance = type_instance - val.values = [value] - val.dispatch() + if not VERBOSE_LOGGING: + return + if COLLECTD_ENABLED: + collectd.info('mysql plugin: %s' % msg) + else: + print('mysql plugin: %s' % msg) + + +def dispatch_value(instance, prefix, key, value, type, type_instance=None): + if not type_instance: + type_instance = key + + log_verbose('Sending value: %s/%s=%s' % (prefix, type_instance, value)) + if value is None: + return + + if not COLLECTD_ENABLED: + return + + if instance is None: + plugin = 'mysql' + else: + plugin = 'mysql.%s' % instance + value = int(value) # safety check + val = collectd.Values(plugin=plugin, plugin_instance=prefix) + val.plugin = 'mysql.%s' % MYSQL_CONFIG['Instance'] + val.plugin_instance = prefix + val.type = type + val.type_instance = type_instance + val.values = [value] + val.dispatch() + def configure_callback(conf): - global MYSQL_CONFIG - for node in conf.children: - if node.key in MYSQL_CONFIG: - MYSQL_CONFIG[node.key] = node.values[0] + instance = None + host = 'localhost' + port = 3306 + user = 'root' + password = '' + heartbeattable = '' + verbose = False + + for node in conf.children: + key = node.key.lower() + val = node.values[0] + if key == 'instance': + instance = val + elif key == 'host': + host = val + elif key == 'port': + port = int(val) + elif key == 'user': + user = val + elif key == 'password': + password = val + elif key == 'heartbeattable': + heartbeattable = val + elif key == 'verbose': + global VERBOSE_LOGGING + VERBOSE_LOGGING = bool(val) or VERBOSE_LOGGING + else: + collectd.warning('mysql plugin: Unknown config key: %s.' % key) + + log_verbose('Configured with host=%s, port=%s, instance name=%s, user=%s' % (host, port, instance, user)) + + mysql_config = { + 'instance': instance, + 'host': host, + 'port': port, + 'user': user, + 'password': password, + 'heartbeattable': heartbeattable + } + CONFIGS.append(mysql_config) + + +def get_metrics(conf): + global MYSQL_STATUS_VARS + conn = get_mysql_conn(conf) + + mysql_status = fetch_mysql_status(conn) + for key in mysql_status: + if mysql_status[key] == '': mysql_status[key] = 0 + + # collect anything beginning with Com_/Handler_ as these change + # regularly between mysql versions and this is easier than a fixed + # list + if key.split('_', 2)[0] in ['Com', 'Handler']: + ds_type = 'counter' + elif key in MYSQL_STATUS_VARS: + ds_type = MYSQL_STATUS_VARS[key] + else: + continue + + dispatch_value(conf['instance'], 'status', key, mysql_status[key], ds_type) + + mysql_variables = fetch_mysql_variables(conn) + for key in mysql_variables: + dispatch_value(conf['instance'], 'variables', key, mysql_variables[key], 'gauge') + + mysql_master_status = fetch_mysql_master_stats(conn) + for key in mysql_master_status: + dispatch_value(conf['instance'], 'master', key, mysql_master_status[key], 'gauge') + + mysql_states = fetch_mysql_process_states(conn) + for key in mysql_states: + dispatch_value(conf['instance'], 'state', key, mysql_states[key], 'gauge') + + slave_status = fetch_mysql_slave_stats(conf, conn) + for key in slave_status: + dispatch_value(conf['instance'], 'slave', key, slave_status[key], 'gauge') + + response_times = fetch_mysql_response_times(conn) + for key in response_times: + dispatch_value(conf['instance'], 'response_time_total', str(key), response_times[key]['total'], 'counter') + dispatch_value(conf['instance'], 'response_time_count', str(key), response_times[key]['count'], 'counter') + + innodb_status = fetch_innodb_stats(conn) + for key in MYSQL_INNODB_STATUS_VARS: + if key not in innodb_status: continue + dispatch_value(conf['instance'], 'innodb', key, innodb_status[key], MYSQL_INNODB_STATUS_VARS[key]) - MYSQL_CONFIG['Port'] = int(MYSQL_CONFIG['Port']) - MYSQL_CONFIG['Verbose'] = bool(MYSQL_CONFIG['Verbose']) def read_callback(): - global MYSQL_STATUS_VARS - conn = get_mysql_conn() - - mysql_status = fetch_mysql_status(conn) - for key in mysql_status: - if mysql_status[key] == '': mysql_status[key] = 0 - - # collect anything beginning with Com_/Handler_ as these change - # regularly between mysql versions and this is easier than a fixed - # list - if key.split('_', 2)[0] in ['Com', 'Handler']: - ds_type = 'counter' - elif key in MYSQL_STATUS_VARS: - ds_type = MYSQL_STATUS_VARS[key] - else: - continue - - dispatch_value('status', key, mysql_status[key], ds_type) - - mysql_variables = fetch_mysql_variables(conn) - for key in mysql_variables: - dispatch_value('variables', key, mysql_variables[key], 'gauge') - - mysql_master_status = fetch_mysql_master_stats(conn) - for key in mysql_master_status: - dispatch_value('master', key, mysql_master_status[key], 'gauge') - - mysql_states = fetch_mysql_process_states(conn) - for key in mysql_states: - dispatch_value('state', key, mysql_states[key], 'gauge') - - slave_status = fetch_mysql_slave_stats(conn) - for key in slave_status: - dispatch_value('slave', key, slave_status[key], 'gauge') - - response_times = fetch_mysql_response_times(conn) - for key in response_times: - dispatch_value('response_time_total', str(key), response_times[key]['total'], 'counter') - dispatch_value('response_time_count', str(key), response_times[key]['count'], 'counter') - - innodb_status = fetch_innodb_stats(conn) - for key in MYSQL_INNODB_STATUS_VARS: - if key not in innodb_status: continue - dispatch_value('innodb', key, innodb_status[key], MYSQL_INNODB_STATUS_VARS[key]) + for conf in CONFIGS: + get_metrics(conf) + if COLLECTD_ENABLED: - collectd.register_read(read_callback) - collectd.register_config(configure_callback) + collectd.register_read(read_callback) + collectd.register_config(configure_callback) if __name__ == "__main__" and not COLLECTD_ENABLED: - print "Running in test mode, invoke with" - print sys.argv[0] + " Host Port User Password " - MYSQL_CONFIG['Host'] = sys.argv[1] - MYSQL_CONFIG['Port'] = int(sys.argv[2]) - MYSQL_CONFIG['User'] = sys.argv[3] - MYSQL_CONFIG['Password'] = sys.argv[4] - MYSQL_CONFIG['Verbose'] = True - from pprint import pprint as pp - pp(MYSQL_CONFIG) - read_callback() - - -# vim:noexpandtab ts=8 sw=8 sts=8 + VERBOSE_LOGGING = True + print "Running in test mode, invoke with" + print sys.argv[0] + " Host Port User Password Instance" + mysql_config = { + 'host': sys.argv[1], + 'heartbeattable': '', + 'instance': 'slave' if sys.argv.count < 6 else sys.argv[5], + 'port': int(sys.argv[2]), + 'user': sys.argv[3], + 'password': sys.argv[4], + 'verbose': VERBOSE_LOGGING + } + from pprint import pprint as pp + + pp(mysql_config) + CONFIGS.append(mysql_config) + read_callback() + + # vim:noexpandtab ts=8 sw=8 sts=8