Added ProxySQL collector for diamond

This commit is contained in:
René Cannaò 2016-09-25 23:49:24 +00:00
Родитель f733d1fb5c
Коммит 9af3842324
2 изменённых файлов: 198 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,7 @@
enabled=True
db = None
host = 127.0.0.1
passwd = stats
port = 6032
user = stats

191
diamond/proxysqlstat.py Normal file
Просмотреть файл

@ -0,0 +1,191 @@
# coding=utf-8
import diamond.collector
from diamond.collector import str_to_bool
import re
import time
try:
import MySQLdb
from MySQLdb import MySQLError
except ImportError:
MySQLdb = None
MySQLError = ValueError
class ProxySQLCollector(diamond.collector.Collector):
_GAUGE_KEYS = [
'Active_Transactions',
'Client_Connections_connected',
'ConnPool_memory_bytes',
'MySQL_Monitor_Workers',
'MySQL_Thread_Workers',
'Query_Cache_Entries',
'Query_Cache_Memory_bytes',
'SQLite3_memory_bytes',
'Server_Connections_connected',
'mysql_backend_buffers_bytes',
'mysql_frontend_buffers_bytes',
'mysql_session_internal_bytes',
]
def __init__(self, *args, **kwargs):
super(ProxySQLCollector, self).__init__(*args, **kwargs)
def process_config(self):
super(ProxySQLCollector, self).process_config()
if self.config['hosts'].__class__.__name__ != 'list':
self.config['hosts'] = [self.config['hosts']]
# Move legacy config format to new format
if 'host' in self.config:
hoststr = "%s:%s@%s:%s/%s" % (
self.config['user'],
self.config['passwd'],
self.config['host'],
self.config['port'],
self.config['db'],
)
self.config['hosts'].append(hoststr)
self.db = None
def get_default_config_help(self):
config_help = super(ProxySQLCollector, self).get_default_config_help()
config_help.update({
'publish':
"Which rows of 'SHOW MYSQL STATUS' you would " +
"like to publish. Leave unset to publish all",
'hosts': 'List of hosts to collect from. Format is ' +
'yourusername:yourpassword@host:port/db[/nickname]' +
'use db "None" to avoid connecting to a particular db'
})
return config_help
def get_default_config(self):
"""
Returns the default collector settings
"""
config = super(ProxySQLCollector, self).get_default_config()
config.update({
'path': 'proxysql',
# Connection settings
'hosts': [],
})
return config
def get_db_stats(self, query):
cursor = self.db.cursor(cursorclass=MySQLdb.cursors.DictCursor)
try:
cursor.execute(query)
return cursor.fetchall()
except MySQLError, e:
self.log.error('ProxySQLCollector could not get db stats', e)
return ()
def connect(self, params):
try:
self.db = MySQLdb.connect(**params)
self.log.debug('ProxySQLCollector: Connected to database.')
except MySQLError, e:
self.log.error('ProxySQLCollector couldnt connect to database %s', e)
return False
return True
def disconnect(self):
self.db.close()
def get_db_global_status(self):
return self.get_db_stats('SHOW MYSQL STATUS')
def get_stats(self, params):
metrics = {'status': {}}
if not self.connect(params):
return metrics
rows = self.get_db_global_status()
for row in rows:
try:
metrics['status'][row['Variable_name']] = float(row['Value'])
except:
pass
self.disconnect()
return metrics
def _publish_stats(self, nickname, metrics):
for key in metrics:
for metric_name in metrics[key]:
metric_value = metrics[key][metric_name]
if type(metric_value) is not float:
continue
if metric_name not in self._GAUGE_KEYS:
metric_value = self.derivative(nickname + metric_name,
metric_value)
if key == 'status':
if (('publish' not in self.config or
metric_name in self.config['publish'])):
self.publish(nickname + metric_name, metric_value)
else:
self.publish(nickname + metric_name, metric_value)
def collect(self):
if MySQLdb is None:
self.log.error('Unable to import MySQLdb')
return False
for host in self.config['hosts']:
matches = re.search(
'^([^:]*):([^@]*)@([^:]*):?([^/]*)/([^/]*)/?(.*)', host)
if not matches:
self.log.error(
'Connection string not in required format, skipping: %s',
host)
continue
params = {}
params['host'] = matches.group(3)
try:
params['port'] = int(matches.group(4))
except ValueError:
params['port'] = 3306
params['db'] = matches.group(5)
params['user'] = matches.group(1)
params['passwd'] = matches.group(2)
nickname = matches.group(6)
if len(nickname):
nickname += '.'
if params['db'] == 'None':
del params['db']
try:
metrics = self.get_stats(params=params)
except Exception, e:
try:
self.disconnect()
except MySQLdb.ProgrammingError:
pass
self.log.error('Collection failed for %s %s', nickname, e)
continue
# Warn if publish contains an unknown variable
if 'publish' in self.config and metrics['status']:
for k in self.config['publish'].split():
if k not in metrics['status']:
self.log.error("No such key '%s' available, issue " +
"'show global status' for a full " +
"list", k)
self._publish_stats(nickname, metrics)