From 00002a8540b6e29fc3a4363d4696671df6992732 Mon Sep 17 00:00:00 2001 From: Mr Chen Date: Sat, 30 Nov 2024 03:32:33 +0800 Subject: [PATCH] update --- plugins/data_query/sql_mysql.py | 99 +++++++++++- plugins/data_query/static/html/index.html | 10 +- plugins/data_query/static/js/app.js | 179 ++++++++++++++++++++++ plugins/task_manager/js/task_manager.js | 38 ++--- web/core/orm.py | 8 +- 5 files changed, 309 insertions(+), 25 deletions(-) diff --git a/plugins/data_query/sql_mysql.py b/plugins/data_query/sql_mysql.py index 6b9dc35e4..19df8bd09 100755 --- a/plugins/data_query/sql_mysql.py +++ b/plugins/data_query/sql_mysql.py @@ -90,7 +90,7 @@ class nosqlMySQL(): keys = ["bind_ip", "port"] result['host'] = '127.0.0.1' - rep = 'port\s*=\s*(.*)' + rep = r'port\s*=\s*(.*)' port_re = re.search(rep, my_content) if port_re: @@ -98,7 +98,7 @@ class nosqlMySQL(): else: result['port'] = 3306 - socket_rep = 'socket\s*=\s*(.*)' + socket_rep = r'socket\s*=\s*(.*)' socket_re = re.search(socket_rep, my_content) if socket_re: result['socket'] = socket_re.groups()[0].strip() @@ -281,6 +281,88 @@ class nosqlMySQLCtr(): rdata['list'] = result return mw.returnData(True,'ok', rdata) + def getNetRow(self, my_instance): + row = {} + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Com_select'") + row['select'] = data['Value'] + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Com_insert'") + row['insert'] = data['Value'] + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Com_update'") + row['update'] = data['Value'] + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Com_delete'") + row['delete'] = data['Value'] + + + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Bytes_received'") + row['recv_bytes'] = data['Value'] + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Bytes_sent'") + row['send_bytes'] = data['Value'] + return row + + + def getNetList(self, args): + from datetime import datetime + sid = args['sid'] + my_instance = self.getInstanceBySid(sid).conn() + if my_instance is False: + return mw.returnData(False,'无法链接') + + rdata = [] + row = {} + row1 = self.getNetRow(my_instance) + # 等待1秒 + time.sleep(1) + row2 = self.getNetRow(my_instance) + + data = my_instance.find("SHOW GLOBAL VARIABLES LIKE 'max_connections'") + row['max_conn'] = data['Value'] + + data = my_instance.find("SHOW GLOBAL STATUS LIKE 'Threads_connected'") + row['conn'] = data['Value'] + + current_time = datetime.now() + row['current_time'] = current_time.strftime("%Y-%m-%d %H:%M:%S") + + row['select'] = int(row2['select']) - int(row1['select']) + row['insert'] = int(row2['insert']) - int(row1['insert']) + row['update'] = int(row2['update']) - int(row1['update']) + row['delete'] = int(row2['delete']) - int(row1['delete']) + + recv_per_second = int(row2['recv_bytes']) - int(row1['recv_bytes']) + send_per_second = int(row2['send_bytes']) - int(row1['send_bytes']) + + # 将每秒接收和发送数据量从字节转换为兆比特 + row['recv_mbps'] = "{:.2f}".format(recv_per_second * 8 / 1000000) + " MBit/s" + row['send_mbps'] = "{:.2f}".format(send_per_second * 8 / 1000000) + " MBit/s" + + rdata.append(row) + return mw.returnData(True, 'ok', rdata) + + + def getTopnList(self, args): + sid = args['sid'] + my_instance = self.getInstanceBySid(sid).conn() + if my_instance is False: + return mw.returnData(False,'无法链接') + + is_performance_schema = my_instance.find("SELECT @@performance_schema") + if is_performance_schema["@@performance_schema"] == 0: + msg = "performance_schema参数未开启。\n" + msg += "在my.cnf配置文件里添加performance_schema=1,并重启mysqld进程生效。" + return mw.returnData(False, msg) + + my_instance.execute("SET @sys.statement_truncate_len=4096") + data = my_instance.query("select query,db,last_seen,exec_count,max_latency,avg_latency from sys.statement_analysis order by exec_count desc, last_seen desc limit 10") + if data is None: + return mw.returnData(False, "查询失败!") + return mw.returnData(True, 'ok', data) + # ---------------------------------- run ---------------------------------- # 获取 mysql 列表 def get_db_list(args): @@ -308,6 +390,19 @@ def get_stats_list(args): t = nosqlMySQLCtr() return t.showStatsList(args) +# 查询执行次数最频繁的前N条SQL语句 +def get_topn_list(args): + t = nosqlMySQLCtr() + return t.getTopnList(args) + +# MySQL服务器的QPS/TPS/网络带宽指标 +def get_net_list(args): + t = nosqlMySQLCtr() + return t.getNetList(args) + + + + # 测试 def test(args): diff --git a/plugins/data_query/static/html/index.html b/plugins/data_query/static/html/index.html index c6bcd3ab0..dd589c749 100644 --- a/plugins/data_query/static/html/index.html +++ b/plugins/data_query/static/html/index.html @@ -51,9 +51,11 @@ - + +
+ + +
@@ -78,6 +80,8 @@ +
+
diff --git a/plugins/data_query/static/js/app.js b/plugins/data_query/static/js/app.js index b8850c4c0..07648cb98 100755 --- a/plugins/data_query/static/js/app.js +++ b/plugins/data_query/static/js/app.js @@ -267,6 +267,185 @@ function initTabMySQL(){ var name = $(this).data('name'); mysqlRunMysqlTab(name); }); + + mysqlCommonFunc(); +} + +function mysqlCommonFuncMysqlNSQL(){ + function renderSQL(){ + var sid = mysqlGetSid(); + myPostCBN('get_topn_list',{'sid':sid} ,function(rdata){ + var data = rdata.data; + if (data['status']){ + var items = data.data; + var tbody = ''; + for (var i = 0; i < items.length; i++) { + var t = ''; + t += ''+items[i].query+''; + t += ''+items[i].db+''; + t += ''+items[i].last_seen+''; + t += ''+items[i].exec_count+''; + t += ''+items[i].max_latency+''; + t += ''+items[i].avg_latency+''; + t += ''; + tbody += t; + } + $('#topn_list tbody').html(tbody); + } else { + layer.msg(data.msg,{icon:2}); + } + }); + } + + var sql_timer = null; + layer.open({ + type: 1, + title: "查询执行次数最频繁的前N条SQL语句", + area: ['1200px', '500px'], + closeBtn: 1, + shadeClose: false, + content: '
\ +
\ +
\ + 实时监控\ +
\ + \ + \ +
\ +
\ +
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
SQL数据名最近时间总次数最大时间平均时间
\ +
', + success:function(i,l){ + renderSQL(); + + $('#real_time_label').click(function(){ + sql_timer = setInterval(function(){ + var t = $('#real_time_monitoring').is(':checked'); + if (t){ + renderSQL(); + } else{ + clearInterval(sql_timer); + } + }, 3000); + }); + } + }); +} + +function mysqlCommonFuncMysqlNet(){ + function renderSQL(){ + var sid = mysqlGetSid(); + myPostCBN('get_net_list',{'sid':sid} ,function(rdata){ + var data = rdata.data; + if (data['status']){ + var items = data.data; + var tbody = ''; + for (var i = 0; i < items.length; i++) { + var t = ''; + t += ''+items[i]['current_time']+''; + t += ''+items[i]['select']+''; + t += ''+items[i]['insert']+''; + t += ''+items[i]['update']+''; + t += ''+items[i]['delete']+''; + t += ''+items[i]['conn']+''; + t += ''+items[i]['max_conn']+''; + t += ''+items[i]['recv_mbps']+''; + t += ''+items[i]['send_mbps']+''; + t += ''; + tbody += t; + } + $('#net_list tbody').html(tbody); + } else { + layer.msg(data.msg,{icon:2}); + } + }); + } + + var sql_timer = null; + layer.open({ + type: 1, + title: "MySQL服务器的QPS/TPS/网络带宽指标", + area: ['700px', '220px'], + closeBtn: 1, + shadeClose: false, + content: '
\ +
\ +
\ + 实时监控\ +
\ + \ + \ +
\ +
\ +
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
时间SelectInsertUpdateDeleteConnMax_connRecvSend
\ +
', + success:function(i,l){ + renderSQL(); + + $('#real_qps_label').click(function(){ + sql_timer = setInterval(function(){ + var t = $('#real_qps_monitoring').is(':checked'); + if (t){ + renderSQL(); + } else{ + clearInterval(sql_timer); + } + }, 3000); + }); + } + }); +} + +function mysqlCommonFunc(){ + $('#mysql_common').click(function(){ + layer.open({ + type: 1, + title: "MySQL常用功能", + area: ['600px', '400px'], + closeBtn: 1, + shadeClose: false, + content: '
\ + \ + \ +
', + success:function(i,l){ + $('#mysql_top_nsql').click(function(){ + mysqlCommonFuncMysqlNSQL(); + }); + + $('#mysql_net_stat').click(function(){ + mysqlCommonFuncMysqlNet(); + }); + } + }); + }); } function mysqlRunMysqlTab(name){ diff --git a/plugins/task_manager/js/task_manager.js b/plugins/task_manager/js/task_manager.js index 6c3f7f36e..16eab7e58 100644 --- a/plugins/task_manager/js/task_manager.js +++ b/plugins/task_manager/js/task_manager.js @@ -506,25 +506,25 @@ function get_resource_list() { buildRealProcess() var tbody_tr = createProcessTable(true); var tbody = '\ - \ - 应用名称\ - PID\ - 线程\ - 用户\ - CPU\ - 内存\ - io读\ - io写\ - 上行\ - 下行\ - 连接\ - 状态\ - 操作\ - \ - \ - ' + tbody_tr + '' - $('#taskResourceTable').html(tbody); - $(".table-cont").css("height", "220px"); + \ + 应用名称\ + PID\ + 线程\ + 用户\ + CPU\ + 内存\ + io读\ + io写\ + 上行\ + 下行\ + 连接\ + 状态\ + 操作\ + \ + \ + ' + tbody_tr + ''; + $('#taskResourceTable').html(tbody); + $(".table-cont").css("height", "220px"); }) $("#load_average").html('') diff --git a/web/core/orm.py b/web/core/orm.py index 89ba623e9..6baaeb790 100755 --- a/web/core/orm.py +++ b/web/core/orm.py @@ -119,6 +119,12 @@ class ORM: print(e) return True + def find(self, sql): + d = self.query(sql) + if d is not None: + return d[0] + return None + def query(self, sql): # 执行SQL语句返回数据集 if not self.__Conn(): @@ -132,7 +138,7 @@ class ORM: self.__Close() return result except Exception as ex: - return ex + return None def __Close(self): # 关闭连接