@cryptotaxi247 / netdata-1 / commits / 6fc971fe4

add userstats charts for mysql (#6118)

* add userstats charts for mysql

Oleksii Kravchenko committed Jun 27, 2019 at 11:33 UTC 6fc971fe4d070d7c3e666ee24fb0c43d43084c85
2 files changed +145 -2
collectors/python.d.plugin/mysql/README.md
+21 -1
@@ -218,6 +218,24 @@ It will produce following charts (if data is available):
218 45. **Flow Control** in ms
219 * paused
220
221 +46. **Users CPU time** in percentage
222 + * users
223 +
224 +**Per user statistics:**
225 +
226 +1. **Rows Operations** in operations/s
227 + * read
228 + * send
229 + * updated
230 + * inserted
231 + * deleted
232 +
233 +2. **Commands** in commands/s
234 + * select
235 + * update
236 + * other
237 +
238 +
239 ### configuration
240
241 You can provide, per server, the following:
@@ -234,7 +252,7 @@ You can provide, per server, the following:
252 - ca: the path name of the Certificate Authority (CA) certificate file. This option, if used, must specify the same certificate used by the server.
253 - capath: the path name of the directory that contains trusted SSL CA certificate files.
254 - cipher: the list of permitted ciphers for SSL encryption.
237 -
255 +
256 Here is an example for 3 servers:
257
258 ```yaml
@@ -260,6 +278,8 @@ remote:
278
279 If no configuration is given, module will attempt to connect to mysql server via unix socket at `/var/run/mysqld/mysqld.sock` without password and with username `root`
280
281 +`userstats` graph works only if you enable such plugin in MariaDB server and set proper mysql priviliges (SUPER or PROCESS). For more detail please check [MariaDB User Statistics page](https://mariadb.com/kb/en/library/user-statistics/)
282 +
283 ---
284
285 [![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Fcollectors%2Fpython.d.plugin%2Fmysql%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)]()
collectors/python.d.plugin/mysql/mysql.chart.py
+124 -1
@@ -11,6 +11,7 @@ from bases.FrameworkServices.MySQLService import MySQLService
11 QUERY_GLOBAL = 'SHOW GLOBAL STATUS;'
12 QUERY_SLAVE = 'SHOW SLAVE STATUS;'
13 QUERY_VARIABLES = 'SHOW GLOBAL VARIABLES LIKE \'max_connections\';'
14 +QUERY_USER_STATISTICS = 'SHOW USER_STATISTICS;'
15
16 GLOBAL_STATS = [
17 'Bytes_received',
@@ -150,6 +151,18 @@ SLAVE_STATS = [
151 ('Slave_IO_Running', slave_running)
152 ]
153
154 +USER_STATISTICS = [
155 + 'Select_commands',
156 + 'Update_commands',
157 + 'Other_commands',
158 + 'Cpu_time',
159 + 'Rows_read',
160 + 'Rows_sent',
161 + 'Rows_deleted',
162 + 'Rows_inserted',
163 + 'Rows_updated'
164 +]
165 +
166 VARIABLES = [
167 'max_connections'
168 ]
@@ -202,7 +215,8 @@ ORDER = [
215 'galera_bytes',
216 'galera_queue',
217 'galera_conflicts',
205 - 'galera_flow_control'
218 + 'galera_flow_control',
219 + 'userstats_cpu'
220 ]
221
222 CHARTS = {
@@ -579,10 +593,45 @@ CHARTS = {
593 'lines': [
594 ['wsrep_flow_control_paused_ns', 'paused', 'incremental', 1, 1000000],
595 ]
596 + },
597 + 'userstats_cpu': {
598 + 'options': [None, 'Users CPU time', 'percentage', 'userstats', 'mysql.userstats_cpu', 'stacked'],
599 + 'lines': []
600 }
601 }
602
603
604 +def userstats_chart_template(name):
605 + order = [
606 + 'userstats_rows_{0}'.format(name),
607 + 'userstats_commands_{0}'.format(name)
608 + ]
609 + family = 'userstats {0}'.format(name)
610 +
611 + charts = {
612 + order[0]: {
613 + 'options': [None, 'Rows Operations', 'operations/s', family, 'mysql.userstats_rows', 'stacked'],
614 + 'lines': [
615 + ['userstats_{0}_Rows_read'.format(name), 'read', 'incremental'],
616 + ['userstats_{0}_Rows_send'.format(name), 'send', 'incremental'],
617 + ['userstats_{0}_Rows_updated'.format(name), 'updated', 'incremental'],
618 + ['userstats_{0}_Rows_inserted'.format(name), 'inserted', 'incremental'],
619 + ['userstats_{0}_Rows_deleted'.format(name), 'deleted', 'incremental']
620 + ]
621 + },
622 + order[1]: {
623 + 'options': [None, 'Commands', 'commands/s', family, 'mysql.userstats_commands', 'stacked'],
624 + 'lines': [
625 + ['userstats_{0}_Select_commands'.format(name), 'select', 'incremental'],
626 + ['userstats_{0}_Update_commands'.format(name), 'update', 'incremental'],
627 + ['userstats_{0}_Other_commands'.format(name), 'other', 'incremental']
628 + ]
629 + }
630 + }
631 +
632 + return order, charts
633 +
634 +
635 class Service(MySQLService):
636 def __init__(self, configuration=None, name=None):
637 MySQLService.__init__(self, configuration=configuration, name=name)
@@ -592,6 +641,7 @@ class Service(MySQLService):
641 global_status=QUERY_GLOBAL,
642 slave_status=QUERY_SLAVE,
643 variables=QUERY_VARIABLES,
644 + user_statistics=QUERY_USER_STATISTICS,
645 )
646
647 def _get_data(self):
@@ -621,6 +671,12 @@ class Service(MySQLService):
671 else:
672 self.queries.pop('slave_status')
673
674 + if 'user_statistics' in raw_data:
675 + if raw_data['user_statistics'][0]:
676 + to_netdata.update(self.get_userstats(raw_data))
677 + else:
678 + self.queries.pop('user_statistics')
679 +
680 if 'variables' in raw_data:
681 variables = dict(raw_data['variables'][0])
682 for key in VARIABLES:
@@ -628,3 +684,70 @@ class Service(MySQLService):
684 to_netdata[key] = variables[key]
685
686 return to_netdata or None
687 +
688 + # raw_data['user_statistics'] contains the following data structure:
689 + # (
690 + # (
691 + # ('netdata', 42L, 0L, 1264L, 3.111252999999968, 2.968510299999994, 110267L, 19741424L, 0L, 0L, 1265L, 0L,
692 + # 0L, 0L, 3L, 0L, 1301L, 0L, 0L, 7633L, 0L, 83L, 44L, 0L, 0L),
693 + # ('root', 60L, 0L, 184L, 0.22856499999999966, 0.1601419999999998, 11605L, 1516513L, 0L, 9L, 220L, 0L, 2L, 1L,
694 + # 6L, 4L,127L, 0L, 0L, 45L, 0L, 45L, 0L, 0L, 0L)
695 + # ),
696 + # (
697 + # ('User', 253, 9, 128, 128, 0, 0),
698 + # ('Total_connections', 3, 2, 11, 11, 0, 0),
699 + # ('Concurrent_connections', 3, 1, 11, 11, 0, 0),
700 + # ('Connected_time', 3, 4, 11, 11, 0, 0),
701 + # ('Busy_time', 5, 21, 21, 21, 31, 0),
702 + # ('Cpu_time', 5, 18, 21, 21, 31, 0),
703 + # ('Bytes_received', 8, 6, 21, 21, 0, 0),
704 + # ('Bytes_sent', 8, 8, 21, 21, 0, 0),
705 + # ('Binlog_bytes_written', 8, 1, 21, 21, 0, 0),
706 + # ('Rows_read', 8, 1, 21, 21, 0, 0),
707 + # ('Rows_sent', 8, 4, 21, 21, 0, 0),
708 + # ('Rows_deleted', 8, 1, 21, 21, 0, 0),
709 + # ('Rows_inserted', 8, 1, 21, 21, 0, 0),
710 + # ('Rows_updated', 8, 1, 21, 21, 0, 0),
711 + # ('Select_commands', 8, 1, 21, 21, 0, 0),
712 + # ('Update_commands', 8, 1, 21, 21, 0, 0),
713 + # ('Other_commands', 8, 4, 21, 21, 0, 0),
714 + # ('Commit_transactions', 8, 1, 21, 21, 0, 0),
715 + # ('Rollback_transactions', 8, 1, 21, 21, 0, 0),
716 + # ('Denied_connections', 8, 4, 21, 21, 0, 0),
717 + # ('Lost_connections', 8, 1, 21, 21, 0, 0),
718 + # ('Access_denied', 8, 2, 21, 21, 0, 0),
719 + # ('Empty_queries', 8, 2, 21, 21, 0, 0),
720 + # ('Total_ssl_connections', 8, 1, 21, 21, 0, 0),
721 + # ('Max_statement_time_exceeded', 8, 1, 21, 21, 0, 0)),
722 + # )
723 + def get_userstats(self, raw_data):
724 + data = dict()
725 + userstats_vars = [e[0] for e in raw_data['user_statistics'][1]]
726 + for i, _ in enumerate(raw_data['user_statistics'][0]):
727 + user_name = raw_data['user_statistics'][0][i][0]
728 + userstats = dict(zip(userstats_vars, raw_data['user_statistics'][0][i]))
729 +
730 + if len(self.charts) > 0:
731 + if ('userstats_{0}_Cpu_time'.format(user_name)) not in self.charts['userstats_cpu']:
732 + self.add_userstats_dimensions(user_name)
733 + self.create_new_userstats_charts(user_name)
734 +
735 + for key in USER_STATISTICS:
736 + if key in userstats:
737 + data['userstats_{0}_{1}'.format(user_name, key)] = userstats[key]
738 +
739 + return data
740 +
741 + def add_userstats_dimensions(self, name):
742 + self.charts['userstats_cpu'].add_dimension(['userstats_{0}_Cpu_time'.format(name), name, 'incremental', 100, 1])
743 +
744 + def create_new_userstats_charts(self, tube):
745 + order, charts = userstats_chart_template(tube)
746 +
747 + for chart_name in order:
748 + params = [chart_name] + charts[chart_name]['options']
749 + dimensions = charts[chart_name]['lines']
750 +
751 + new_chart = self.charts.add_chart(params)
752 + for dimension in dimensions:
753 + new_chart.add_dimension(dimension)