已关闭
实例监控codecheck #383
AtomGit-Bot创建于 2023年8月25日关闭于 2023年8月28日
实例监控codecheck #383
已关闭
从refs/pull/383/head合入到master
共 164 个文件变更+11936-9940
| @@ -43,8 +43,8 @@ | |||
| 43 | <!-- https://mvnrepository.com/artifact/org.apache.sshd/sshd-scp --> | 43 | <!-- https://mvnrepository.com/artifact/org.apache.sshd/sshd-scp --> |
| 44 | <dependency> | 44 | <dependency> |
| 45 | <groupId>org.apache.sshd</groupId> | 45 | <groupId>org.apache.sshd</groupId> |
| 46 | - <artifactId>sshd-sftp</artifactId> | 46 | + <artifactId>sshd-core</artifactId> |
| 47 | - <version>2.9.2</version> | 47 | + <version>2.10.0</version> |
| 48 | </dependency> | 48 | </dependency> |
| 49 | <dependency> | 49 | <dependency> |
| 50 | <groupId>org.opengauss</groupId> | 50 | <groupId>org.opengauss</groupId> |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/controller/Command.java+79-1
| @@ -1,10 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.controller; | 5 | package org.opengauss.plugin.agent.controller; |
| 5 | 6 | ||
| 6 | import java.io.FileNotFoundException; | 7 | import java.io.FileNotFoundException; |
| 7 | import java.io.IOException; | 8 | import java.io.IOException; |
| 9 | +import java.math.BigDecimal; | ||
| 10 | +import java.math.RoundingMode; | ||
| 11 | +import java.text.DecimalFormat; | ||
| 8 | import java.util.ArrayList; | 12 | import java.util.ArrayList; |
| 9 | import java.util.Arrays; | 13 | import java.util.Arrays; |
| 10 | import java.util.Collections; | 14 | import java.util.Collections; |
| @@ -14,15 +18,18 @@ import java.util.HashSet; | |||
| 14 | import java.util.List; | 18 | import java.util.List; |
| 15 | import java.util.Map; | 19 | import java.util.Map; |
| 16 | import java.util.Set; | 20 | import java.util.Set; |
| 21 | +import java.util.stream.Collectors; | ||
| 17 | 22 | ||
| 18 | import org.opengauss.plugin.agent.config.DbConfig; | 23 | import org.opengauss.plugin.agent.config.DbConfig; |
| 19 | import org.opengauss.plugin.agent.util.CmdUtil; | 24 | import org.opengauss.plugin.agent.util.CmdUtil; |
| 25 | +import org.opengauss.plugin.agent.util.DbUtil; | ||
| 20 | import org.opengauss.plugin.agent.util.StringUtil; | 26 | import org.opengauss.plugin.agent.util.StringUtil; |
| 21 | import org.springframework.web.bind.annotation.GetMapping; | 27 | import org.springframework.web.bind.annotation.GetMapping; |
| 22 | import org.springframework.web.bind.annotation.RequestMapping; | 28 | import org.springframework.web.bind.annotation.RequestMapping; |
| 23 | import org.springframework.web.bind.annotation.RequestParam; | 29 | import org.springframework.web.bind.annotation.RequestParam; |
| 24 | import org.springframework.web.bind.annotation.RestController; | 30 | import org.springframework.web.bind.annotation.RestController; |
| 25 | 31 | ||
| 32 | +import cn.hutool.core.util.ArrayUtil; | ||
| 26 | import cn.hutool.core.util.StrUtil; | 33 | import cn.hutool.core.util.StrUtil; |
| 27 | import lombok.AllArgsConstructor; | 34 | import lombok.AllArgsConstructor; |
| 28 | 35 | ||
| @@ -30,9 +37,14 @@ import lombok.AllArgsConstructor; | |||
| 30 | 37 | ||
| 31 | 38 | ||
| 32 | public class Command { | 39 | public class Command { |
| 40 | + private static final String PID = "PID"; | ||
| 33 | private static final String TOP = "top -b -n 1"; | 41 | private static final String TOP = "top -b -n 1"; |
| 34 | private static final String TOP_DB_PID = "netstat -nap|grep :'|grep LISTEN"; | 42 | private static final String TOP_DB_PID = "netstat -nap|grep :'|grep LISTEN"; |
| 35 | private static final String TOP_DB_THREAD = "top -H -bn1 -p "; | 43 | private static final String TOP_DB_THREAD = "top -H -bn1 -p "; |
| 44 | + private static final String PS = "ps -aux"; | ||
| 45 | + private static final String NETSTAT = "netstat -tulnp|grep gauss"; | ||
| 46 | + private static final String TOTAL_MEMORY = "grep MemTotal /proc/meminfo | awk '{print $2 * 1024}'"; | ||
| 47 | + private final DbUtil dbUtil; | ||
| 36 | private final DbConfig dbConfig; | 48 | private final DbConfig dbConfig; |
| 37 | 49 | ||
| 38 | 50 | ||
| @@ -53,6 +65,7 @@ public class Command { | |||
| 53 | } | 65 | } |
| 54 | top.add(obj); | 66 | top.add(obj); |
| 55 | }); | 67 | }); |
| 68 | + // db thread pids | ||
| 56 | Set<String> pids = new HashSet<>(); | 69 | Set<String> pids = new HashSet<>(); |
| 57 | CmdUtil.readFromCmd(TOP_DB_PID.replaceAll("'", dbConfig.getDbport().toString()), line -> { | 70 | CmdUtil.readFromCmd(TOP_DB_PID.replaceAll("'", dbConfig.getDbport().toString()), line -> { |
| 58 | var part = StringUtil.splitByBlank(line); | 71 | var part = StringUtil.splitByBlank(line); |
| @@ -60,12 +73,67 @@ public class Command { | |||
| 60 | pid = pid.split("/")[0]; | 73 | pid = pid.split("/")[0]; |
| 61 | pids.add(pid); | 74 | pids.add(pid); |
| 62 | }); | 75 | }); |
| 76 | + // full command | ||
| 77 | + CmdUtil.readFromCmd(PS, line -> { | ||
| 78 | + var part = StringUtil.splitByBlank(line); | ||
| 79 | + for (Map<String, String> map : top) { | ||
| 80 | + if (map.get(PID).equals(part[1])) { | ||
| 81 | + map.put("FullCommand", | ||
| 82 | + StrUtil.join(StrUtil.SPACE, (Object[]) ArrayUtil.sub(part, 10, part.length - 1))); | ||
| 83 | + return; | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + }); | ||
| 87 | + // db port | ||
| 88 | + // eg: tcp 0 0 0.0.0.0:5432 0.0.0.0:* LISTEN 3825204/gaussdb | ||
| 89 | + Map<String, Set<String>> ports = new HashMap<>(); | ||
| 90 | + CmdUtil.readFromCmd(NETSTAT, (i, line) -> { | ||
| 91 | + if (i < 2 && !line.startsWith("tcp")) { | ||
| 92 | + return; | ||
| 93 | + } | ||
| 94 | + var part = StringUtil.splitByBlank(line); | ||
| 95 | + if (part.length < 7) { | ||
| 96 | + return; | ||
| 97 | + } | ||
| 98 | + // 5432 | ||
| 99 | + String[] ipPort = part[3].split(StrUtil.COLON); | ||
| 100 | + // 3825204, 5432 | ||
| 101 | + String key = part[6].split(StrUtil.SLASH)[0]; | ||
| 102 | + if (!ports.containsKey(key)) { | ||
| 103 | + ports.put(key, new HashSet<>()); | ||
| 104 | + } | ||
| 105 | + ports.get(key).add(ipPort[ipPort.length - 1]); | ||
| 106 | + }); | ||
| 107 | + top.forEach(map -> { | ||
| 108 | + String pid = map.get(PID); | ||
| 109 | + if ("gaussdb".equals(map.get("COMMAND")) && ports.containsKey(pid)) { | ||
| 110 | + map.put("port", String.valueOf(ports.get(pid).stream().mapToInt(Integer::parseInt).min().orElse(0))); | ||
| 111 | + } | ||
| 112 | + }); | ||
| 113 | + | ||
| 114 | + // thread session/query id | ||
| 115 | + List<Map<String, Object>> sessions = dbUtil.query("select s.lwtid , a.sessionid , a.query_id " | ||
| 116 | + + "from pg_stat_activity a, dbe_perf.thread_wait_status s where a.sessionid = s.sessionid"); | ||
| 117 | + Map<String, Map<String, Object>> sessionMap = sessions.stream() | ||
| 118 | + .collect(Collectors.toMap(map -> map.get("lwtid").toString(), map -> map)); | ||
| 119 | + // thread memory | ||
| 120 | + BigDecimal totalMemory = new BigDecimal(CmdUtil.readFromCmd(TOTAL_MEMORY)).divide(new BigDecimal(100)); | ||
| 121 | + List<Map<String, Object>> memList = dbUtil.query("select s.lwtid , sum(usedsize) used " | ||
| 122 | + + "from GS_SESSION_MEMORY_DETAIL d, dbe_perf.thread_wait_status s " | ||
| 123 | + + "where d.sessid like '%.' || s.tid group by s.lwtid,d.sessid"); | ||
| 124 | + DecimalFormat decimalFormat = new DecimalFormat("#0.0"); | ||
| 125 | + Map<String, Object> memMap = memList.stream() | ||
| 126 | + .collect(Collectors.toMap(map -> map.get("lwtid").toString(), map -> decimalFormat.format( | ||
| 127 | + new BigDecimal(map.get("used").toString()).divide(totalMemory, 2, RoundingMode.HALF_UP)))); | ||
| 128 | + // thread | ||
| 129 | + // e.g. 3825204 omm 20 0 7461264 490508 170264 S 0.0 3.1 2:32.81 gaussdb | ||
| 63 | List<Map<String, String>> db_top = new ArrayList<>(); | 130 | List<Map<String, String>> db_top = new ArrayList<>(); |
| 64 | if (pids.size() != 0) { | 131 | if (pids.size() != 0) { |
| 65 | var pid = pids.iterator().next(); | 132 | var pid = pids.iterator().next(); |
| 66 | CmdUtil.readFromCmd(TOP_DB_THREAD + pid, (i, line) -> { | 133 | CmdUtil.readFromCmd(TOP_DB_THREAD + pid, (i, line) -> { |
| 67 | - if (i < 6) | 134 | + if (i < 6) { |
| 68 | return; | 135 | return; |
| 136 | + } | ||
| 69 | String[] part = StringUtil.splitByBlank(line); | 137 | String[] part = StringUtil.splitByBlank(line); |
| 70 | if (i == 6) { | 138 | if (i == 6) { |
| 71 | header.clear(); | 139 | header.clear(); |
| @@ -76,9 +144,19 @@ public class Command { | |||
| 76 | for (int j = 0; j < header.size(); j++) { | 144 | for (int j = 0; j < header.size(); j++) { |
| 77 | obj.put(header.get(j), part[j]); | 145 | obj.put(header.get(j), part[j]); |
| 78 | } | 146 | } |
| 147 | + if (obj.containsKey(PID)) { | ||
| 148 | + var dbTid = obj.get(PID).toString(); | ||
| 149 | + if (sessionMap.containsKey(dbTid)) { | ||
| 150 | + sessionMap.get(dbTid).forEach((key, value) -> { | ||
| 151 | + obj.put(key, value.toString()); | ||
| 152 | + }); | ||
| 153 | + } | ||
| 154 | + obj.put("%MEM", memMap.getOrDefault(dbTid, "0").toString()); | ||
| 155 | + } | ||
| 79 | db_top.add(obj); | 156 | db_top.add(obj); |
| 80 | }); | 157 | }); |
| 81 | } | 158 | } |
| 159 | + | ||
| 82 | if (StrUtil.isNotBlank(sort)) { | 160 | if (StrUtil.isNotBlank(sort)) { |
| 83 | var comparator = new Comparator<Map<String, String>>() { | 161 | var comparator = new Comparator<Map<String, String>>() { |
| 84 | 162 | ||
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/controller/Config.java+2-1
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.controller; | 5 | package org.opengauss.plugin.agent.controller; |
| 5 | 6 | ||
| 6 | import java.io.File; | 7 | import java.io.File; |
| @@ -36,7 +37,7 @@ public class Config { | |||
| 36 | if (map == null) | 37 | if (map == null) |
| 37 | map = new HashMap<>(); | 38 | map = new HashMap<>(); |
| 38 | map.put("conf", Map.of("hostId", hostId, "node", | 39 | map.put("conf", Map.of("hostId", hostId, "node", |
| 39 | - Map.of("nodeId", nodeId, "dbport", dbport, "username", username, "password", password))); | 40 | + Map.of("nodeId", nodeId, "dbport", dbport, "dbUsername", username, "dbPassword", password))); |
| 40 | // refresh curr config | 41 | // refresh curr config |
| 41 | dbConfig.setHostId(hostId).setNodeId(nodeId).setDbport(dbport).setDbUsername(username) | 42 | dbConfig.setHostId(hostId).setNodeId(nodeId).setDbport(dbport).setDbUsername(username) |
| 42 | .setDbPassword(password); | 43 | .setDbPassword(password); |
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/exception/ExporterException.java+30-0
| @@ -0,0 +1,30 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.agent.exception; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * ExporterException.java | ||
| 9 | + * | ||
| 10 | + * 2023-08-25 | ||
| 11 | + */ | ||
| 12 | +public class ExporterException extends RuntimeException { | ||
| 13 | + private static final long serialVersionUID = 1L; | ||
| 14 | + | ||
| 15 | + public ExporterException() { | ||
| 16 | + super(); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + public ExporterException(String message) { | ||
| 20 | + super(message); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public ExporterException(String message, Throwable cause) { | ||
| 24 | + super(message, cause); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public ExporterException(Throwable cause) { | ||
| 28 | + super(cause); | ||
| 29 | + } | ||
| 30 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/opengauss/DBStatus.java+48-0
| @@ -0,0 +1,48 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.agent.metric.opengauss; | ||
| 6 | + | ||
| 7 | +import java.io.FileNotFoundException; | ||
| 8 | +import java.io.IOException; | ||
| 9 | +import java.util.Collections; | ||
| 10 | +import java.util.HashMap; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +import org.opengauss.plugin.agent.metric.DBmetric; | ||
| 15 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 16 | +import org.opengauss.plugin.agent.util.DbUtil; | ||
| 17 | +import org.springframework.stereotype.Service; | ||
| 18 | + | ||
| 19 | +import io.prometheus.client.Collector; | ||
| 20 | +import lombok.RequiredArgsConstructor; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * DBStatus | ||
| 24 | + * | ||
| 25 | + * 2023/8/7 11:46 | ||
| 26 | + */ | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +public class DBStatus implements DBmetric { | ||
| 30 | + private static final String SQL = "select 1 as count"; | ||
| 31 | + | ||
| 32 | + private final DbUtil dbUtil; | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 36 | + if (dbPort == null) { | ||
| 37 | + return Collections.emptyMap(); | ||
| 38 | + } | ||
| 39 | + Map<String, Metric> map = new HashMap<>(); | ||
| 40 | + List<Map<String, Object>> query = dbUtil.query(SQL); | ||
| 41 | + Integer count = 0; | ||
| 42 | + if (query.get(0).get("count") instanceof Integer) { | ||
| 43 | + count = (Integer) query.get(0).get("count"); | ||
| 44 | + } | ||
| 45 | + map.put("pg_db_status", new Metric(Collector.Type.GAUGE, null).addValue(null, count)); | ||
| 46 | + return map; | ||
| 47 | + } | ||
| 48 | +} | ||
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/opengauss/OpengaussExporter.java+14-1
| @@ -25,6 +25,7 @@ import org.springframework.beans.factory.InitializingBean; | |||
| 25 | import org.springframework.core.io.ClassPathResource; | 25 | import org.springframework.core.io.ClassPathResource; |
| 26 | import org.springframework.scheduling.annotation.Scheduled; | 26 | import org.springframework.scheduling.annotation.Scheduled; |
| 27 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
| 28 | +import org.springframework.util.StringUtils; | ||
| 28 | import org.yaml.snakeyaml.Yaml; | 29 | import org.yaml.snakeyaml.Yaml; |
| 29 | 30 | ||
| 30 | import cn.hutool.core.bean.BeanUtil; | 31 | import cn.hutool.core.bean.BeanUtil; |
| @@ -70,7 +71,7 @@ public class OpengaussExporter implements DBmetric, InitializingBean { | |||
| 70 | return metricData; | 71 | return metricData; |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | - @Scheduled(fixedRate = 15000, initialDelay = 1000) | 74 | + @Scheduled(fixedDelay = 15000, initialDelay = 1000) |
| 74 | public void catchMetric() { | 75 | public void catchMetric() { |
| 75 | if (CONFIG.size() == 0) { | 76 | if (CONFIG.size() == 0) { |
| 76 | return; | 77 | return; |
| @@ -97,6 +98,9 @@ public class OpengaussExporter implements DBmetric, InitializingBean { | |||
| 97 | private Map<String, Metric> metric(Entry<String, queryInstance> conf) { | 98 | private Map<String, Metric> metric(Entry<String, queryInstance> conf) { |
| 98 | String sql = null; | 99 | String sql = null; |
| 99 | for (query q : conf.getValue().getQuery()) { | 100 | for (query q : conf.getValue().getQuery()) { |
| 101 | + if (!isRoleMatched(q)) { | ||
| 102 | + continue; | ||
| 103 | + } | ||
| 100 | if (q.getStatus() == state.enable) { | 104 | if (q.getStatus() == state.enable) { |
| 101 | sql = q.getSql(); | 105 | sql = q.getSql(); |
| 102 | break; | 106 | break; |
| @@ -143,6 +147,15 @@ public class OpengaussExporter implements DBmetric, InitializingBean { | |||
| 143 | return result; | 147 | return result; |
| 144 | } | 148 | } |
| 145 | 149 | ||
| 150 | + private boolean isRoleMatched(query q) { | ||
| 151 | + String dbRole = q.getDbRole(); | ||
| 152 | + if (!StringUtils.hasLength(dbRole)) { | ||
| 153 | + return true; | ||
| 154 | + } | ||
| 155 | + List<Map<String, Object>> query = dbUtil.query("SELECT pg_is_in_recovery();"); | ||
| 156 | + return ((boolean) query.get(0).get("pg_is_in_recovery")) != "primary".equalsIgnoreCase(dbRole); | ||
| 157 | + } | ||
| 158 | + | ||
| 146 | 159 | ||
| 147 | public static class queryInstance { | 160 | public static class queryInstance { |
| 148 | private String name; | 161 | private String name; |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/VmStat.java+4-2
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.metric.system; | 5 | package org.opengauss.plugin.agent.metric.system; |
| 5 | 6 | ||
| 6 | import java.io.FileNotFoundException; | 7 | import java.io.FileNotFoundException; |
| @@ -38,12 +39,13 @@ public class VmStat implements OSmetric { | |||
| 38 | "us", | 39 | "us", |
| 39 | "sy", | 40 | "sy", |
| 40 | "wa", | 41 | "wa", |
| 41 | - "st" }; | 42 | + "st" |
| 43 | + }; | ||
| 42 | 44 | ||
| 43 | 45 | ||
| 44 | public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | 46 | public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { |
| 45 | Map<String, Metric> map = new HashMap<>(); | 47 | Map<String, Metric> map = new HashMap<>(); |
| 46 | - CmdUtil.readFromCmd(CmdUtil.cmd("vmstat"), (index, line) -> { | 48 | + CmdUtil.readFromCmd("vmstat", (index, line) -> { |
| 47 | if (index < 2) | 49 | if (index < 2) |
| 48 | return; | 50 | return; |
| 49 | var part = StringUtil.splitByBlank(line); | 51 | var part = StringUtil.splitByBlank(line); |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/memory/Free.java+12-4
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.metric.system.memory; | 5 | package org.opengauss.plugin.agent.metric.system.memory; |
| 5 | 6 | ||
| 6 | import java.io.FileNotFoundException; | 7 | import java.io.FileNotFoundException; |
| @@ -9,22 +10,29 @@ import java.util.HashMap; | |||
| 9 | import java.util.Map; | 10 | import java.util.Map; |
| 10 | 11 | ||
| 11 | import org.opengauss.plugin.agent.metric.Metric; | 12 | import org.opengauss.plugin.agent.metric.Metric; |
| 13 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 12 | import org.opengauss.plugin.agent.util.CmdUtil; | 14 | import org.opengauss.plugin.agent.util.CmdUtil; |
| 13 | import org.opengauss.plugin.agent.util.StringUtil; | 15 | import org.opengauss.plugin.agent.util.StringUtil; |
| 14 | import org.springframework.stereotype.Service; | 16 | import org.springframework.stereotype.Service; |
| 15 | 17 | ||
| 16 | -import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 17 | - | ||
| 18 | import io.prometheus.client.Collector.Type; | 18 | import io.prometheus.client.Collector.Type; |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | public class Free implements OSmetric { | 21 | public class Free implements OSmetric { |
| 22 | - private static final String[] KEYS = { "type", "total", "used", "free", "shared", "cache", "available" }; | 22 | + private static final String[] KEYS = { |
| 23 | + "type", | ||
| 24 | + "total", | ||
| 25 | + "used", | ||
| 26 | + "free", | ||
| 27 | + "shared", | ||
| 28 | + "cache", | ||
| 29 | + "available" | ||
| 30 | + }; | ||
| 23 | 31 | ||
| 24 | 32 | ||
| 25 | public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | 33 | public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { |
| 26 | Map<String, Metric> map = new HashMap<>(); | 34 | Map<String, Metric> map = new HashMap<>(); |
| 27 | - CmdUtil.readFromCmd(CmdUtil.cmd("free"), (index, line) -> { | 35 | + CmdUtil.readFromCmd("free", (index, line) -> { |
| 28 | if (index == 0) { | 36 | if (index == 0) { |
| 29 | // total used free shared buff/cache available | 37 | // total used free shared buff/cache available |
| 30 | return; | 38 | return; |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/network/Socket.java+3-10
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.metric.system.network; | 5 | package org.opengauss.plugin.agent.metric.system.network; |
| 5 | 6 | ||
| 6 | import java.io.FileNotFoundException; | 7 | import java.io.FileNotFoundException; |
| @@ -10,12 +11,11 @@ import java.util.HashMap; | |||
| 10 | import java.util.Map; | 11 | import java.util.Map; |
| 11 | 12 | ||
| 12 | import org.opengauss.plugin.agent.metric.Metric; | 13 | import org.opengauss.plugin.agent.metric.Metric; |
| 14 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 13 | import org.opengauss.plugin.agent.util.CmdUtil; | 15 | import org.opengauss.plugin.agent.util.CmdUtil; |
| 14 | import org.opengauss.plugin.agent.util.StringUtil; | 16 | import org.opengauss.plugin.agent.util.StringUtil; |
| 15 | import org.springframework.stereotype.Service; | 17 | import org.springframework.stereotype.Service; |
| 16 | 18 | ||
| 17 | -import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 18 | - | ||
| 19 | import io.prometheus.client.Collector.Type; | 19 | import io.prometheus.client.Collector.Type; |
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -24,14 +24,8 @@ public class Socket implements OSmetric { | |||
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | 26 | public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { |
| 27 | - // TODO | ||
| 28 | -// try { | ||
| 29 | -// CmdUtil.readFromCmd(CmdUtil.cmd("ss -e"), line -> { | ||
| 30 | -// | ||
| 31 | -// }); | ||
| 32 | -// } catch (IOException e) { | ||
| 33 | Map<String, Integer> counter = new HashMap<>(); | 27 | Map<String, Integer> counter = new HashMap<>(); |
| 34 | - CmdUtil.readFromCmd(CmdUtil.cmd("netstat"), (index, line) -> { | 28 | + CmdUtil.readFromCmd("netstat", (index, line) -> { |
| 35 | if (index < 2) | 29 | if (index < 2) |
| 36 | return; | 30 | return; |
| 37 | var part = StringUtil.splitByBlank(line); | 31 | var part = StringUtil.splitByBlank(line); |
| @@ -43,7 +37,6 @@ public class Socket implements OSmetric { | |||
| 43 | counter.put(key, counter.getOrDefault(key, 0) + 1); | 37 | counter.put(key, counter.getOrDefault(key, 0) + 1); |
| 44 | } | 38 | } |
| 45 | }); | 39 | }); |
| 46 | -// } | ||
| 47 | var metric = new Metric(Type.GAUGE, Arrays.asList("proto", "state")); | 40 | var metric = new Metric(Type.GAUGE, Arrays.asList("proto", "state")); |
| 48 | counter.forEach((key, value) -> { | 41 | counter.forEach((key, value) -> { |
| 49 | var part = key.split(SPLIT); | 42 | var part = key.split(SPLIT); |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/server/HostMetric.java+2-1
| @@ -83,7 +83,7 @@ public class HostMetric implements ApplicationRunner { | |||
| 83 | return StringUtil.replaceParenthesis((collector instanceof DBmetric) ? k : "agent_" + collectorName + k); | 83 | return StringUtil.replaceParenthesis((collector instanceof DBmetric) ? k : "agent_" + collectorName + k); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | - @Scheduled(fixedRate = 1000) | 86 | + @Scheduled(fixedDelay = 5000) |
| 87 | public void cache() { | 87 | public void cache() { |
| 88 | try { | 88 | try { |
| 89 | collectors.forEach((collectorName, collector) -> { | 89 | collectors.forEach((collectorName, collector) -> { |
| @@ -128,6 +128,7 @@ public class HostMetric implements ApplicationRunner { | |||
| 128 | } | 128 | } |
| 129 | CACHE.put(collectorName, list); | 129 | CACHE.put(collectorName, list); |
| 130 | }); | 130 | }); |
| 131 | + log.info("refresh metric cache!"); | ||
| 131 | } catch (Exception e) { | 132 | } catch (Exception e) { |
| 132 | log.error("metric cache err", e); | 133 | log.error("metric cache err", e); |
| 133 | } | 134 | } |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/CmdUtil.java+47-24
| @@ -1,60 +1,83 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.util; | 5 | package org.opengauss.plugin.agent.util; |
| 5 | 6 | ||
| 6 | import java.io.BufferedReader; | 7 | import java.io.BufferedReader; |
| 7 | import java.io.FileNotFoundException; | 8 | import java.io.FileNotFoundException; |
| 8 | import java.io.IOException; | 9 | import java.io.IOException; |
| 9 | import java.io.InputStreamReader; | 10 | import java.io.InputStreamReader; |
| 10 | -import java.util.Arrays; | 11 | +import java.util.EnumSet; |
| 11 | import java.util.function.BiConsumer; | 12 | import java.util.function.BiConsumer; |
| 12 | import java.util.function.Consumer; | 13 | import java.util.function.Consumer; |
| 13 | 14 | ||
| 15 | +import org.apache.sshd.client.SshClient; | ||
| 16 | +import org.apache.sshd.client.channel.ClientChannelEvent; | ||
| 17 | +import org.apache.sshd.client.session.ClientSession; | ||
| 18 | +import org.opengauss.plugin.agent.exception.ExporterException; | ||
| 19 | + | ||
| 20 | +import cn.hutool.core.thread.ThreadUtil; | ||
| 21 | +import cn.hutool.core.util.StrUtil; | ||
| 14 | import lombok.extern.log4j.Log4j2; | 22 | import lombok.extern.log4j.Log4j2; |
| 15 | 23 | ||
| 16 | 24 | ||
| 17 | public class CmdUtil { | 25 | public class CmdUtil { |
| 18 | - public static final String[] cmd(String... cmd) { | 26 | + private static final int SESSION_TIMEOUT = 10000; |
| 19 | - return cmd; | 27 | + private static final int CHANNEL_TIMEOUT = 1000 * 60 * 5; |
| 28 | + | ||
| 29 | + private static SshClient client; | ||
| 30 | + private static ClientSession session; | ||
| 31 | + | ||
| 32 | + static { | ||
| 33 | + try { | ||
| 34 | + client = SshClient.setUpDefaultClient(); | ||
| 35 | + client.start(); | ||
| 36 | + session = client.connect("root", "127.0.0.1", 22).verify().getSession(); | ||
| 37 | + session.addPasswordIdentity("Ncti@001122"); | ||
| 38 | + session.auth().verify(SESSION_TIMEOUT); | ||
| 39 | + log.info("server init success"); | ||
| 40 | + } catch (Exception e) { | ||
| 41 | + e.printStackTrace(); | ||
| 42 | + } | ||
| 20 | } | 43 | } |
| 21 | 44 | ||
| 22 | public static final void readFromCmd(String cmd, Consumer<String> consumer) | 45 | public static final void readFromCmd(String cmd, Consumer<String> consumer) |
| 23 | throws FileNotFoundException, IOException { | 46 | throws FileNotFoundException, IOException { |
| 24 | - readFromCmd(Arrays.asList("sh", "-c", cmd).toArray(new String[3]), consumer); | 47 | + if (consumer != null) { |
| 48 | + readFromCmd(cmd, (i, line) -> consumer.accept(line)); | ||
| 49 | + } | ||
| 25 | } | 50 | } |
| 26 | 51 | ||
| 27 | public static final void readFromCmd(String cmd, BiConsumer<Integer, String> consumer) | 52 | public static final void readFromCmd(String cmd, BiConsumer<Integer, String> consumer) |
| 28 | throws FileNotFoundException, IOException { | 53 | throws FileNotFoundException, IOException { |
| 29 | - readFromCmd(Arrays.asList("sh", "-c", cmd).toArray(new String[3]), consumer); | 54 | + log.debug("exec:" + cmd); |
| 30 | - } | 55 | + var channel = session.createExecChannel(cmd); |
| 56 | + channel.setPtyType("ansi"); | ||
| 57 | + channel.setPtyColumns(300); | ||
| 58 | + channel.setPtyWidth(300); | ||
| 59 | + channel.open(); | ||
| 31 | 60 | ||
| 32 | - public static final void readFromCmd(String[] cmd, Consumer<String> consumer) | 61 | + channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), CHANNEL_TIMEOUT); |
| 33 | - throws FileNotFoundException, IOException { | 62 | + for (int i = 0; i < 100 && channel.getExitStatus() == null; i++) |
| 34 | - if (consumer != null) | 63 | + ThreadUtil.sleep(100L); |
| 35 | - readFromCmd(cmd, (i, line) -> consumer.accept(line)); | 64 | + if (channel.getExitStatus() != null && channel.getExitStatus() != 0) { |
| 36 | - } | 65 | + throw new ExporterException(cmd + StrUtil.SPACE + StrUtil.LF + StrUtil.SPACE + channel.getInvertedErr()); |
| 37 | - | ||
| 38 | - public static final void readFromCmd(String[] cmd, BiConsumer<Integer, String> consumer) | ||
| 39 | - throws FileNotFoundException, IOException { | ||
| 40 | - var process = new ProcessBuilder().command(cmd).start(); | ||
| 41 | - try { | ||
| 42 | - process.waitFor(); | ||
| 43 | - } catch (InterruptedException e) { | ||
| 44 | - log.error("", e); | ||
| 45 | - return; | ||
| 46 | } | 66 | } |
| 47 | - try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()));) { | 67 | + |
| 68 | + try (var reader = new BufferedReader(new InputStreamReader(channel.getInvertedOut()));) { | ||
| 48 | int i = -1; | 69 | int i = -1; |
| 49 | while (reader.ready()) { | 70 | while (reader.ready()) { |
| 50 | i++; | 71 | i++; |
| 51 | String line = reader.readLine(); | 72 | String line = reader.readLine(); |
| 52 | - if (line.isBlank()) | 73 | + if (line.isBlank()) { |
| 53 | continue; | 74 | continue; |
| 54 | - if (consumer != null) | 75 | + } |
| 76 | + if (consumer != null) { | ||
| 55 | consumer.accept(i, line); | 77 | consumer.accept(i, line); |
| 78 | + } | ||
| 56 | } | 79 | } |
| 57 | - } catch (Exception e) { | 80 | + } catch (IOException e) { |
| 58 | log.error("cmd '{}' format error", cmd, e); | 81 | log.error("cmd '{}' format error", cmd, e); |
| 59 | throw e; | 82 | throw e; |
| 60 | } | 83 | } |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/DbUtil.java+5-6
| @@ -32,14 +32,13 @@ public class DbUtil { | |||
| 32 | synchronized (this) { | 32 | synchronized (this) { |
| 33 | try { | 33 | try { |
| 34 | if (conn == null) { | 34 | if (conn == null) { |
| 35 | - conn = DriverManager | 35 | + conn = DriverManager.getConnection( |
| 36 | - .getConnection( | 36 | + "jdbc:opengauss://" + "localhost" + ":" + dbConfig.getDbport() + "/" + "postgres" |
| 37 | - "jdbc:opengauss://" + "localhost" + ":" + dbConfig.getDbport() + "/" | 37 | + + "?TimeZone=UTC&ApplicationName=DataKit Instance Monitoring Agent", |
| 38 | - + "postgres" | 38 | + dbConfig.getDbUsername(), dbConfig.getDbPassword()); |
| 39 | - + "?TimeZone=UTC&ApplicationName=DataKit Instance Monitoring Agent", | ||
| 40 | - dbConfig.getDbUsername(), dbConfig.getDbPassword()); | ||
| 41 | } | 39 | } |
| 42 | } catch (SQLException e) { | 40 | } catch (SQLException e) { |
| 41 | + log.error("db connection fail", e); | ||
| 43 | conn = null; | 42 | conn = null; |
| 44 | } | 43 | } |
| 45 | } | 44 | } |
Mplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/FileUtil.java+2-1
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package org.opengauss.plugin.agent.util; | 5 | package org.opengauss.plugin.agent.util; |
| 5 | 6 | ||
| 6 | import java.io.FileNotFoundException; | 7 | import java.io.FileNotFoundException; |
| @@ -23,6 +24,6 @@ public class FileUtil { | |||
| 23 | */ | 24 | */ |
| 24 | public static final void readFileLine(String name, BiConsumer<Integer, String> consumer) | 25 | public static final void readFileLine(String name, BiConsumer<Integer, String> consumer) |
| 25 | throws FileNotFoundException, IOException { | 26 | throws FileNotFoundException, IOException { |
| 26 | - CmdUtil.readFromCmd(CmdUtil.cmd("cat", name), consumer); | 27 | + CmdUtil.readFromCmd("cat " + name, consumer); |
| 27 | } | 28 | } |
| 28 | } | 29 | } |
| @@ -1547,7 +1547,102 @@ gauss_thread_wait_status: | |||
| 1547 | desc: openGauss database thread metrics | 1547 | desc: openGauss database thread metrics |
| 1548 | query: | 1548 | query: |
| 1549 | - name: gauss_thread_wait_status | 1549 | - name: gauss_thread_wait_status |
| 1550 | - sql: select wait_status, count(*) count from pg_thread_wait_status group by wait_status; | 1550 | + sql: |- |
| 1551 | + select | ||
| 1552 | + * | ||
| 1553 | + from | ||
| 1554 | + ( | ||
| 1555 | + select | ||
| 1556 | + WAIT_STATUS, | ||
| 1557 | + COUNT(*) COUNT | ||
| 1558 | + from | ||
| 1559 | + PG_THREAD_WAIT_STATUS | ||
| 1560 | + where | ||
| 1561 | + WAIT_STATUS not like 'SET CMD%' | ||
| 1562 | + and WAIT_STATUS not like 'WAIT NODE%' | ||
| 1563 | + and WAIT_STATUS not like 'POOLER CREATE CONN%' | ||
| 1564 | + and WAIT_STATUS not like 'FLUSH DATA%' | ||
| 1565 | + and WAIT_STATUS not like 'STREAM GET CONN%' | ||
| 1566 | + and WAIT_STATUS not like 'WAIT PRODUCER READY%' | ||
| 1567 | + and WAIT_STATUS not like 'analyze:%' | ||
| 1568 | + and wait_status not like 'vacuum:%' | ||
| 1569 | + and wait_status not like 'vacuum full:%' | ||
| 1570 | + group by | ||
| 1571 | + WAIT_STATUS | ||
| 1572 | + union all | ||
| 1573 | + select | ||
| 1574 | + 'SET CMD', | ||
| 1575 | + COUNT(*) COUNT | ||
| 1576 | + from | ||
| 1577 | + PG_THREAD_WAIT_STATUS | ||
| 1578 | + where | ||
| 1579 | + WAIT_STATUS like 'SET CMD%' | ||
| 1580 | + union all | ||
| 1581 | + select | ||
| 1582 | + 'WAIT NODE', | ||
| 1583 | + COUNT(*) COUNT | ||
| 1584 | + from | ||
| 1585 | + PG_THREAD_WAIT_STATUS | ||
| 1586 | + where | ||
| 1587 | + WAIT_STATUS like 'WAIT NODE%' | ||
| 1588 | + union all | ||
| 1589 | + select | ||
| 1590 | + 'POOLER CREATE CONN', | ||
| 1591 | + COUNT(*) COUNT | ||
| 1592 | + from | ||
| 1593 | + PG_THREAD_WAIT_STATUS | ||
| 1594 | + where | ||
| 1595 | + WAIT_STATUS like 'POOLER CREATE CONN%' | ||
| 1596 | + union all | ||
| 1597 | + select | ||
| 1598 | + 'FLUSH DATA', | ||
| 1599 | + COUNT(*) COUNT | ||
| 1600 | + from | ||
| 1601 | + PG_THREAD_WAIT_STATUS | ||
| 1602 | + where | ||
| 1603 | + WAIT_STATUS like 'FLUSH DATA%' | ||
| 1604 | + union all | ||
| 1605 | + select | ||
| 1606 | + 'STREAM GET CONN', | ||
| 1607 | + COUNT(*) COUNT | ||
| 1608 | + from | ||
| 1609 | + PG_THREAD_WAIT_STATUS | ||
| 1610 | + where | ||
| 1611 | + WAIT_STATUS like 'STREAM GET CONN%' | ||
| 1612 | + union all | ||
| 1613 | + select | ||
| 1614 | + 'analyze', | ||
| 1615 | + COUNT(*) COUNT | ||
| 1616 | + from | ||
| 1617 | + PG_THREAD_WAIT_STATUS | ||
| 1618 | + where | ||
| 1619 | + WAIT_STATUS like 'analyze%' | ||
| 1620 | + union all | ||
| 1621 | + select | ||
| 1622 | + 'WAIT PRODUCER READY', | ||
| 1623 | + COUNT(*) COUNT | ||
| 1624 | + from | ||
| 1625 | + PG_THREAD_WAIT_STATUS | ||
| 1626 | + where | ||
| 1627 | + WAIT_STATUS like 'WAIT PRODUCER READY%' | ||
| 1628 | + union all | ||
| 1629 | + select | ||
| 1630 | + 'vacuum', | ||
| 1631 | + COUNT(*) COUNT | ||
| 1632 | + from | ||
| 1633 | + PG_THREAD_WAIT_STATUS | ||
| 1634 | + where | ||
| 1635 | + WAIT_STATUS like 'vacuum:%' | ||
| 1636 | + union all | ||
| 1637 | + select | ||
| 1638 | + 'vacuum full', | ||
| 1639 | + COUNT(*) COUNT | ||
| 1640 | + from | ||
| 1641 | + PG_THREAD_WAIT_STATUS | ||
| 1642 | + where | ||
| 1643 | + WAIT_STATUS like 'vacuum full:%') | ||
| 1644 | + where | ||
| 1645 | + count != 0; | ||
| 1551 | version: '>=0.0.0' | 1646 | version: '>=0.0.0' |
| 1552 | timeout: 1 | 1647 | timeout: 1 |
| 1553 | ttl: 60 | 1648 | ttl: 60 |
| @@ -2536,13 +2631,13 @@ pg_stat_activity_slow: | |||
| 2536 | query: | 2631 | query: |
| 2537 | - name: count | 2632 | - name: count |
| 2538 | sql: |- | 2633 | sql: |- |
| 2539 | - select count(1) count | 2634 | + select count(1) count |
| 2540 | - from pg_stat_activity | 2635 | + from pg_stat_activity |
| 2541 | - where | 2636 | + where |
| 2542 | - pid <> pg_backend_pid() | 2637 | + pid <> pg_backend_pid() |
| 2543 | - and xact_start is not null | 2638 | + and xact_start is not null |
| 2544 | - and state = 'active' | 2639 | + and state = 'active' |
| 2545 | - and extract(epoch from now() - xact_start)>3 | 2640 | + and extract(epoch from now() - xact_start)>3 |
| 2546 | version: '>=0.0.0' | 2641 | version: '>=0.0.0' |
| 2547 | timeout: 10 | 2642 | timeout: 10 |
| 2548 | ttl: 3600 | 2643 | ttl: 3600 |
| @@ -2551,4 +2646,85 @@ pg_stat_activity_slow: | |||
| 2551 | metrics: | 2646 | metrics: |
| 2552 | - name: count | 2647 | - name: count |
| 2553 | description: index scans initiated on this index | 2648 | description: index scans initiated on this index |
| 2554 | - usage: GAUGE | 2649 | + usage: GAUGE |
| 2650 | + | ||
| 2651 | +pg_wal_write_total: | ||
| 2652 | + name: count | ||
| 2653 | + query: | ||
| 2654 | + - name: count | ||
| 2655 | + sql: select round(pg_xlog_location_diff(pg_current_xlog_location(), '0/0')/1024) as count | ||
| 2656 | + version: '>=0.0.0' | ||
| 2657 | + timeout: 10 | ||
| 2658 | + ttl: 3600 | ||
| 2659 | + dbRole: "primary" | ||
| 2660 | + status: enable | ||
| 2661 | + metrics: | ||
| 2662 | + - name: count | ||
| 2663 | + description: index scans initiated on this index | ||
| 2664 | + usage: GAUGE | ||
| 2665 | + | ||
| 2666 | +pg_wal_send_pressure: | ||
| 2667 | + name: count | ||
| 2668 | + query: | ||
| 2669 | + - name: count | ||
| 2670 | + sql: |- | ||
| 2671 | + select round(sum(pg_xlog_location_diff(sender_write_location, sender_sent_location))/1024) as count | ||
| 2672 | + from pg_stat_get_wal_senders(); | ||
| 2673 | + version: '>=0.0.0' | ||
| 2674 | + timeout: 10 | ||
| 2675 | + ttl: 3600 | ||
| 2676 | + dbRole: "primary" | ||
| 2677 | + status: enable | ||
| 2678 | + metrics: | ||
| 2679 | + - name: count | ||
| 2680 | + description: index scans initiated on this index | ||
| 2681 | + usage: GAUGE | ||
| 2682 | + | ||
| 2683 | +pg_wal_delay: | ||
| 2684 | + name: count | ||
| 2685 | + query: | ||
| 2686 | + - name: count | ||
| 2687 | + sql: |- | ||
| 2688 | + select round(pg_xlog_location_diff (sender_sent_location,receiver_received_location)/1024) received, | ||
| 2689 | + round(pg_xlog_location_diff (sender_write_location,receiver_write_location)/1024) as write, | ||
| 2690 | + round(pg_xlog_location_diff(sender_replay_location,receiver_replay_location)/1024) replay | ||
| 2691 | + from pg_stat_get_wal_receiver() | ||
| 2692 | + version: '>=0.0.0' | ||
| 2693 | + timeout: 10 | ||
| 2694 | + ttl: 3600 | ||
| 2695 | + dbRole: "standby" | ||
| 2696 | + status: enable | ||
| 2697 | + metrics: | ||
| 2698 | + - name: received | ||
| 2699 | + description: index scans initiated on this index | ||
| 2700 | + usage: GAUGE | ||
| 2701 | + - name: write | ||
| 2702 | + description: index scans initiated on this index | ||
| 2703 | + usage: GAUGE | ||
| 2704 | + - name: replay | ||
| 2705 | + description: index scans initiated on this index | ||
| 2706 | + usage: GAUGE usage: GAUGE | ||
| 2707 | + | ||
| 2708 | +pg_tablespace: | ||
| 2709 | + name: pg_tablespace | ||
| 2710 | + desc: openGauss tablespace | ||
| 2711 | + query: | ||
| 2712 | + - name: pg_tablespace | ||
| 2713 | + sql: |- | ||
| 2714 | + SELECT spcname as name, pg_tablespace_size(spcname)/1024/1024 AS size FROM pg_tablespace; | ||
| 2715 | + version: '>=0.0.0' | ||
| 2716 | + timeout: 0.1 | ||
| 2717 | + ttl: 10 | ||
| 2718 | + status: enable | ||
| 2719 | + dbRole: "" | ||
| 2720 | + metrics: | ||
| 2721 | + - name: name | ||
| 2722 | + description: tablespace name | ||
| 2723 | + usage: LABEL | ||
| 2724 | + - name: size | ||
| 2725 | + description: tablespace size | ||
| 2726 | + usage: GAUGE | ||
| 2727 | + status: enable | ||
| 2728 | + ttl: 60 | ||
| 2729 | + timeout: 0.1 | ||
| 2730 | + public: true | ||
| @@ -11,6 +11,7 @@ | |||
| 11 | <plugin-id>observability-instance</plugin-id> | 11 | <plugin-id>observability-instance</plugin-id> |
| 12 | <npm.run.script>buildNoTest</npm.run.script> | 12 | <npm.run.script>buildNoTest</npm.run.script> |
| 13 | <web.build.skip>false</web.build.skip> | 13 | <web.build.skip>false</web.build.skip> |
| 14 | + <build.frontend.skip>false</build.frontend.skip> | ||
| 14 | <!--project--> | 15 | <!--project--> |
| 15 | <java.version>11</java.version> | 16 | <java.version>11</java.version> |
| 16 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | 17 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| @@ -22,7 +23,6 @@ | |||
| 22 | <fastjson.version>1.2.78</fastjson.version> | 23 | <fastjson.version>1.2.78</fastjson.version> |
| 23 | <lombok.version>1.18.24</lombok.version> | 24 | <lombok.version>1.18.24</lombok.version> |
| 24 | <hutool.version>5.0.3</hutool.version> | 25 | <hutool.version>5.0.3</hutool.version> |
| 25 | - <build.frontend.skip>false</build.frontend.skip> | ||
| 26 | </properties> | 26 | </properties> |
| 27 | <dependencies> | 27 | <dependencies> |
| 28 | <!-- same as framework --> | 28 | <!-- same as framework --> |
| @@ -241,6 +241,9 @@ | |||
| 241 | <source>${java.version}</source> | 241 | <source>${java.version}</source> |
| 242 | <target>${java.version}</target> | 242 | <target>${java.version}</target> |
| 243 | <encoding>${project.build.sourceEncoding}</encoding> | 243 | <encoding>${project.build.sourceEncoding}</encoding> |
| 244 | + <compilerArgs> | ||
| 245 | + <arg>-parameters</arg> | ||
| 246 | + </compilerArgs> | ||
| 244 | </configuration> | 247 | </configuration> |
| 245 | </plugin> | 248 | </plugin> |
| 246 | <plugin> | 249 | <plugin> |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/ObservabilityPluginApplication.java+6-1
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance; | 5 | package com.nctigba.observability.instance; |
| 5 | 6 | ||
| 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; | 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| @@ -8,7 +9,9 @@ import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; | |||
| 8 | import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; | 9 | import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; |
| 9 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | 10 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
| 10 | import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; | 11 | import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; |
| 12 | +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; | ||
| 11 | import org.springframework.cache.annotation.EnableCaching; | 13 | import org.springframework.cache.annotation.EnableCaching; |
| 14 | +import org.springframework.context.annotation.EnableAspectJAutoProxy; | ||
| 12 | 15 | ||
| 13 | import com.gitee.starblues.bootstrap.SpringPluginBootstrap; | 16 | import com.gitee.starblues.bootstrap.SpringPluginBootstrap; |
| 14 | 17 | ||
| @@ -17,8 +20,10 @@ import com.gitee.starblues.bootstrap.SpringPluginBootstrap; | |||
| 17 | HibernateJpaAutoConfiguration.class, | 20 | HibernateJpaAutoConfiguration.class, |
| 18 | RedisAutoConfiguration.class, | 21 | RedisAutoConfiguration.class, |
| 19 | RedisRepositoriesAutoConfiguration.class, | 22 | RedisRepositoriesAutoConfiguration.class, |
| 20 | - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class }) | 23 | + SecurityAutoConfiguration.class |
| 24 | +}) | ||
| 21 | 25 | ||
| 26 | + | ||
| 22 | public class ObservabilityPluginApplication extends SpringPluginBootstrap { | 27 | public class ObservabilityPluginApplication extends SpringPluginBootstrap { |
| 23 | 28 | ||
| 24 | public static void main(String[] args) { | 29 | public static void main(String[] args) { |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/aop/DatasourceAspect.java+82-0
| @@ -0,0 +1,82 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.aop; | ||
| 6 | + | ||
| 7 | +import java.util.Map; | ||
| 8 | + | ||
| 9 | +import org.aspectj.lang.ProceedingJoinPoint; | ||
| 10 | +import org.aspectj.lang.Signature; | ||
| 11 | +import org.aspectj.lang.annotation.Around; | ||
| 12 | +import org.aspectj.lang.annotation.Aspect; | ||
| 13 | +import org.aspectj.lang.reflect.MethodSignature; | ||
| 14 | +import org.springframework.stereotype.Component; | ||
| 15 | + | ||
| 16 | +import com.nctigba.observability.instance.service.ClusterManager; | ||
| 17 | + | ||
| 18 | +import cn.hutool.core.bean.BeanUtil; | ||
| 19 | +import cn.hutool.core.util.StrUtil; | ||
| 20 | +import lombok.RequiredArgsConstructor; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * aop for switch data source, using nodeId or clusterId | ||
| 24 | + * | ||
| 25 | + * 2023年8月1日 | ||
| 26 | + */ | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +public class DatasourceAspect { | ||
| 31 | + private final ClusterManager clusterManager; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * { } used by this join point | ||
| 35 | + * | ||
| 36 | + * joinPoint point cut object | ||
| 37 | + * target method result | ||
| 38 | + * Throwable target method Throwable | ||
| 39 | + */ | ||
| 40 | + | ||
| 41 | + public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { | ||
| 42 | + var args = joinPoint.getArgs(); | ||
| 43 | + Signature signature = joinPoint.getSignature(); | ||
| 44 | + Class<?> declaringType = signature.getDeclaringType(); | ||
| 45 | + | ||
| 46 | + Ds annotation = declaringType.getMethod(signature.getName(), getParameterTypes(joinPoint)) | ||
| 47 | + .getAnnotation(Ds.class); | ||
| 48 | + int index = annotation.index(); | ||
| 49 | + if (args.length <= index) { | ||
| 50 | + index = args.length - 1; | ||
| 51 | + } | ||
| 52 | + var obj = args[index]; | ||
| 53 | + String path = annotation.value(); | ||
| 54 | + Object nodeId; | ||
| 55 | + if (StrUtil.isNotBlank(path)) { | ||
| 56 | + if (obj instanceof Map) { | ||
| 57 | + nodeId = ((Map<?, ?>) obj).get(path); | ||
| 58 | + } else { | ||
| 59 | + nodeId = BeanUtil.getProperty(obj, path); | ||
| 60 | + } | ||
| 61 | + } else { | ||
| 62 | + nodeId = obj; | ||
| 63 | + } | ||
| 64 | + try { | ||
| 65 | + clusterManager.setCurrentDatasource(nodeId.toString()); | ||
| 66 | + return joinPoint.proceed(); | ||
| 67 | + } finally { | ||
| 68 | + clusterManager.pool(); | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + private Class<?>[] getParameterTypes(ProceedingJoinPoint joinPoint) { | ||
| 73 | + Signature signature = joinPoint.getSignature(); | ||
| 74 | + if (signature instanceof MethodSignature) { | ||
| 75 | + MethodSignature methodSignature = (MethodSignature) signature; | ||
| 76 | + return methodSignature.getMethod().getParameterTypes(); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + // unused for code check | ||
| 80 | + return DatasourceAspect.class.getClasses(); | ||
| 81 | + } | ||
| 82 | +} | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.aop; | ||
| 6 | + | ||
| 7 | +import java.lang.annotation.ElementType; | ||
| 8 | +import java.lang.annotation.Retention; | ||
| 9 | +import java.lang.annotation.RetentionPolicy; | ||
| 10 | +import java.lang.annotation.Target; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * The core Annotation to switch datasource. It can be annotated at method. | ||
| 14 | + * | ||
| 15 | + * 2023年8月1日 | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +public Ds { | ||
| 20 | + /** | ||
| 21 | + * parameter index of nodeId | ||
| 22 | + */ | ||
| 23 | + int index() default 0; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * if parameter is a map or a bean, key name or property | ||
| 27 | + */ | ||
| 28 | + String value() default ""; | ||
| 29 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/config/MybatisPlusConfig.java+1-0
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.config; | 5 | package com.nctigba.observability.instance.config; |
| 5 | 6 | ||
| 6 | import org.springframework.context.annotation.Bean; | 7 | import org.springframework.context.annotation.Bean; |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/DatabaseType.java+0-24
| @@ -1,24 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.constants; | ||
| 5 | - | ||
| 6 | -import lombok.Getter; | ||
| 7 | -import lombok.RequiredArgsConstructor; | ||
| 8 | - | ||
| 9 | - | ||
| 10 | - | ||
| 11 | -public enum DatabaseType { | ||
| 12 | - | ||
| 13 | - DEFAULT("openGauss"), | ||
| 14 | - | ||
| 15 | - OPENGAUSS("openGauss"), | ||
| 16 | - | ||
| 17 | - VASTBASE_G100("vastbase G100"), | ||
| 18 | - | ||
| 19 | - MYSQL("mysql"), | ||
| 20 | - | ||
| 21 | - ORACLE("oracle"); | ||
| 22 | - | ||
| 23 | - private final String dbType; | ||
| 24 | -} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MetricsLine.java+45-9
| @@ -11,7 +11,7 @@ import lombok.Getter; | |||
| 11 | 11 | ||
| 12 | public enum MetricsLine { | 12 | public enum MetricsLine { |
| 13 | // index | 13 | // index |
| 14 | - CPU(Type.OS, "(avg(sum(irate(agent_cpu_seconds_total{mode!='idle',host='ogbrench'}[5m]))by (cpu))) * 100"), | 14 | + CPU(Type.OS, "(avg(sum(irate(agent_cpu_seconds_total{mode!='idle',host='ogbrench'}[5m]))by (cpu,instance))) * 100"), |
| 15 | MEMORY(Type.OS, | 15 | MEMORY(Type.OS, |
| 16 | "(1 - (agent_memory_MemAvailable_bytes{host='ogbrench'} /" | 16 | "(1 - (agent_memory_MemAvailable_bytes{host='ogbrench'} /" |
| 17 | + " (agent_memory_MemTotal_bytes{host='ogbrench'}))) * 100"), | 17 | + " (agent_memory_MemTotal_bytes{host='ogbrench'}))) * 100"), |
| @@ -23,16 +23,39 @@ public enum MetricsLine { | |||
| 23 | DB_ACTIVE_SESSION(Type.DB, "gauss_thread_wait_status_count{instanceId='ogbrench'}", "{wait_status}"), | 23 | DB_ACTIVE_SESSION(Type.DB, "gauss_thread_wait_status_count{instanceId='ogbrench'}", "{wait_status}"), |
| 24 | 24 | ||
| 25 | // CPU | 25 | // CPU |
| 26 | - CPU_TOTAL(Type.OS, "(avg(sum(irate(agent_cpu_seconds_total{mode!='idle',host='ogbrench'}[5m]))by (cpu))) * 100"), | 26 | + CPU_TOTAL(Type.OS, |
| 27 | - CPU_USER(Type.OS, "(avg(sum(irate(agent_cpu_seconds_total{mode='user',host='ogbrench'}[5m]))by (cpu))) * 100"), | 27 | + "clamp_max((avg(sum(irate(agent_cpu_seconds_total" |
| 28 | - CPU_SYSTEM(Type.OS, "(avg(sum(irate(agent_cpu_seconds_total{mode='system',host='ogbrench'}[5m]))by (cpu))) * 100"), | 28 | + + "{mode!='idle',host='ogbrench'}[5m]))by (instance,cpu))by (instance)) * 100, 100)"), |
| 29 | - CPU_IOWAIT(Type.OS, "(avg(sum(irate(agent_cpu_seconds_total{mode='iowait',host='ogbrench'}[5m]))by (cpu))) * 100"), | 29 | + CPU_USER(Type.OS, |
| 30 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='user',host='ogbrench'}[5m]))" | ||
| 31 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 32 | + CPU_SYSTEM(Type.OS, | ||
| 33 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='system',host='ogbrench'}[5m]))" | ||
| 34 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 35 | + CPU_IOWAIT(Type.OS, | ||
| 36 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='iowait',host='ogbrench'}[5m]))" | ||
| 37 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 38 | + CPU_IRQ(Type.OS, | ||
| 39 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='irq',host='ogbrench'}[5m]))" | ||
| 40 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 41 | + CPU_SOFTIRQ(Type.OS, | ||
| 42 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='softirq',host='ogbrench'}[5m]))" | ||
| 43 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 44 | + CPU_NICE(Type.OS, | ||
| 45 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='nice',host='ogbrench'}[5m]))" | ||
| 46 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 47 | + CPU_STEAL(Type.OS, | ||
| 48 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='steal',host='ogbrench'}[5m]))" | ||
| 49 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 50 | + CPU_IDLE(Type.OS, | ||
| 51 | + "(avg(sum(irate(agent_cpu_seconds_total{mode='idle',host='ogbrench'}[5m]))" | ||
| 52 | + + "by (instance,cpu))by (instance)) * 100"), | ||
| 30 | CPU_DB(Type.DB, "top_db_cpu{instanceId='ogbrench'}"), | 53 | CPU_DB(Type.DB, "top_db_cpu{instanceId='ogbrench'}"), |
| 31 | 54 | ||
| 32 | - CPU_TOTAL_5M_LOAD(Type.OS, "sum(agent_load5{host='ogbrench'})"), | 55 | + CPU_TOTAL_5M_LOAD(Type.OS, "sum(agent_load5{host='ogbrench'})by (instance)"), |
| 33 | - CPU_TOTAL_CORE_NUM(Type.OS, "count(agent_cpu_seconds_total{mode='system',host='ogbrench'}) by (host)"), | 56 | + CPU_TOTAL_CORE_NUM(Type.OS, "count(agent_cpu_seconds_total{mode='system',host='ogbrench'}) by (host,instance)"), |
| 34 | CPU_TOTAL_AVERAGE_UTILIZATION(Type.OS, | 57 | CPU_TOTAL_AVERAGE_UTILIZATION(Type.OS, |
| 35 | - "avg(rate(agent_cpu_seconds_total{mode!='idle',host='ogbrench'}[5m])) by (host) * 100"), | 58 | + "avg(rate(agent_cpu_seconds_total{mode!='idle',host='ogbrench'}[5m])) by (host,instance) * 100"), |
| 36 | CPU_TIME(Type.OS, "increase(gauss_instance_time_value{host='ogbrench',stat_name='CPU_TIME'}[5m])"), | 59 | CPU_TIME(Type.OS, "increase(gauss_instance_time_value{host='ogbrench',stat_name='CPU_TIME'}[5m])"), |
| 37 | NET_SEND_TIME(Type.OS, "increase(gauss_instance_time_value{host='ogbrench',stat_name='NET_SEND_TIME'}[5m])"), | 60 | NET_SEND_TIME(Type.OS, "increase(gauss_instance_time_value{host='ogbrench',stat_name='NET_SEND_TIME'}[5m])"), |
| 38 | DATA_IO_TIME(Type.OS, "increase(gauss_instance_time_value{host='ogbrench',stat_name='DATA_IO_TIME'}[5m])"), | 61 | DATA_IO_TIME(Type.OS, "increase(gauss_instance_time_value{host='ogbrench',stat_name='DATA_IO_TIME'}[5m])"), |
| @@ -47,6 +70,7 @@ public enum MetricsLine { | |||
| 47 | 70 | ||
| 48 | // IO | 71 | // IO |
| 49 | IOPS_R(Type.OS, "sum(rate(agent_disk_rd_ios_total{host='ogbrench'}[5m]))by(device)", "{device}"), | 72 | IOPS_R(Type.OS, "sum(rate(agent_disk_rd_ios_total{host='ogbrench'}[5m]))by(device)", "{device}"), |
| 73 | + IOPS_R_TOTAL(Type.OS, "sum(rate(agent_disk_rd_ios_total{host='ogbrench'}[5m]))"), | ||
| 50 | IOPS_W(Type.OS, "sum(rate(agent_disk_wr_ios_total{host='ogbrench'}[5m]))by(device)", "{device}"), | 74 | IOPS_W(Type.OS, "sum(rate(agent_disk_wr_ios_total{host='ogbrench'}[5m]))by(device)", "{device}"), |
| 51 | IO_DISK_READ_BYTES_PER_SECOND(Type.OS, "sum(rate(agent_disk_rd_sectors_total{host='ogbrench'}[5m]))by(device) *512", | 75 | IO_DISK_READ_BYTES_PER_SECOND(Type.OS, "sum(rate(agent_disk_rd_sectors_total{host='ogbrench'}[5m]))by(device) *512", |
| 52 | "{device}"), | 76 | "{device}"), |
| @@ -99,6 +123,10 @@ public enum MetricsLine { | |||
| 99 | INSTANCE_DB_CONNECTION_TOTAL(Type.DB, "pg_connections_max_conn{instanceId='ogbrench'}"), | 123 | INSTANCE_DB_CONNECTION_TOTAL(Type.DB, "pg_connections_max_conn{instanceId='ogbrench'}"), |
| 100 | 124 | ||
| 101 | INSTANCE_DB_SLOWSQL(Type.DB, "pg_stat_activity_slow_count{instanceId='ogbrench',state!='idle'}"), | 125 | INSTANCE_DB_SLOWSQL(Type.DB, "pg_stat_activity_slow_count{instanceId='ogbrench',state!='idle'}"), |
| 126 | + INSTANCE_DB_RESPONSETIME_P80(Type.DB, "gauss_statement_responsetime_percentile_p80{instanceId=" | ||
| 127 | + + "'ogbrench'}"), | ||
| 128 | + INSTANCE_DB_RESPONSETIME_P95(Type.DB, "gauss_statement_responsetime_percentile_p95{instanceId=" | ||
| 129 | + + "'ogbrench'}"), | ||
| 102 | 130 | ||
| 103 | // opengauss session | 131 | // opengauss session |
| 104 | SESSION_MAX_CONNECTION(Type.DB, "pg_connections_max_conn{instanceId='ogbrench'}"), | 132 | SESSION_MAX_CONNECTION(Type.DB, "pg_connections_max_conn{instanceId='ogbrench'}"), |
| @@ -107,7 +135,15 @@ public enum MetricsLine { | |||
| 107 | SESSION_WAITING_CONNECTION(Type.DB, "pg_state_activity_group_count{state='waiting',instanceId='ogbrench'}"), | 135 | SESSION_WAITING_CONNECTION(Type.DB, "pg_state_activity_group_count{state='waiting',instanceId='ogbrench'}"), |
| 108 | 136 | ||
| 109 | // wait event !pg_wait_events_total_wait_time | 137 | // wait event !pg_wait_events_total_wait_time |
| 110 | - WAIT_EVENT_COUNT(Type.DB, "gauss_wait_events_value{instanceId='ogbrench'}", "{type}"); | 138 | + WAIT_EVENT_COUNT(Type.DB, "gauss_wait_events_value{instanceId='ogbrench'}", "{type}"), |
| 139 | + | ||
| 140 | + // cluster | ||
| 141 | + CLUSTER_PRIMARY_WAL_WRITE_TOTAL(Type.DB, "increase(pg_wal_write_total_count{instanceId='ogbrench'}[1d])"), | ||
| 142 | + CLUSTER_PRIMARY_WAL_SEND_PRESSURE(Type.DB, "pg_wal_send_pressure_count{instanceId='ogbrench'}"), | ||
| 143 | + CLUSTER_PRIMARY_WAL_WRITE_PER_SEC(Type.DB, "rate(pg_wal_write_total_count{instanceId='ogbrench'}[2m])"), | ||
| 144 | + CLUSTER_WAL_RECEIVED_DELAY(Type.DB, "pg_wal_delay_received{instanceId='ogbrench'}"), | ||
| 145 | + CLUSTER_WAL_WRITE_DELAY(Type.DB, "pg_wal_delay_write{instanceId='ogbrench'}"), | ||
| 146 | + CLUSTER_WAL_REPLAY_DELAY(Type.DB, "pg_wal_delay_replay{instanceId='ogbrench'}"); | ||
| 111 | 147 | ||
| 112 | private enum Type { | 148 | private enum Type { |
| 113 | OS, | 149 | OS, |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MonitoringConstants.java+0-12
| @@ -1,12 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.constants; | ||
| 5 | - | ||
| 6 | -public class MonitoringConstants { | ||
| 7 | - // prometheus query ?query={query} | ||
| 8 | - public static final String PROMETHEUS_QUERY_POINT = "/api/v1/query"; | ||
| 9 | - | ||
| 10 | - // prometheus range query ?query={query}&start={start}&end={end}&step={step} | ||
| 11 | - public static final String PROMETHEUS_QUERY_RANGE = "/api/v1/query_range"; | ||
| 12 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MonitoringResultType.java+0-24
| @@ -1,24 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.constants; | ||
| 5 | - | ||
| 6 | -import lombok.Getter; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * Monitoring data return type | ||
| 10 | - * | ||
| 11 | - * yangjie | ||
| 12 | - */ | ||
| 13 | - | ||
| 14 | -public enum MonitoringResultType { | ||
| 15 | - /** | ||
| 16 | - * table | ||
| 17 | - */ | ||
| 18 | - TABLE, | ||
| 19 | - | ||
| 20 | - /** | ||
| 21 | - * line | ||
| 22 | - */ | ||
| 23 | - LINE, | ||
| 24 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MonitoringType.java+0-16
| @@ -1,16 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.constants; | ||
| 5 | - | ||
| 6 | -import lombok.Getter; | ||
| 7 | -import lombok.RequiredArgsConstructor; | ||
| 8 | - | ||
| 9 | - | ||
| 10 | - | ||
| 11 | -public enum MonitoringType { | ||
| 12 | - | ||
| 13 | - DEFAULT("prometheus"); | ||
| 14 | - | ||
| 15 | - private final String monitoringType; | ||
| 16 | -} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/StateColor.java+55-0
| @@ -0,0 +1,55 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.constants; | ||
| 6 | + | ||
| 7 | +import java.util.Arrays; | ||
| 8 | +import java.util.Set; | ||
| 9 | +import java.util.stream.Collectors; | ||
| 10 | + | ||
| 11 | +import lombok.Getter; | ||
| 12 | +import lombok.RequiredArgsConstructor; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * | ||
| 16 | + * StateColor.java | ||
| 17 | + * | ||
| 18 | + * 2023-08-25 | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +public enum StateColor { | ||
| 23 | + GREEN("cluster.state.value.Normal", "cluster.node.state.Normal", "cluster.node.syncState.Streaming", | ||
| 24 | + "OS.bin.state.TASK_RUNNING"), | ||
| 25 | + YELLOW("cluster.state.value.Degraded", "cluster.node.state.Need repair", "cluster.node.state.Starting", | ||
| 26 | + "cluster.node.state.Wait promoting", "cluster.node.state.Promoting", "cluster.node.state.Demoting", | ||
| 27 | + "cluster.node.state.Building", "cluster.node.state.Catchup", "cluster.node.state.Coredump", | ||
| 28 | + "cluster.node.syncState.Catchup", "OS.bin.state.TASK_INTERRUPTIBLE", "OS.bin.state.TASK_STOPPED", | ||
| 29 | + "OS.bin.state.TASK_TRACED", "OS.bin.state.TASK_UNINTERRUPTIBLE"), | ||
| 30 | + RED("cluster.state.value.Unavailable", "cluster.node.state.Unknown", "OS.bin.state.EXIT_ZOMBIE", | ||
| 31 | + "OS.bin.state.EXIT_DEAD", "OS.bin.state.STOP"), | ||
| 32 | + GREY("cluster.state.value.Unknown", "OS.bin.state.UNKNOWN"); | ||
| 33 | + | ||
| 34 | + private String[] state; | ||
| 35 | + | ||
| 36 | + StateColor(String... states) { | ||
| 37 | + this.state = states; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * getColor | ||
| 42 | + * | ||
| 43 | + * state state | ||
| 44 | + * color | ||
| 45 | + */ | ||
| 46 | + public static StateColor getColor(String state) { | ||
| 47 | + for (StateColor color : StateColor.values()) { | ||
| 48 | + Set<String> states = Arrays.stream(color.state).collect(Collectors.toSet()); | ||
| 49 | + if (states.contains(state)) { | ||
| 50 | + return color; | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + return GREY; | ||
| 54 | + } | ||
| 55 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/AspController.java+49-0
| @@ -0,0 +1,49 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.controller; | ||
| 6 | + | ||
| 7 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 8 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 9 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 10 | +import org.springframework.web.bind.annotation.RestController; | ||
| 11 | + | ||
| 12 | +import com.nctigba.observability.instance.dto.asp.AspCountReq; | ||
| 13 | +import com.nctigba.observability.instance.service.AspService; | ||
| 14 | + | ||
| 15 | +import lombok.RequiredArgsConstructor; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * AspController.java | ||
| 19 | + * | ||
| 20 | + * 2023-08-25 | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class AspController extends ControllerConfig { | ||
| 26 | + private final AspService aspService; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * list | ||
| 30 | + * | ||
| 31 | + * req req | ||
| 32 | + * AjaxResult | ||
| 33 | + */ | ||
| 34 | + | ||
| 35 | + public AjaxResult list(AspCountReq req) { | ||
| 36 | + return AjaxResult.success(aspService.count(req)); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * analysis | ||
| 41 | + * | ||
| 42 | + * req req | ||
| 43 | + * AjaxResult | ||
| 44 | + */ | ||
| 45 | + | ||
| 46 | + public AjaxResult analysis(AspCountReq req) { | ||
| 47 | + return AjaxResult.success(aspService.analysis(req)); | ||
| 48 | + } | ||
| 49 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ClusterOpsController.java+93-0
| @@ -0,0 +1,93 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.controller; | ||
| 6 | + | ||
| 7 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 8 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 9 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 10 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 11 | +import org.springframework.web.bind.annotation.RestController; | ||
| 12 | + | ||
| 13 | +import com.nctigba.observability.instance.service.ClusterOpsService; | ||
| 14 | + | ||
| 15 | +import lombok.RequiredArgsConstructor; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * ClusterOpsController.java | ||
| 19 | + * | ||
| 20 | + * 2023-08-25 | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class ClusterOpsController { | ||
| 26 | + private final ClusterOpsService clusterOpsService; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * list | ||
| 30 | + * | ||
| 31 | + * AjaxResult | ||
| 32 | + */ | ||
| 33 | + | ||
| 34 | + public AjaxResult list() { | ||
| 35 | + return AjaxResult.success(clusterOpsService.listClusters()); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * nodes | ||
| 40 | + * | ||
| 41 | + * clusterId clusterId | ||
| 42 | + * AjaxResult | ||
| 43 | + */ | ||
| 44 | + | ||
| 45 | + public AjaxResult nodes( String clusterId) { | ||
| 46 | + return AjaxResult.success(clusterOpsService.nodes(clusterId)); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * relation | ||
| 51 | + * | ||
| 52 | + * clusterId clusterId | ||
| 53 | + * AjaxResult | ||
| 54 | + */ | ||
| 55 | + | ||
| 56 | + public AjaxResult relation( String clusterId) { | ||
| 57 | + return AjaxResult.success(clusterOpsService.relation(clusterId)); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * allClusterState | ||
| 62 | + * | ||
| 63 | + * AjaxResult | ||
| 64 | + */ | ||
| 65 | + | ||
| 66 | + public AjaxResult allClusterState() { | ||
| 67 | + return AjaxResult.success(clusterOpsService.allClusterState()); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * allStandbyNodes | ||
| 72 | + * | ||
| 73 | + * AjaxResult | ||
| 74 | + */ | ||
| 75 | + | ||
| 76 | + public AjaxResult allStandbyNodes() { | ||
| 77 | + return AjaxResult.success(clusterOpsService.allStandbyNodes()); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * clusterMetrics | ||
| 82 | + * | ||
| 83 | + * clusterId clusterId | ||
| 84 | + * start start | ||
| 85 | + * end end | ||
| 86 | + * step step | ||
| 87 | + * AjaxResult | ||
| 88 | + */ | ||
| 89 | + | ||
| 90 | + public AjaxResult clusterMetrics( String clusterId, Long start, Long end, Integer step) { | ||
| 91 | + return AjaxResult.success(clusterOpsService.clusterMetrics(clusterId, start, end, step)); | ||
| 92 | + } | ||
| 93 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ControllerConfig.java+19-15
| @@ -1,29 +1,33 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | -package com.nctigba.observability.instance.controller; | ||
| 5 | 4 | ||
| 6 | -import org.springframework.beans.propertyeditors.CustomDateEditor; | 5 | +package com.nctigba.observability.instance.controller; |
| 7 | -import org.springframework.web.bind.WebDataBinder; | ||
| 8 | -import org.springframework.web.bind.annotation.InitBinder; | ||
| 9 | 6 | ||
| 10 | import java.text.ParsePosition; | 7 | import java.text.ParsePosition; |
| 11 | import java.text.SimpleDateFormat; | 8 | import java.text.SimpleDateFormat; |
| 12 | import java.util.Date; | 9 | import java.util.Date; |
| 13 | 10 | ||
| 14 | -public class ControllerConfig { | 11 | +import org.springframework.beans.propertyeditors.CustomDateEditor; |
| 12 | +import org.springframework.web.bind.WebDataBinder; | ||
| 13 | +import org.springframework.web.bind.annotation.InitBinder; | ||
| 14 | + | ||
| 15 | +import cn.hutool.core.util.StrUtil; | ||
| 16 | + | ||
| 17 | +public abstract class ControllerConfig { | ||
| 15 | 18 | ||
| 16 | public void initBinder(WebDataBinder webDataBinder) { | 19 | public void initBinder(WebDataBinder webDataBinder) { |
| 17 | - webDataBinder.registerCustomEditor(Date.class, | 20 | + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") { |
| 18 | - new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") { | 21 | + private static final long serialVersionUID = 1L; |
| 19 | - private static final long serialVersionUID = 1L; | ||
| 20 | 22 | ||
| 21 | - @Override | 23 | + @Override |
| 22 | - public Date parse(String text, ParsePosition pos) { | 24 | + public Date parse(String text, ParsePosition pos) { |
| 23 | - if (org.apache.commons.lang3.StringUtils.isBlank(text)) | 25 | + if (StrUtil.isBlank(text)) |
| 24 | - return null; | 26 | + return null; |
| 25 | - return super.parse(text, pos); | 27 | + return super.parse(text, pos); |
| 26 | - } | 28 | + } |
| 27 | - }, true)); | 29 | + }; |
| 30 | + dateFormat.setTimeZone(java.util.TimeZone.getTimeZone(java.time.ZoneOffset.UTC)); | ||
| 31 | + webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); | ||
| 28 | } | 32 | } |
| 29 | } | 33 | } |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/IndexController.java+100-15
| @@ -1,33 +1,65 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.controller; | 5 | package com.nctigba.observability.instance.controller; |
| 5 | 6 | ||
| 7 | +import java.io.IOException; | ||
| 6 | import java.util.HashMap; | 8 | import java.util.HashMap; |
| 7 | -import java.util.List; | ||
| 8 | import java.util.Map; | 9 | import java.util.Map; |
| 9 | 10 | ||
| 10 | import org.opengauss.admin.common.core.domain.AjaxResult; | 11 | import org.opengauss.admin.common.core.domain.AjaxResult; |
| 12 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 13 | +import org.opengauss.admin.common.exception.CustomException; | ||
| 14 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 15 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 16 | +import org.opengauss.admin.system.service.ops.IOpsClusterService; | ||
| 17 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 18 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 11 | import org.springframework.web.bind.annotation.GetMapping; | 19 | import org.springframework.web.bind.annotation.GetMapping; |
| 12 | import org.springframework.web.bind.annotation.RequestMapping; | 20 | import org.springframework.web.bind.annotation.RequestMapping; |
| 13 | import org.springframework.web.bind.annotation.RestController; | 21 | import org.springframework.web.bind.annotation.RestController; |
| 14 | 22 | ||
| 15 | -import com.alibaba.fastjson.JSONObject; | 23 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; |
| 24 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType.Type; | ||
| 25 | +import com.nctigba.observability.instance.aop.Ds; | ||
| 16 | import com.nctigba.observability.instance.constants.MetricsLine; | 26 | import com.nctigba.observability.instance.constants.MetricsLine; |
| 17 | -import com.nctigba.observability.instance.dto.topsql.TopSQLNowReq; | 27 | +import com.nctigba.observability.instance.mapper.DbConfigMapper; |
| 28 | +import com.nctigba.observability.instance.service.ClusterManager; | ||
| 18 | import com.nctigba.observability.instance.service.MetricsService; | 29 | import com.nctigba.observability.instance.service.MetricsService; |
| 19 | import com.nctigba.observability.instance.service.SessionService; | 30 | import com.nctigba.observability.instance.service.SessionService; |
| 20 | import com.nctigba.observability.instance.service.TopSQLService; | 31 | import com.nctigba.observability.instance.service.TopSQLService; |
| 32 | +import com.nctigba.observability.instance.util.SshSession; | ||
| 21 | 33 | ||
| 22 | -import lombok.RequiredArgsConstructor; | 34 | +import cn.hutool.core.util.StrUtil; |
| 35 | +import lombok.extern.log4j.Log4j2; | ||
| 23 | 36 | ||
| 24 | 37 | ||
| 25 | 38 | ||
| 26 | -@RequiredArgsConstructor | 39 | +@Log4j2 |
| 27 | public class IndexController extends ControllerConfig { | 40 | public class IndexController extends ControllerConfig { |
| 28 | - private final MetricsService metricsService; | 41 | + @Autowired |
| 29 | - private final TopSQLService topSQLService; | 42 | + private MetricsService metricsService; |
| 30 | - private final SessionService sessionService; | 43 | + @Autowired |
| 44 | + private TopSQLService topSQLService; | ||
| 45 | + | ||
| 46 | + private SessionService sessionService; | ||
| 47 | + | ||
| 48 | + private ClusterManager clusterManager; | ||
| 49 | + | ||
| 50 | + private DbConfigMapper configMapper; | ||
| 51 | + | ||
| 52 | + | ||
| 53 | + private IOpsClusterService opsClusterService; | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + private HostFacade hostFacade; | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + private HostUserFacade hostUserFacade; | ||
| 60 | + | ||
| 61 | + | ||
| 62 | + private EncryptionUtils encryptionUtils; | ||
| 31 | 63 | ||
| 32 | private static final MetricsLine[] MAIN = { | 64 | private static final MetricsLine[] MAIN = { |
| 33 | MetricsLine.CPU, | 65 | MetricsLine.CPU, |
| @@ -40,19 +72,72 @@ public class IndexController extends ControllerConfig { | |||
| 40 | MetricsLine.DB_ACTIVE_SESSION | 72 | MetricsLine.DB_ACTIVE_SESSION |
| 41 | }; | 73 | }; |
| 42 | 74 | ||
| 75 | + /** | ||
| 76 | + * nodeInfo | ||
| 77 | + * | ||
| 78 | + * id id | ||
| 79 | + * AjaxResult | ||
| 80 | + */ | ||
| 81 | + | ||
| 82 | + | ||
| 83 | + public AjaxResult nodeInfo(String id) { | ||
| 84 | + Map<String, Object> result = new HashMap<>(); | ||
| 85 | + // cluster info | ||
| 86 | + var node = clusterManager.getOpsNodeById(id); | ||
| 87 | + result.put("version", configMapper.version()); | ||
| 88 | + result.put("time", configMapper.starttime()); | ||
| 89 | + var env = configMapper.env(); | ||
| 90 | + result.put("dbDataPath", env.get("datapath")); | ||
| 91 | + result.put("dbLogPath", env.get("datapath") + StrUtil.SLASH + env.get("log_directory")); | ||
| 92 | + result.put("archiveMode", configMapper.archiveMode()); | ||
| 93 | + OpsHostEntity hostEntity = hostFacade.getById(node.getHostId()); | ||
| 94 | + var user = hostUserFacade.listHostUserByHostId(hostEntity.getHostId()).stream().filter(e -> { | ||
| 95 | + return node.getInstallUserName().equals(e.getUsername()); | ||
| 96 | + }).findFirst().orElse(null); | ||
| 97 | + try (var session = SshSession.connect(hostEntity.getPublicIp(), hostEntity.getPort(), node.getInstallUserName(), | ||
| 98 | + encryptionUtils.decrypt(user.getPassword()));) { | ||
| 99 | + result.put("osVersion", session.execute("cat /etc/system-release")); | ||
| 100 | + result.put("CPUmanufacturer", session.execute("cat /proc/cpuinfo | grep 'vendor_id' | head -n 1 | " | ||
| 101 | + + "awk -F: '{print $2}' | sed 's/^[ \\t]*//'")); | ||
| 102 | + result.put("CPUmodel", session.execute("cat /proc/cpuinfo | grep 'model name' | head -n 1 | " | ||
| 103 | + + "awk -F: '{print $2}' | sed 's/^[ \\t]*//'")); | ||
| 104 | + result.put("CPUcores", session.execute("nproc")); | ||
| 105 | + result.put("TotalMemory", session.execute("free -h | awk '/^Mem:/ {print $2}'")); | ||
| 106 | + } catch (IOException | CustomException e) { | ||
| 107 | + log.error("", e); | ||
| 108 | + } | ||
| 109 | + return AjaxResult.success(result); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + /** | ||
| 113 | + * mainMetrics | ||
| 114 | + * | ||
| 115 | + * id id | ||
| 116 | + * start start | ||
| 117 | + * end end | ||
| 118 | + * step step | ||
| 119 | + * AjaxResult | ||
| 120 | + */ | ||
| 43 | 121 | ||
| 44 | public AjaxResult mainMetrics(String id, Long start, Long end, Integer step) { | 122 | public AjaxResult mainMetrics(String id, Long start, Long end, Integer step) { |
| 45 | - HashMap<String, Object> metrics = metricsService.listBatch(MAIN, id, start, end, step); | 123 | + Map<String, Object> metrics = metricsService.listBatch(MAIN, id, start, end, step); |
| 46 | - JSONObject simpleStatistic = sessionService.simpleStatistic(id); | 124 | + var simpleStatistic = sessionService.simpleStatistic(id); |
| 47 | metrics.putAll(simpleStatistic); | 125 | metrics.putAll(simpleStatistic); |
| 48 | return AjaxResult.success(metrics); | 126 | return AjaxResult.success(metrics); |
| 49 | } | 127 | } |
| 50 | 128 | ||
| 51 | - @GetMapping(value = "/topSQLNow") | 129 | + /** |
| 52 | - public AjaxResult topSQLNow(TopSQLNowReq topSQLNowReq) { | 130 | + * topSQLNow |
| 53 | - Map<String, List<JSONObject>> blockAndLongTxc = sessionService.blockAndLongTxc(topSQLNowReq.getId()); | 131 | + * |
| 54 | - List<JSONObject> topSQLNow = topSQLService.getTopSQLNow(topSQLNowReq); | 132 | + * @param id id |
| 55 | - blockAndLongTxc.put("topSQLNow", topSQLNow); | 133 | + * @return AjaxResult |
| 134 | + */ | ||
| 135 | + | ||
| 136 | + | ||
| 137 | + public AjaxResult topSQLNow(String id) { | ||
| 138 | + var blockAndLongTxc = sessionService.blockAndLongTxc(id); | ||
| 139 | + blockAndLongTxc.put("topSQLNow", topSQLService.topSQLNow(id)); | ||
| 140 | + blockAndLongTxc.put("waitEvents", configMapper.waitEvents()); | ||
| 56 | return AjaxResult.success(blockAndLongTxc); | 141 | return AjaxResult.success(blockAndLongTxc); |
| 57 | } | 142 | } |
| 58 | } | 143 | } |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/MonitoringController.java+0-212
| @@ -1,212 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.controller; | ||
| 5 | - | ||
| 6 | -import java.util.Arrays; | ||
| 7 | -import java.util.HashMap; | ||
| 8 | -import java.util.List; | ||
| 9 | -import java.util.Map; | ||
| 10 | -import java.util.concurrent.ArrayBlockingQueue; | ||
| 11 | -import java.util.concurrent.CountDownLatch; | ||
| 12 | -import java.util.concurrent.ThreadPoolExecutor; | ||
| 13 | -import java.util.concurrent.TimeUnit; | ||
| 14 | - | ||
| 15 | -import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 16 | -import org.opengauss.admin.common.exception.CustomException; | ||
| 17 | -import org.springframework.web.bind.annotation.GetMapping; | ||
| 18 | -import org.springframework.web.bind.annotation.PostMapping; | ||
| 19 | -import org.springframework.web.bind.annotation.RequestBody; | ||
| 20 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 21 | -import org.springframework.web.bind.annotation.RestController; | ||
| 22 | - | ||
| 23 | -import com.nctigba.observability.instance.model.monitoring.MonitoringParam; | ||
| 24 | -import com.nctigba.observability.instance.service.MonitoringService; | ||
| 25 | - | ||
| 26 | -import lombok.RequiredArgsConstructor; | ||
| 27 | - | ||
| 28 | -/** | ||
| 29 | - * Monitoring data | ||
| 30 | - * | ||
| 31 | - * zhanggr.com.cn | ||
| 32 | - * 2022/9/5 17:04 | ||
| 33 | - */ | ||
| 34 | - | ||
| 35 | - | ||
| 36 | - | ||
| 37 | -public class MonitoringController { | ||
| 38 | - private final MonitoringService monitoringService; | ||
| 39 | - private final ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS, | ||
| 40 | - new ArrayBlockingQueue<>(100)); | ||
| 41 | - | ||
| 42 | - private static final List<String> names = Arrays.asList("cpu", "memory", "disk_read", "disk_written", | ||
| 43 | - "network_transmit", "network_receive", "load5", "run_time", "mem", "cpu_cnt", "uname", "os"); | ||
| 44 | - private static final List<String> metrics = Arrays.asList( | ||
| 45 | - "(avg(sum(irate(node_cpu_seconds_total{mode!=\"idle\",instance=\"ogbrench\"}[5m]))by (cpu))) * 100", | ||
| 46 | - "(1 - (node_memory_MemAvailable_bytes{instance=\"ogbrench\"} / (node_memory_MemTotal_bytes{instance=\"ogbrench\"}))) * 100", | ||
| 47 | - "max(rate(node_disk_read_bytes_total{instance=\"ogbrench\"}[5m])) by (instance)", | ||
| 48 | - "max(rate(node_disk_written_bytes_total{instance=\"ogbrench\"}[5m])) by (instance)", | ||
| 49 | - "max(rate(node_network_transmit_bytes_total{instance=\"ogbrench\"}[5m])*8) by (instance)", | ||
| 50 | - "max(rate(node_network_receive_bytes_total{instance=\"ogbrench\"}[5m])*8) by (instance)", | ||
| 51 | - "node_load5{instance=\"ogbrench\"}", | ||
| 52 | - "sum(time() - node_boot_time_seconds{instance=\"ogbrench\"})by(instance)", | ||
| 53 | - "node_memory_MemTotal_bytes{instance=\"ogbrench\"}", | ||
| 54 | - "count(node_cpu_seconds_total{mode='system',instance=\"ogbrench\"}) by (instance)", | ||
| 55 | - "node_uname_info{instance=\"ogbrench\"}", "node_os_info{instance=\"ogbrench\"}", | ||
| 56 | - "sum(avg(node_filesystem_size_bytes{fstype=~\"xfs|ext.*\",instance=\"ogbrench\"})by(device,instance))"); | ||
| 57 | - private static final List<String> databaseNames = Arrays.asList("CPU_TIME", "NET_SEND_TIME", "DATA_IO_TIME", | ||
| 58 | - "gauss_wait_events_value", "totalCoreNum", "total5mLoad", "totalAverageUtilization1", "diskIOUsage", | ||
| 59 | - "systemUsage", "userUsage", "totalUsage", "totalMemory", "usedMemory", "totalAverageUtilization2", | ||
| 60 | - "totalDisks", "totalNumber", "totalAverageUtilization3", "read1", "write1", "read2", "write2", "upload", | ||
| 61 | - "download", "TCP_alloc", "CurrEstab", "Tcp_OutSegs", "Tcp_InSegs", "UDP_inuse", "TCP_tw", "Tcp_RetransSegs", | ||
| 62 | - "Sockets_used", "transactionRollbackNum", "transactionCommitments", "transactionAndRollbackTotal", | ||
| 63 | - "queryTransactions", "currentIdleConnections", "currentActiveConnections", "currentConnections", | ||
| 64 | - "totalConnections", "slowSqlNum", "longTransactions", "sqlResponseTime80", "sqlResponseTime95", | ||
| 65 | - "accessExclusiveLock", "accessShareLock", "ExclusiveLock", "ShareUpdateExclusiveLock", | ||
| 66 | - "ShareRowExclusiveLock", "RowShareLock", "RowExclusiveLock", "ShareLock", "queryCacheHitRate", | ||
| 67 | - "databaseCacheHitRate", "readPhysicalFileBlockNum", "writePhysicalFileBlockNum", "lastBatchDirtyPageNum", | ||
| 68 | - "currentRemainingDirtyPages"); | ||
| 69 | - private static final List<String> databaseMetrics = Arrays.asList( | ||
| 70 | - "increase(gauss_instance_time_value{instance='ogbrench',stat_name='CPU_TIME'}[5m])", | ||
| 71 | - "increase(gauss_instance_time_value{instance='ogbrench',stat_name='NET_SEND_TIME'}[5m])", | ||
| 72 | - "increase(gauss_instance_time_value{instance='ogbrench',stat_name='DATA_IO_TIME'}[5m])", | ||
| 73 | - "gauss_wait_events_value{instance='ogbrench'}", | ||
| 74 | - "count(node_cpu_seconds_total{mode='system',instance='ogbrench'}) by (instance)", | ||
| 75 | - "sum(node_load5{instance='ogbrench'})", | ||
| 76 | - "avg(rate(node_cpu_seconds_total{mode!='idle',instance='ogbrench'}[5m])) by (instance) * 100", | ||
| 77 | - "(avg(sum(irate(node_cpu_seconds_total{mode='iowait',instance='ogbrench'}[5m]))by (cpu))) * 100", | ||
| 78 | - "(avg(sum(irate(node_cpu_seconds_total{mode='system',instance='ogbrench'}[5m]))by (cpu))) * 100", | ||
| 79 | - "(avg(sum(irate(node_cpu_seconds_total{mode='user',instance='ogbrench'}[5m]))by (cpu))) * 100", | ||
| 80 | - "(avg(sum(irate(node_cpu_seconds_total{mode!='idle',instance='ogbrench'}[5m]))by (cpu))) * 100", | ||
| 81 | - "node_memory_MemTotal_bytes{instance='ogbrench'}", | ||
| 82 | - "node_memory_MemTotal_bytes{instance='ogbrench'} - node_memory_MemAvailable_bytes{instance='ogbrench'}", | ||
| 83 | - "(node_memory_MemTotal_bytes{instance='ogbrench'} - node_memory_MemAvailable_bytes{instance='ogbrench'})/node_memory_MemTotal_bytes{instance='ogbrench'} * 100", | ||
| 84 | - "sum(avg(node_filesystem_size_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance))", | ||
| 85 | - "sum(avg(node_filesystem_size_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance)) - sum(avg(node_filesystem_free_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance))", | ||
| 86 | - "(sum(avg(node_filesystem_size_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance)) - sum(avg(node_filesystem_free_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance))) /(sum(avg(node_filesystem_avail_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance))+(sum(avg(node_filesystem_size_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance)) - sum(avg(node_filesystem_free_bytes{fstype=~'xfs|ext.*',instance='ogbrench'})by(device,instance)))) * 100", | ||
| 87 | - "sum(rate(node_disk_reads_completed_total{instance='ogbrench'}[5m]))", | ||
| 88 | - "sum(rate(node_disk_writes_completed_total{instance='ogbrench'}[5m]))", | ||
| 89 | - "sum(rate(node_disk_read_bytes_total{instance='ogbrench'}[5m]))", | ||
| 90 | - "sum(rate(node_disk_written_bytes_total{instance='ogbrench'}[5m]))", | ||
| 91 | - "sum(rate(node_network_transmit_bytes_total{instance='ogbrench'}[5m])*8)", | ||
| 92 | - "sum(rate(node_network_receive_bytes_total{instance='ogbrench'}[5m])*8)", | ||
| 93 | - "node_sockstat_TCP_alloc{instance='ogbrench'}", "node_netstat_Tcp_CurrEstab{instance='ogbrench'}", | ||
| 94 | - "rate(node_netstat_Tcp_OutSegs{instance='ogbrench'}[5m])", | ||
| 95 | - "rate(node_netstat_Tcp_InSegs{instance='ogbrench'}[5m])", "node_sockstat_UDP_inuse{instance='ogbrench'}", | ||
| 96 | - "node_sockstat_TCP_tw{instance='ogbrench'}", "rate(node_netstat_Tcp_RetransSegs{instance='ogbrench'}[5m])", | ||
| 97 | - "node_sockstat_sockets_used{instance='ogbrench'}", | ||
| 98 | - "sum(irate(pg_stat_database_xact_rollback{instance='ogbrench'}[5m]))", | ||
| 99 | - "sum(irate(pg_stat_database_xact_commit{instance='ogbrench'}[5m]))", | ||
| 100 | - "sum(irate(pg_stat_database_xact_rollback{instance='ogbrench'}[5m])) + sum(irate(pg_stat_database_xact_commit{instance='ogbrench'}[5m]))", | ||
| 101 | - "sum(rate(gauss_workload_sql_count_select_count{instance='ogbrench'}[5m]))", | ||
| 102 | - "sum(pg_stat_activity_count{instance='ogbrench',state='idle'})", | ||
| 103 | - "sum(pg_stat_activity_count{instance='ogbrench',state='active'})", | ||
| 104 | - "sum(pg_stat_activity_count{instance='ogbrench'})", "pg_settings_max_connections{instance='ogbrench'}", | ||
| 105 | - "sum(pg_stat_activity_max_tx_duration{instance='ogbrench',state!='idle'}) > bool 3", | ||
| 106 | - "sum(pg_stat_activity_max_tx_duration{instance='ogbrench',state!='idle'}) > bool 30", | ||
| 107 | - "gauss_statement_responsetime_percentile_p80{instance='ogbrench'}", | ||
| 108 | - "gauss_statement_responsetime_percentile_p95{instance='ogbrench'}", | ||
| 109 | - "sum(pg_lock_count{mode='AccessExclusiveLock',instance='ogbrench'})", | ||
| 110 | - "sum(pg_lock_count{mode='AccessShareLock',instance='ogbrench'})", | ||
| 111 | - "sum(pg_lock_count{mode='ExclusiveLock',instance='ogbrench'})", | ||
| 112 | - "sum(pg_lock_count{mode='ShareUpdateExclusiveLock',instance='ogbrench'})", | ||
| 113 | - "sum(pg_lock_count{mode='ShareRowExclusiveLock',instance='ogbrench'})", | ||
| 114 | - "sum(pg_lock_count{mode='RowShareLock',instance='ogbrench'})", | ||
| 115 | - "sum(pg_lock_count{mode='RowExclusiveLock',instance='ogbrench'})", | ||
| 116 | - "sum(pg_lock_count{mode='ShareLock',instance='ogbrench'})", | ||
| 117 | - "(gauss_query_statement_cache_hit_rate{instance='ogbrench'}) * 100", | ||
| 118 | - "(sum(pg_stat_database_blks_hit{instance='ogbrench'}) / (sum(pg_stat_database_blks_hit{instance='ogbrench'}) + sum(pg_stat_database_blks_read{instance='ogbrench'}))) * 100", | ||
| 119 | - "rate(gauss_summary_file_iostat_total_phyblkrd{instance='ogbrench'}[5m])", | ||
| 120 | - "rate(gauss_summary_file_iostat_total_phyblkwrt{instance='ogbrench'}[5m])", | ||
| 121 | - "sum(gauss_global_pagewriter_status_pgwr_last_flush_num{instance='ogbrench'})", | ||
| 122 | - "sum(gauss_global_pagewriter_status_remain_dirty_page_num{instance='ogbrench'})"); | ||
| 123 | - | ||
| 124 | - | ||
| 125 | - public AjaxResult point( MonitoringParam monitoringParam) { | ||
| 126 | - // The specified time point can only be returned in table data format | ||
| 127 | - return AjaxResult.success(monitoringService.getPointMonitoringData(monitoringParam)); | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - | ||
| 131 | - public AjaxResult range( MonitoringParam monitoringParam) { | ||
| 132 | - return AjaxResult.success(monitoringService.getRangeMonitoringData(monitoringParam)); | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - | ||
| 136 | - public AjaxResult pointMetrics(MonitoringParam monitoringParam) { | ||
| 137 | - Map<String, Object> map = new HashMap<>(); | ||
| 138 | - int i = 0; | ||
| 139 | - for (String metric : metrics) { | ||
| 140 | - if (i > 6) { | ||
| 141 | - break; | ||
| 142 | - } | ||
| 143 | - handlePoint(map, monitoringParam, metric, i++); | ||
| 144 | - } | ||
| 145 | - return AjaxResult.success(map); | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | - | ||
| 149 | - public AjaxResult pointInfo(MonitoringParam monitoringParam) { | ||
| 150 | - Map<String, Object> map = new HashMap<>(); | ||
| 151 | - int i = 0; | ||
| 152 | - for (String metric : metrics) { | ||
| 153 | - if (i < 7) { | ||
| 154 | - i++; | ||
| 155 | - continue; | ||
| 156 | - } | ||
| 157 | - handlePoint(map, monitoringParam, metric, i++); | ||
| 158 | - } | ||
| 159 | - return AjaxResult.success(map); | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - private void handlePoint(Map<String, Object> map, MonitoringParam monitoringParam, String metric, int i) { | ||
| 163 | - monitoringParam.setQuery(metric.replace("ogbrench", monitoringParam.getId())); | ||
| 164 | - Map<String, Object> pointMonitoringData = monitoringService.getPointMonitoringData(monitoringParam); | ||
| 165 | - if (pointMonitoringData.containsKey("value")) { | ||
| 166 | - map.put(names.get(i), pointMonitoringData.get("value")); | ||
| 167 | - } else { | ||
| 168 | - map.putAll(pointMonitoringData); | ||
| 169 | - } | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - public interface MyRunnable extends Runnable { | ||
| 173 | - MyRunnable setName(String name); | ||
| 174 | - } | ||
| 175 | - | ||
| 176 | - | ||
| 177 | - public AjaxResult getDatabaseMetrics(MonitoringParam monitoringParam) { | ||
| 178 | - Map<String, Object> map = new HashMap<>(); | ||
| 179 | - int i = 0; | ||
| 180 | - CountDownLatch countDownLatch = new CountDownLatch(databaseMetrics.size()); | ||
| 181 | - for (String metric : databaseMetrics) { | ||
| 182 | - pool.submit(new MyRunnable() { | ||
| 183 | - String name; | ||
| 184 | - | ||
| 185 | - | ||
| 186 | - public MyRunnable setName(String name) { | ||
| 187 | - this.name = name; | ||
| 188 | - return this; | ||
| 189 | - } | ||
| 190 | - | ||
| 191 | - | ||
| 192 | - public void run() { | ||
| 193 | - try { | ||
| 194 | - monitoringParam.setQuery(metric.replace("ogbrench", monitoringParam.getId())); | ||
| 195 | - if ("gauss_wait_events_value".equals(name)) { | ||
| 196 | - monitoringParam.setLegendName("event"); | ||
| 197 | - } | ||
| 198 | - map.put(name, monitoringService.getRangeMonitoringData(monitoringParam).get(0)); | ||
| 199 | - } finally { | ||
| 200 | - countDownLatch.countDown(); | ||
| 201 | - } | ||
| 202 | - } | ||
| 203 | - }.setName(databaseNames.get(i++))); | ||
| 204 | - } | ||
| 205 | - try { | ||
| 206 | - countDownLatch.await(10, TimeUnit.SECONDS); | ||
| 207 | - } catch (InterruptedException e) { | ||
| 208 | - throw new CustomException(e.getMessage()); | ||
| 209 | - } | ||
| 210 | - return AjaxResult.success(map); | ||
| 211 | - } | ||
| 212 | -} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/PageController.java+33-27
| @@ -15,10 +15,10 @@ import org.springframework.web.bind.annotation.GetMapping; | |||
| 15 | import org.springframework.web.bind.annotation.RequestMapping; | 15 | import org.springframework.web.bind.annotation.RequestMapping; |
| 16 | import org.springframework.web.bind.annotation.RestController; | 16 | import org.springframework.web.bind.annotation.RestController; |
| 17 | 17 | ||
| 18 | +import com.nctigba.observability.instance.aop.Ds; | ||
| 18 | import com.nctigba.observability.instance.constants.MetricsLine; | 19 | import com.nctigba.observability.instance.constants.MetricsLine; |
| 19 | import com.nctigba.observability.instance.constants.MetricsValue; | 20 | import com.nctigba.observability.instance.constants.MetricsValue; |
| 20 | import com.nctigba.observability.instance.mapper.DbConfigMapper; | 21 | import com.nctigba.observability.instance.mapper.DbConfigMapper; |
| 21 | -import com.nctigba.observability.instance.service.ClusterManager; | ||
| 22 | import com.nctigba.observability.instance.service.MetricsService; | 22 | import com.nctigba.observability.instance.service.MetricsService; |
| 23 | import com.nctigba.observability.instance.util.Language; | 23 | import com.nctigba.observability.instance.util.Language; |
| 24 | 24 | ||
| @@ -102,41 +102,47 @@ public class PageController extends ControllerConfig { | |||
| 102 | 102 | ||
| 103 | private final MetricsService metricsService; | 103 | private final MetricsService metricsService; |
| 104 | private final DbConfigMapper dbConfigMapper; | 104 | private final DbConfigMapper dbConfigMapper; |
| 105 | - private final ClusterManager clusterManager; | ||
| 106 | private final MessageSource messageSource; | 105 | private final MessageSource messageSource; |
| 107 | private final Language language; | 106 | private final Language language; |
| 108 | 107 | ||
| 109 | 108 | ||
| 109 | + | ||
| 110 | public Map<String, Object> memory(String id, Long start, Long end, Integer step) { | 110 | public Map<String, Object> memory(String id, Long start, Long end, Integer step) { |
| 111 | - HashMap<String, Object> batch = metricsService.listBatch(MEMORY, id, start, end, step); | 111 | + Map<String, Object> batch = metricsService.listBatch(MEMORY, id, start, end, step); |
| 112 | - try { | 112 | + // memory node detail |
| 113 | - clusterManager.setCurrentDatasource(id, null); | 113 | + List<Map<String, Object>> memoryNodeDetail = dbConfigMapper.memoryNodeDetail(); |
| 114 | - // memory node detail | 114 | + memoryNodeDetail.forEach(map -> { |
| 115 | - List<Map<String, Object>> memoryNodeDetail = dbConfigMapper.memoryNodeDetail(); | 115 | + var str = map.get("memorytype").toString(); |
| 116 | - memoryNodeDetail.forEach(map -> { | 116 | + map.put("desc", messageSource.getMessage("memory.node." + str, null, str, language.getLocale())); |
| 117 | - var str = map.get("memorytype").toString(); | 117 | + }); |
| 118 | - map.put("desc", messageSource.getMessage("memory.node." + str, null, str, language.getLocale())); | 118 | + batch.put("memoryNodeDetail", memoryNodeDetail); |
| 119 | - }); | 119 | + // memory config detail |
| 120 | - batch.put("memoryNodeDetail", memoryNodeDetail); | 120 | + List<Map<String, Object>> memoryConfig = dbConfigMapper.memoryConfig(); |
| 121 | - // memory config detail | 121 | + memoryConfig.forEach(map -> { |
| 122 | - List<Map<String, Object>> memoryConfig = dbConfigMapper.memoryConfig(); | 122 | + var str = map.get("name").toString(); |
| 123 | - memoryConfig.forEach(map -> { | 123 | + map.put("desc", messageSource.getMessage("memory.config." + str, null, str, language.getLocale())); |
| 124 | - var str = map.get("name").toString(); | 124 | + }); |
| 125 | - map.put("desc", messageSource.getMessage("memory.config." + str, null, str, language.getLocale())); | 125 | + // db memory |
| 126 | - }); | 126 | + var total = Long.parseLong(batch.get(MetricsValue.MEM_TOTAL.name()).toString()); |
| 127 | - batch.put("memoryConfig", memoryConfig); | 127 | + var percents = batch.get(MetricsLine.MEMORY_DB_USED.name()); |
| 128 | - } finally { | 128 | + if (percents instanceof List) { |
| 129 | - clusterManager.pool(); | 129 | + var listPercents = (List<?>) percents; |
| 130 | + var percent = listPercents.get(listPercents.size() - 1); | ||
| 131 | + if (percent instanceof Number) { | ||
| 132 | + batch.put("MEMORY_DB_USED_CURR", total * ((Number) percent).doubleValue() / 100); | ||
| 133 | + } | ||
| 130 | } | 134 | } |
| 135 | + | ||
| 136 | + batch.put("memoryConfig", memoryConfig); | ||
| 131 | return AjaxResult.success(batch); | 137 | return AjaxResult.success(batch); |
| 132 | } | 138 | } |
| 133 | 139 | ||
| 134 | 140 | ||
| 135 | 141 | ||
| 136 | public Map<String, Object> io(String id, Long start, Long end, Integer step) { | 142 | public Map<String, Object> io(String id, Long start, Long end, Integer step) { |
| 137 | - HashMap<String, Object> io = metricsService.listBatch(IO, id, start, end, step); | 143 | + Map<String, Object> io = metricsService.listBatch(IO, id, start, end, step); |
| 138 | - HashMap<String, Object> table = metricsService.listBatch(IO_TABLE, id, start, end, step); | 144 | + Map<String, Object> table = metricsService.listBatch(IO_TABLE, id, start, end, step); |
| 139 | - HashMap<String, Object> lines = new HashMap<>(); | 145 | + Map<String, Object> lines = new HashMap<>(); |
| 140 | for (MetricsValue metric : IO_TABLE) { | 146 | for (MetricsValue metric : IO_TABLE) { |
| 141 | var map = (Map<String, Object>) table.get(metric.name()); | 147 | var map = (Map<String, Object>) table.get(metric.name()); |
| 142 | if (map == null) { | 148 | if (map == null) { |
| @@ -158,9 +164,9 @@ public class PageController extends ControllerConfig { | |||
| 158 | 164 | ||
| 159 | 165 | ||
| 160 | public Map<String, Object> network(String id, Long start, Long end, Integer step) { | 166 | public Map<String, Object> network(String id, Long start, Long end, Integer step) { |
| 161 | - HashMap<String, Object> network = metricsService.listBatch(NETWORK, id, start, end, step); | 167 | + Map<String, Object> network = metricsService.listBatch(NETWORK, id, start, end, step); |
| 162 | - HashMap<String, Object> table = metricsService.listBatch(NETWORK_TABLE, id, start, end, step); | 168 | + Map<String, Object> table = metricsService.listBatch(NETWORK_TABLE, id, start, end, step); |
| 163 | - HashMap<String, Object> lines = new HashMap<>(); | 169 | + Map<String, Object> lines = new HashMap<>(); |
| 164 | for (MetricsValue metric : NETWORK_TABLE) { | 170 | for (MetricsValue metric : NETWORK_TABLE) { |
| 165 | var map = (Map<String, Object>) table.get(metric.name()); | 171 | var map = (Map<String, Object>) table.get(metric.name()); |
| 166 | if (map == null) { | 172 | if (map == null) { |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ParamInfoController.java+10-8
| @@ -1,19 +1,22 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.controller; | 5 | package com.nctigba.observability.instance.controller; |
| 5 | 6 | ||
| 6 | -import com.nctigba.common.web.exception.InstanceException; | 7 | +import java.util.List; |
| 7 | -import com.nctigba.observability.instance.dto.param.ParamInfoDTO; | 8 | + |
| 8 | -import com.nctigba.observability.instance.model.param.ParamQuery; | ||
| 9 | -import com.nctigba.observability.instance.service.ParamInfoService; | ||
| 10 | -import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 11 | -import lombok.RequiredArgsConstructor; | ||
| 12 | import org.springframework.web.bind.annotation.GetMapping; | 9 | import org.springframework.web.bind.annotation.GetMapping; |
| 13 | import org.springframework.web.bind.annotation.RequestMapping; | 10 | import org.springframework.web.bind.annotation.RequestMapping; |
| 14 | import org.springframework.web.bind.annotation.RestController; | 11 | import org.springframework.web.bind.annotation.RestController; |
| 15 | 12 | ||
| 16 | -import java.util.List; | 13 | +import com.nctigba.observability.instance.dto.param.ParamInfoDTO; |
| 14 | +import com.nctigba.observability.instance.exception.InstanceException; | ||
| 15 | +import com.nctigba.observability.instance.model.ParamQuery; | ||
| 16 | +import com.nctigba.observability.instance.service.ParamInfoService; | ||
| 17 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 18 | + | ||
| 19 | +import lombok.RequiredArgsConstructor; | ||
| 17 | 20 | ||
| 18 | /** | 21 | /** |
| 19 | * ParamInfo | 22 | * ParamInfo |
| @@ -25,7 +28,6 @@ import java.util.List; | |||
| 25 | 28 | ||
| 26 | 29 | ||
| 27 | public class ParamInfoController { | 30 | public class ParamInfoController { |
| 28 | - | ||
| 29 | private final ParamInfoService paramInfoService; | 31 | private final ParamInfoService paramInfoService; |
| 30 | 32 | ||
| 31 | 33 | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ResourceCPUController.java+10-2
| @@ -1,12 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.controller; | 5 | package com.nctigba.observability.instance.controller; |
| 5 | 6 | ||
| 6 | import java.io.IOException; | 7 | import java.io.IOException; |
| 7 | import java.util.ArrayList; | 8 | import java.util.ArrayList; |
| 8 | import java.util.HashMap; | 9 | import java.util.HashMap; |
| 9 | import java.util.List; | 10 | import java.util.List; |
| 11 | +import java.util.Map; | ||
| 10 | 12 | ||
| 11 | import org.opengauss.admin.common.core.domain.AjaxResult; | 13 | import org.opengauss.admin.common.core.domain.AjaxResult; |
| 12 | import org.opengauss.admin.common.exception.CustomException; | 14 | import org.opengauss.admin.common.exception.CustomException; |
| @@ -45,14 +47,20 @@ public class ResourceCPUController extends ControllerConfig { | |||
| 45 | MetricsLine.CPU_USER, | 47 | MetricsLine.CPU_USER, |
| 46 | MetricsLine.CPU_SYSTEM, | 48 | MetricsLine.CPU_SYSTEM, |
| 47 | MetricsLine.CPU_IOWAIT, | 49 | MetricsLine.CPU_IOWAIT, |
| 50 | + MetricsLine.CPU_IRQ, | ||
| 51 | + MetricsLine.CPU_SOFTIRQ, | ||
| 52 | + MetricsLine.CPU_NICE, | ||
| 53 | + MetricsLine.CPU_STEAL, | ||
| 54 | + MetricsLine.CPU_IDLE, | ||
| 48 | MetricsLine.CPU_DB, | 55 | MetricsLine.CPU_DB, |
| 49 | MetricsLine.CPU_TOTAL_5M_LOAD, | 56 | MetricsLine.CPU_TOTAL_5M_LOAD, |
| 50 | - MetricsLine.CPU_TOTAL_CORE_NUM, }; | 57 | + MetricsLine.CPU_TOTAL_CORE_NUM, |
| 58 | + }; | ||
| 51 | 59 | ||
| 52 | 60 | ||
| 53 | 61 | ||
| 54 | public AjaxResult cpu(String id, Long start, Long end, Integer step) { | 62 | public AjaxResult cpu(String id, Long start, Long end, Integer step) { |
| 55 | - HashMap<String, Object> cpu = metricsService.listBatch(CPU, id, start, end, step); | 63 | + Map<String, Object> cpu = metricsService.listBatch(CPU, id, start, end, step); |
| 56 | int core = 1; | 64 | int core = 1; |
| 57 | for (Number n : (List<Number>) cpu.get(MetricsLine.CPU_TOTAL_CORE_NUM.name())) { | 65 | for (Number n : (List<Number>) cpu.get(MetricsLine.CPU_TOTAL_CORE_NUM.name())) { |
| 58 | if (n.intValue() != 0) { | 66 | if (n.intValue() != 0) { |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/SessionController.java+1-66
| @@ -1,88 +1,23 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.controller; | 5 | package com.nctigba.observability.instance.controller; |
| 5 | 6 | ||
| 6 | -import java.util.HashMap; | ||
| 7 | -import java.util.List; | ||
| 8 | -import java.util.Map; | ||
| 9 | -import java.util.concurrent.ExecutionException; | ||
| 10 | -import java.util.concurrent.Future; | ||
| 11 | - | ||
| 12 | import org.opengauss.admin.common.core.domain.AjaxResult; | 7 | import org.opengauss.admin.common.core.domain.AjaxResult; |
| 13 | -import org.opengauss.admin.common.exception.CustomException; | ||
| 14 | import org.springframework.web.bind.annotation.GetMapping; | 8 | import org.springframework.web.bind.annotation.GetMapping; |
| 15 | import org.springframework.web.bind.annotation.RequestMapping; | 9 | import org.springframework.web.bind.annotation.RequestMapping; |
| 16 | import org.springframework.web.bind.annotation.RestController; | 10 | import org.springframework.web.bind.annotation.RestController; |
| 17 | 11 | ||
| 18 | -import com.alibaba.fastjson.JSONObject; | ||
| 19 | -import com.nctigba.observability.instance.constants.MetricsLine; | ||
| 20 | -import com.nctigba.observability.instance.model.monitoring.MonitoringParam; | ||
| 21 | -import com.nctigba.observability.instance.service.MetricsService; | ||
| 22 | -import com.nctigba.observability.instance.service.MonitoringService; | ||
| 23 | import com.nctigba.observability.instance.service.SessionService; | 12 | import com.nctigba.observability.instance.service.SessionService; |
| 24 | 13 | ||
| 25 | -import cn.hutool.core.thread.ThreadUtil; | ||
| 26 | import lombok.RequiredArgsConstructor; | 14 | import lombok.RequiredArgsConstructor; |
| 27 | -import lombok.extern.slf4j.Slf4j; | ||
| 28 | 15 | ||
| 29 | 16 | ||
| 30 | 17 | ||
| 31 | 18 | ||
| 32 | - | ||
| 33 | public class SessionController { | 19 | public class SessionController { |
| 34 | private final SessionService sessionService; | 20 | private final SessionService sessionService; |
| 35 | - private final MetricsService metricsService; | ||
| 36 | - private final MonitoringService monitoringService; | ||
| 37 | - | ||
| 38 | - private static final MetricsLine[] SESSION_STATISTIC = { | ||
| 39 | - MetricsLine.SESSION_MAX_CONNECTION, | ||
| 40 | - MetricsLine.SESSION_IDLE_CONNECTION, | ||
| 41 | - MetricsLine.SESSION_ACTIVE_CONNECTION, | ||
| 42 | - MetricsLine.SESSION_WAITING_CONNECTION, | ||
| 43 | - MetricsLine.CPU_TIME, | ||
| 44 | - MetricsLine.NET_SEND_TIME, | ||
| 45 | - MetricsLine.DATA_IO_TIME | ||
| 46 | - }; | ||
| 47 | - | ||
| 48 | - | ||
| 49 | - public AjaxResult sessionStatistic(String id, Long start, Long end, Integer step) { | ||
| 50 | - MonitoringParam monitoringParam = new MonitoringParam(); | ||
| 51 | - monitoringParam.setId(id); | ||
| 52 | - monitoringParam.setStart(String.valueOf(start)); | ||
| 53 | - monitoringParam.setEnd(String.valueOf(end)); | ||
| 54 | - monitoringParam.setStep(String.valueOf(step)); | ||
| 55 | - monitoringParam.setQuery(MetricsLine.WAIT_EVENT_COUNT.promQl(null, id)); | ||
| 56 | - monitoringParam.setType("LINE"); | ||
| 57 | - monitoringParam.setLegendName("event"); | ||
| 58 | - Future<Object> waitingEventFuture = ThreadUtil | ||
| 59 | - .execAsync(() -> monitoringService.getRangeMonitoringData(monitoringParam).get(0)); | ||
| 60 | - Future<JSONObject> simpleFuture = ThreadUtil.execAsync(() -> sessionService.simpleStatistic(id)); | ||
| 61 | - Future<HashMap<String, Object>> metricsFuture = ThreadUtil | ||
| 62 | - .execAsync(() -> metricsService.listBatch(SESSION_STATISTIC, id, start, end, step)); | ||
| 63 | - JSONObject simple; | ||
| 64 | - Object waitEvent; | ||
| 65 | - Map<String, Object> metrics; | ||
| 66 | - try { | ||
| 67 | - waitEvent = waitingEventFuture.get(); | ||
| 68 | - simple = simpleFuture.get(); | ||
| 69 | - metrics = metricsFuture.get(); | ||
| 70 | - } catch (InterruptedException | ExecutionException e) { | ||
| 71 | - log.error("", e); | ||
| 72 | - throw new CustomException("", e); | ||
| 73 | - } | ||
| 74 | - Map<String, Object> map = new HashMap<>(); | ||
| 75 | - map.put("gauss_wait_events_value", waitEvent); | ||
| 76 | - var time = (List<?>) metrics.get("time"); | ||
| 77 | - for (Map.Entry<String, Object> entry : metrics.entrySet()) { | ||
| 78 | - if (entry.getValue() == null) { | ||
| 79 | - entry.setValue(new int[time.size()]); | ||
| 80 | - } | ||
| 81 | - } | ||
| 82 | - map.putAll(metrics); | ||
| 83 | - map.putAll(simple); | ||
| 84 | - return AjaxResult.success(map); | ||
| 85 | - } | ||
| 86 | 21 | ||
| 87 | 22 | ||
| 88 | public AjaxResult blockAndLongTxc(String id) { | 23 | public AjaxResult blockAndLongTxc(String id) { |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/TopSQLController.java+40-23
| @@ -1,9 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.controller; | 5 | package com.nctigba.observability.instance.controller; |
| 5 | 6 | ||
| 7 | +import java.util.HashMap; | ||
| 6 | import java.util.List; | 8 | import java.util.List; |
| 9 | +import java.util.Map; | ||
| 7 | 10 | ||
| 8 | import org.opengauss.admin.common.core.domain.AjaxResult; | 11 | import org.opengauss.admin.common.core.domain.AjaxResult; |
| 9 | import org.springframework.web.bind.annotation.GetMapping; | 12 | import org.springframework.web.bind.annotation.GetMapping; |
| @@ -11,10 +14,10 @@ import org.springframework.web.bind.annotation.PathVariable; | |||
| 11 | import org.springframework.web.bind.annotation.RequestMapping; | 14 | import org.springframework.web.bind.annotation.RequestMapping; |
| 12 | import org.springframework.web.bind.annotation.RestController; | 15 | import org.springframework.web.bind.annotation.RestController; |
| 13 | 16 | ||
| 14 | -import com.alibaba.fastjson.JSONObject; | 17 | +import com.nctigba.observability.instance.constants.MetricsLine; |
| 15 | -import com.nctigba.observability.instance.dto.topsql.TopSQLInfoReq; | ||
| 16 | import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; | 18 | import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; |
| 17 | import com.nctigba.observability.instance.service.ClusterManager; | 19 | import com.nctigba.observability.instance.service.ClusterManager; |
| 20 | +import com.nctigba.observability.instance.service.MetricsService; | ||
| 18 | import com.nctigba.observability.instance.service.TopSQLService; | 21 | import com.nctigba.observability.instance.service.TopSQLService; |
| 19 | 22 | ||
| 20 | import lombok.RequiredArgsConstructor; | 23 | import lombok.RequiredArgsConstructor; |
| @@ -33,15 +36,11 @@ import lombok.RequiredArgsConstructor; | |||
| 33 | public class TopSQLController { | 36 | public class TopSQLController { |
| 34 | private final TopSQLService topSQLService; | 37 | private final TopSQLService topSQLService; |
| 35 | private final ClusterManager clusterManager; | 38 | private final ClusterManager clusterManager; |
| 36 | - | 39 | + private final MetricsService metricsService; |
| 37 | - | ||
| 38 | - public AjaxResult testConnection( String nodeId) { | ||
| 39 | - return AjaxResult.success(topSQLService.testConnection(nodeId)); | ||
| 40 | - } | ||
| 41 | 40 | ||
| 42 | 41 | ||
| 43 | public AjaxResult top10(TopSQLListReq topSQLListReq) { | 42 | public AjaxResult top10(TopSQLListReq topSQLListReq) { |
| 44 | - List<JSONObject> list = topSQLService.getTopSQLList(topSQLListReq); | 43 | + var list = topSQLService.topSQLList(topSQLListReq); |
| 45 | if (list == null) { | 44 | if (list == null) { |
| 46 | return AjaxResult.error("602", "top sql pre check fail"); | 45 | return AjaxResult.error("602", "top sql pre check fail"); |
| 47 | } | 46 | } |
| @@ -49,32 +48,50 @@ public class TopSQLController { | |||
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | 50 | ||
| 52 | - public AjaxResult detail(TopSQLInfoReq topSQLDetailReq) { | 51 | + public AjaxResult detail(String id, String sqlId) { |
| 53 | - return AjaxResult.success(topSQLService.getStatisticalInfo(topSQLDetailReq)); | 52 | + return AjaxResult.success(topSQLService.detail(id, sqlId)); |
| 54 | } | 53 | } |
| 55 | 54 | ||
| 56 | 55 | ||
| 57 | - public AjaxResult plan(TopSQLInfoReq topSQLPlanReq) { | 56 | + public AjaxResult plan(String id, String sqlId) { |
| 58 | - JSONObject res = topSQLService.getExecutionPlan(topSQLPlanReq, ""); | 57 | + var plan = topSQLService.executionPlan(id, sqlId); |
| 59 | - if (res == null) { | 58 | + Map<String, Object> parsedResult = new HashMap<>(); |
| 60 | - return AjaxResult.error("602", "execution plan pre check fail"); | 59 | + parsedResult.put("data", List.of(plan)); |
| 61 | - } | 60 | + parsedResult.put("total", |
| 62 | - return AjaxResult.success(res); | 61 | + Map.of("totalPlanRows", plan.totalPlanRows(), "totalPlanWidth", plan.totalPlanWidth())); |
| 62 | + return AjaxResult.success(parsedResult); | ||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | - @GetMapping(value = "/partition") | 65 | + @GetMapping("/sysResource") |
| 66 | - public AjaxResult partition(TopSQLInfoReq topSQLPartitionReq) { | 66 | + public AjaxResult sysResource(String id, Long start, Long end, Integer step) { |
| 67 | - return AjaxResult.success(topSQLService.getPartitionList(topSQLPartitionReq)); | 67 | + MetricsLine[] metricKey = { |
| 68 | + MetricsLine.CPU_TOTAL, | ||
| 69 | + MetricsLine.CPU_USER, | ||
| 70 | + MetricsLine.CPU_SYSTEM, | ||
| 71 | + MetricsLine.CPU_IOWAIT, | ||
| 72 | + MetricsLine.CPU_IRQ, | ||
| 73 | + MetricsLine.CPU_SOFTIRQ, | ||
| 74 | + MetricsLine.CPU_NICE, | ||
| 75 | + MetricsLine.CPU_STEAL, | ||
| 76 | + MetricsLine.CPU_IDLE, | ||
| 77 | + MetricsLine.CPU_DB, | ||
| 78 | + MetricsLine.MEMORY_USED, | ||
| 79 | + MetricsLine.MEMORY_DB_USED, | ||
| 80 | + MetricsLine.IO_UTIL, | ||
| 81 | + MetricsLine.NETWORK_IN_TOTAL, | ||
| 82 | + MetricsLine.NETWORK_OUT_TOTAL | ||
| 83 | + }; | ||
| 84 | + return AjaxResult.success(metricsService.listBatch(metricKey, id, start, end, step)); | ||
| 68 | } | 85 | } |
| 69 | 86 | ||
| 70 | 87 | ||
| 71 | - public AjaxResult index(TopSQLInfoReq topSQLIndexReq) { | 88 | + public AjaxResult index(String id, String sqlId) { |
| 72 | - return AjaxResult.success(topSQLService.getIndexAdvice(topSQLIndexReq)); | 89 | + return AjaxResult.success(topSQLService.indexAdvice(id, sqlId)); |
| 73 | } | 90 | } |
| 74 | 91 | ||
| 75 | 92 | ||
| 76 | - public AjaxResult object(TopSQLInfoReq topSQLObjectReq) { | 93 | + public AjaxResult object(String id, String sqlId) { |
| 77 | - return AjaxResult.success(topSQLService.getObjectInfo(topSQLObjectReq)); | 94 | + return AjaxResult.success(topSQLService.objectInfo(id, sqlId)); |
| 78 | } | 95 | } |
| 79 | 96 | ||
| 80 | 97 | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/WdrController.java+59-57
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.controller; | 5 | package com.nctigba.observability.instance.controller; |
| 5 | 6 | ||
| 6 | import java.beans.PropertyEditorSupport; | 7 | import java.beans.PropertyEditorSupport; |
| @@ -40,69 +41,70 @@ import com.nctigba.observability.instance.service.OpsWdrService; | |||
| 40 | 41 | ||
| 41 | 42 | ||
| 42 | public class WdrController { | 43 | public class WdrController { |
| 43 | - @InitBinder | 44 | + @InitBinder |
| 44 | - public void initBinder(WebDataBinder binder) { | 45 | + public void initBinder(WebDataBinder binder) { |
| 45 | - // Date format | 46 | + // Date format |
| 46 | - binder.registerCustomEditor(Date.class, new PropertyEditorSupport() { | 47 | + binder.registerCustomEditor(Date.class, new PropertyEditorSupport() { |
| 47 | - @Override | 48 | + @Override |
| 48 | - public void setAsText(String text) { | 49 | + public void setAsText(String text) { |
| 49 | - setValue(DateUtils.parseDate(text)); | 50 | + setValue(DateUtils.parseDate(text)); |
| 50 | - } | 51 | + } |
| 51 | - }); | 52 | + }); |
| 52 | - } | 53 | + } |
| 53 | 54 | ||
| 54 | - @Autowired | 55 | + @Autowired |
| 55 | - private OpsWdrService wdrService; | 56 | + private OpsWdrService wdrService; |
| 56 | 57 | ||
| 57 | - @GetMapping("/listSnapshot") | 58 | + @GetMapping("/listSnapshot") |
| 58 | - public Page<?> listSnapshot(@RequestParam String clusterId, @RequestParam String hostId) { | 59 | + public Page<?> listSnapshot(@RequestParam String clusterId, @RequestParam String hostId) { |
| 59 | - return wdrService.listSnapshot(startPage(), clusterId, hostId); | 60 | + return wdrService.listSnapshot(startPage(), clusterId, hostId); |
| 60 | - } | 61 | + } |
| 61 | 62 | ||
| 62 | - @GetMapping("/createSnapshot") | 63 | + @GetMapping("/createSnapshot") |
| 63 | - public AjaxResult createSnapshot(@RequestParam String clusterId, @RequestParam String hostId) { | 64 | + public AjaxResult createSnapshot(@RequestParam String clusterId, @RequestParam String hostId) { |
| 64 | - wdrService.createSnapshot(clusterId, hostId); | 65 | + wdrService.createSnapshot(clusterId, hostId); |
| 65 | - return AjaxResult.success(); | 66 | + return AjaxResult.success(); |
| 66 | - } | 67 | + } |
| 67 | 68 | ||
| 68 | - @GetMapping("/list") | 69 | + @GetMapping("/list") |
| 69 | - public Page<OpsWdrEntity> list(@RequestParam String clusterId, | 70 | + public Page<OpsWdrEntity> list(@RequestParam String clusterId, |
| 70 | - @RequestParam(required = false, value = "wdrScope") WdrScopeEnum wdrScope, | 71 | + @RequestParam(required = false, value = "wdrScope") WdrScopeEnum wdrScope, |
| 71 | - @RequestParam(required = false, value = "wdrType") WdrTypeEnum wdrType, | 72 | + @RequestParam(required = false, value = "wdrType") WdrTypeEnum wdrType, |
| 72 | - @RequestParam(required = false, value = "hostId") String hostId, | 73 | + @RequestParam(required = false, value = "hostId") String hostId, |
| 73 | - @RequestParam(required = false, value = "start") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date start, | 74 | + @RequestParam(required = false, value = "start") |
| 74 | - @RequestParam(required = false, value = "end") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date end) { | 75 | + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date start, |
| 75 | - return wdrService.listWdr(startPage(), clusterId, wdrScope, wdrType, hostId, start, end); | 76 | + @RequestParam(required = false, value = "end") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date end) { |
| 76 | - } | 77 | + return wdrService.listWdr(startPage(), clusterId, wdrScope, wdrType, hostId, start, end); |
| 78 | + } | ||
| 77 | 79 | ||
| 78 | - @DeleteMapping("/del/{id}") | 80 | + @DeleteMapping("/del/{id}") |
| 79 | - public AjaxResult del(@PathVariable("id") String id) { | 81 | + public AjaxResult del(@PathVariable("id") String id) { |
| 80 | - wdrService.del(id); | 82 | + wdrService.del(id); |
| 81 | - return AjaxResult.success(); | 83 | + return AjaxResult.success(); |
| 82 | - } | 84 | + } |
| 83 | 85 | ||
| 84 | - @PostMapping("/generate") | 86 | + @PostMapping("/generate") |
| 85 | - public AjaxResult generate(@RequestBody @Validated WdrGeneratorBody wdrGeneratorBody) { | 87 | + public AjaxResult generate(@RequestBody @Validated WdrGeneratorBody wdrGeneratorBody) { |
| 86 | - wdrService.generate(wdrGeneratorBody); | 88 | + wdrService.generate(wdrGeneratorBody); |
| 87 | - return AjaxResult.success(); | 89 | + return AjaxResult.success(); |
| 88 | - } | 90 | + } |
| 89 | 91 | ||
| 90 | - @GetMapping("/downloadWdr") | 92 | + @GetMapping("/downloadWdr") |
| 91 | - public void downloadWdr(@RequestParam String wdrId, HttpServletResponse response) { | 93 | + public void downloadWdr(@RequestParam String wdrId, HttpServletResponse response) { |
| 92 | - wdrService.downloadWdr(wdrId, response); | 94 | + wdrService.downloadWdr(wdrId, response); |
| 93 | - } | 95 | + } |
| 94 | 96 | ||
| 95 | - @SuppressWarnings("rawtypes") | 97 | + @SuppressWarnings("rawtypes") |
| 96 | - protected Page startPage() { | 98 | + protected Page startPage() { |
| 97 | - Page page = new Page(); | 99 | + Page page = new Page(); |
| 98 | - Integer pageNum = ServletUtils.getParameterToInt("pageNum"); | 100 | + Integer pageNum = ServletUtils.getParameterToInt("pageNum"); |
| 99 | - Integer pageSize = ServletUtils.getParameterToInt("pageSize"); | 101 | + Integer pageSize = ServletUtils.getParameterToInt("pageSize"); |
| 100 | - if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) { | 102 | + if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) { |
| 101 | - page.setCurrent((long) pageNum); | 103 | + page.setCurrent(pageNum); |
| 102 | - page.setSize((long) pageSize); | 104 | + page.setSize(pageSize); |
| 103 | - page.setOptimizeCountSql(false); | 105 | + page.setOptimizeCountSql(false); |
| 104 | - page.setMaxLimit(500L); | 106 | + page.setMaxLimit(500L); |
| 105 | - } | 107 | + } |
| 106 | - return page; | 108 | + return page; |
| 107 | - } | 109 | + } |
| 108 | } | 110 | } |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/WdrSnapController.java+40-0
| @@ -0,0 +1,40 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.controller; | ||
| 6 | + | ||
| 7 | +import java.util.Date; | ||
| 8 | + | ||
| 9 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 10 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 11 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 12 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 13 | +import org.springframework.web.bind.annotation.RestController; | ||
| 14 | + | ||
| 15 | +import com.nctigba.observability.instance.service.OpsWdrService; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * WdrSnapController.java | ||
| 19 | + * | ||
| 20 | + * 2023-08-25 | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +public class WdrSnapController extends ControllerConfig { | ||
| 25 | + | ||
| 26 | + private OpsWdrService wdrService; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * findSnapshot | ||
| 30 | + * | ||
| 31 | + * id id | ||
| 32 | + * start start | ||
| 33 | + * end end | ||
| 34 | + * AjaxResult | ||
| 35 | + */ | ||
| 36 | + | ||
| 37 | + public AjaxResult findSnapshot(String id, Date start, Date end) { | ||
| 38 | + return AjaxResult.success(wdrService.findSnapshot(id, start, end)); | ||
| 39 | + } | ||
| 40 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/asp/AnalysisDto.java+40-0
| @@ -0,0 +1,40 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.asp; | ||
| 6 | + | ||
| 7 | +import lombok.AllArgsConstructor; | ||
| 8 | +import lombok.Data; | ||
| 9 | +import lombok.NoArgsConstructor; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * AnalysisDto | ||
| 13 | + * | ||
| 14 | + * liupengfei | ||
| 15 | + * 2023/8/25 | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +public class AnalysisDto { | ||
| 21 | + private String sampleid; | ||
| 22 | + private String sampleTime; | ||
| 23 | + private String databaseid; | ||
| 24 | + private String threadId; | ||
| 25 | + private String sessionid; | ||
| 26 | + private String startTime; | ||
| 27 | + private String event; | ||
| 28 | + private String userid; | ||
| 29 | + private String applicationName; | ||
| 30 | + private String clientAddr; | ||
| 31 | + private String clientHostname; | ||
| 32 | + private String clientPort; | ||
| 33 | + private String queryId; | ||
| 34 | + private String uniqueQueryId; | ||
| 35 | + private String userId; | ||
| 36 | + private String cnId; | ||
| 37 | + private String uniqueQuery; | ||
| 38 | + private String lockmode; | ||
| 39 | + private String waitStatus; | ||
| 40 | +} | ||
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/ResInfo.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/asp/AspCountReq.java+13-9
| @@ -2,19 +2,23 @@ | |||
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | -package com.nctigba.observability.instance.model; | 5 | +package com.nctigba.observability.instance.dto.asp; |
| 6 | 6 | ||
| 7 | import lombok.AllArgsConstructor; | 7 | import lombok.AllArgsConstructor; |
| 8 | import lombok.Data; | 8 | import lombok.Data; |
| 9 | +import lombok.NoArgsConstructor; | ||
| 9 | 10 | ||
| 11 | +/** | ||
| 12 | + * AspCountReq | ||
| 13 | + * | ||
| 14 | + * liupengfei | ||
| 15 | + * 2023/8/25 | ||
| 16 | + */ | ||
| 10 | 17 | ||
| 18 | + | ||
| 11 | 19 | ||
| 12 | -public class ResInfo { | 20 | +public class AspCountReq { |
| 13 | - private int exitStatus; | 21 | + private String id; |
| 14 | - private String outRes; | 22 | + private String startTime; |
| 15 | - private String errRes; | 23 | + private String finishTime; |
| 16 | - | ||
| 17 | - public ResInfo() { | ||
| 18 | - this.exitStatus = -2147483648; | ||
| 19 | - } | ||
| 20 | } | 24 | } |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/ClusterHealthState.java+24-0
| @@ -0,0 +1,24 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * ClusterHealthState | ||
| 13 | + * | ||
| 14 | + * liupengfei | ||
| 15 | + * 2023/8/25 | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +public class ClusterHealthState { | ||
| 19 | + private String clusterState; | ||
| 20 | + private Map<String, String> nodeState; | ||
| 21 | + private Map<String, String> nodeRole; | ||
| 22 | + private Map<String, String> nodeName; | ||
| 23 | + private Map<String, String> cmState; | ||
| 24 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/ClusterStateDto.java+64-0
| @@ -0,0 +1,64 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 8 | +import lombok.AllArgsConstructor; | ||
| 9 | +import lombok.Data; | ||
| 10 | +import lombok.NoArgsConstructor; | ||
| 11 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 12 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; | ||
| 13 | + | ||
| 14 | +import java.util.Map; | ||
| 15 | +import java.util.Optional; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * ClusterStateDto | ||
| 19 | + * | ||
| 20 | + * liupengfei | ||
| 21 | + * 2023/8/25 | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +public class ClusterStateDto { | ||
| 27 | + private String clusterId; | ||
| 28 | + private State clusterState; | ||
| 29 | + private String desc; | ||
| 30 | + private String primaryNodeId; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * get ClusterStateDto | ||
| 34 | + * | ||
| 35 | + * clusterVO OpsClusterVO | ||
| 36 | + * stateCache ClusterHealthState | ||
| 37 | + * ClusterStateDto | ||
| 38 | + */ | ||
| 39 | + public static ClusterStateDto of(OpsClusterVO clusterVO, ClusterHealthState stateCache) { | ||
| 40 | + ClusterStateDto dto = new ClusterStateDto(); | ||
| 41 | + dto.setClusterId(clusterVO.getClusterId()); | ||
| 42 | + String state = Optional.ofNullable(stateCache.getClusterState()).orElse( | ||
| 43 | + "Unknown"); | ||
| 44 | + dto.setClusterState(state); | ||
| 45 | + dto.setDesc(state); | ||
| 46 | + Optional<Map.Entry<String, String>> primary = stateCache.getNodeRole().entrySet().stream().filter( | ||
| 47 | + en -> en.getValue().equals("Primary")).findFirst(); | ||
| 48 | + if (primary.isPresent()) { | ||
| 49 | + String primaryIp = primary.get().getKey(); | ||
| 50 | + OpsClusterNodeVO nodeVO = clusterVO.getClusterNodes().stream().filter( | ||
| 51 | + node -> node.getPublicIp().equals(primaryIp)).findFirst().get(); | ||
| 52 | + dto.setPrimaryNodeId(nodeVO.getNodeId()); | ||
| 53 | + } | ||
| 54 | + return dto; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public void setClusterState(String clusterState) { | ||
| 58 | + this.clusterState = new State("cluster.state.value." + clusterState); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void setDesc(String state) { | ||
| 62 | + this.desc = MessageSourceUtil.getMsg("cluster.state.desc." + state); | ||
| 63 | + } | ||
| 64 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/ClustersDto.java+52-0
| @@ -0,0 +1,52 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 10 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; | ||
| 11 | + | ||
| 12 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 13 | + | ||
| 14 | +import lombok.Data; | ||
| 15 | +import lombok.NoArgsConstructor; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * ClustersDto | ||
| 19 | + * | ||
| 20 | + * liupengfei | ||
| 21 | + * 2023/8/25 | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class ClustersDto { | ||
| 26 | + private String clusterId; | ||
| 27 | + private String versionNum; | ||
| 28 | + private String version; | ||
| 29 | + private String envPath; | ||
| 30 | + private Integer nodeCount; | ||
| 31 | + private String arch; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * get ClustersDto | ||
| 35 | + * | ||
| 36 | + * opsClusterVO OpsClusterVO | ||
| 37 | + * ClustersDto | ||
| 38 | + */ | ||
| 39 | + public static ClustersDto of(OpsClusterVO opsClusterVO) { | ||
| 40 | + ClustersDto clustersDto = new ClustersDto(); | ||
| 41 | + clustersDto.setClusterId(opsClusterVO.getClusterId()); | ||
| 42 | + clustersDto.setVersionNum(opsClusterVO.getVersionNum()); | ||
| 43 | + clustersDto.setEnvPath(opsClusterVO.getEnvPath()); | ||
| 44 | + clustersDto.setVersion(opsClusterVO.getVersion()); | ||
| 45 | + clustersDto.setNodeCount(opsClusterVO.getClusterNodes().size()); | ||
| 46 | + List<OpsClusterNodeVO> nodes = opsClusterVO.getClusterNodes(); | ||
| 47 | + Long primaryNum = nodes.stream().filter(node -> "MASTER".equalsIgnoreCase(node.getClusterRole())).count(); | ||
| 48 | + Long standbyNum = nodes.stream().filter(node -> !"MASTER".equalsIgnoreCase(node.getClusterRole())).count(); | ||
| 49 | + clustersDto.setArch(MessageSourceUtil.getMsg("cluster.arch", primaryNum.toString(), standbyNum.toString())); | ||
| 50 | + return clustersDto; | ||
| 51 | + } | ||
| 52 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/NodeAndCompDto.java+82-0
| @@ -0,0 +1,82 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 8 | + | ||
| 9 | +import lombok.AllArgsConstructor; | ||
| 10 | +import lombok.Data; | ||
| 11 | +import lombok.Getter; | ||
| 12 | +import lombok.NoArgsConstructor; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * SyncSituation | ||
| 16 | + * | ||
| 17 | + * liupengfei | ||
| 18 | + * 2023/8/25 | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +public class NodeAndCompDto { | ||
| 23 | + private State cmServerState; | ||
| 24 | + private State omMonitorState; | ||
| 25 | + private State cmAgentState; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * get NodeAndCompDto | ||
| 29 | + * | ||
| 30 | + * vo OpsClusterNodeVO | ||
| 31 | + * NodeAndCompDto | ||
| 32 | + */ | ||
| 33 | + public static NodeAndCompDto of(OpsClusterNodeVO vo) { | ||
| 34 | + return new NodeAndCompDto(); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setCmServerState(String cmServerState) { | ||
| 38 | + this.cmServerState = new State("OS.bin.state." + BinState.getState(cmServerState)); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public void setOmMonitorState(String omMonitorState) { | ||
| 42 | + this.omMonitorState = new State("OS.bin.state." + BinState.getState(omMonitorState)); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public void setCmAgentState(String cmAgentState) { | ||
| 46 | + this.cmAgentState = new State("OS.bin.state." + BinState.getState(cmAgentState)); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * BinState | ||
| 51 | + */ | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + public enum BinState { | ||
| 55 | + TASK_UNINTERRUPTIBLE("D"), | ||
| 56 | + TASK_RUNNING("R"), | ||
| 57 | + TASK_INTERRUPTIBLE("S"), | ||
| 58 | + TASK_STOPPED("T"), | ||
| 59 | + TASK_TRACED("t"), | ||
| 60 | + EXIT_ZOMBIE("Z"), | ||
| 61 | + EXIT_DEAD("X"), | ||
| 62 | + STOP("stop"), | ||
| 63 | + UNKNOWN("Unknown"); | ||
| 64 | + | ||
| 65 | + private final String code; | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * getState | ||
| 69 | + * | ||
| 70 | + * s String | ||
| 71 | + * BinState | ||
| 72 | + */ | ||
| 73 | + public static BinState getState(String s) { | ||
| 74 | + for (BinState state : BinState.values()) { | ||
| 75 | + if (s.contains(state.code)) { | ||
| 76 | + return state; | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + return UNKNOWN; | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/NodeRelationDto.java+56-0
| @@ -0,0 +1,56 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.NoArgsConstructor; | ||
| 9 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * NodeRelationDto | ||
| 15 | + * | ||
| 16 | + * liupengfei | ||
| 17 | + * 2023/8/25 | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +public class NodeRelationDto { | ||
| 22 | + private String hostIp; | ||
| 23 | + private String role; | ||
| 24 | + private String state; | ||
| 25 | + private String replayDelay; | ||
| 26 | + private String syncState; | ||
| 27 | + private List<NodeRelationDto> children; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * getDefaultRelationDto | ||
| 31 | + * | ||
| 32 | + * stateCache ClusterHealthState | ||
| 33 | + * node OpsClusterNodeVO | ||
| 34 | + * standbyList List<NodeRelationDto> | ||
| 35 | + * NodeRelationDto | ||
| 36 | + */ | ||
| 37 | + public static NodeRelationDto getDefaultRelationDto(ClusterHealthState stateCache, OpsClusterNodeVO node, | ||
| 38 | + List<NodeRelationDto> standbyList) { | ||
| 39 | + NodeRelationDto primary = new NodeRelationDto(); | ||
| 40 | + primary.setHostIp(node.getPublicIp()); | ||
| 41 | + setNodeState(primary, stateCache); | ||
| 42 | + primary.setChildren(standbyList); | ||
| 43 | + return primary; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * setNodeState | ||
| 48 | + * | ||
| 49 | + * node NodeRelationDto | ||
| 50 | + * stateCache ClusterHealthState | ||
| 51 | + */ | ||
| 52 | + public static void setNodeState(NodeRelationDto node, ClusterHealthState stateCache) { | ||
| 53 | + node.setRole(stateCache.getNodeRole().getOrDefault(node.getHostIp(), "Unknown")); | ||
| 54 | + node.setState(stateCache.getNodeState().getOrDefault(node.getHostIp(), "Unknown")); | ||
| 55 | + } | ||
| 56 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/State.java+38-0
| @@ -0,0 +1,38 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import com.nctigba.observability.instance.constants.StateColor; | ||
| 8 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 9 | +import lombok.AllArgsConstructor; | ||
| 10 | +import lombok.Data; | ||
| 11 | +import lombok.NoArgsConstructor; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * State | ||
| 15 | + * | ||
| 16 | + * liupengfei | ||
| 17 | + * 2023/8/25 | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +public class State { | ||
| 23 | + private String value; | ||
| 24 | + private StateColor color; | ||
| 25 | + | ||
| 26 | + State(String value) { | ||
| 27 | + this.value = value; | ||
| 28 | + setColor(); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public void setColor() { | ||
| 32 | + this.color = StateColor.getColor(value); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public String getValue() { | ||
| 36 | + return MessageSourceUtil.getMsg(value); | ||
| 37 | + } | ||
| 38 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/SyncSituation.java+28-0
| @@ -0,0 +1,28 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import lombok.AllArgsConstructor; | ||
| 8 | +import lombok.Data; | ||
| 9 | +import lombok.NoArgsConstructor; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * SyncSituation | ||
| 13 | + * | ||
| 14 | + * liupengfei | ||
| 15 | + * 2023/8/25 | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +public class SyncSituation { | ||
| 21 | + private String hostIp; | ||
| 22 | + private String sync; | ||
| 23 | + private String walSyncState; | ||
| 24 | + private String syncPriority; | ||
| 25 | + private String receivedDelay; | ||
| 26 | + private String writeDelay; | ||
| 27 | + private String replayDelay; | ||
| 28 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/cluster/SyncSituationDto.java+82-0
| @@ -0,0 +1,82 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.dto.cluster; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| 8 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 9 | +import lombok.Data; | ||
| 10 | +import lombok.NoArgsConstructor; | ||
| 11 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 12 | + | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Optional; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * SyncSituationDto | ||
| 18 | + * | ||
| 19 | + * liupengfei | ||
| 20 | + * 2023/8/25 | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +public class SyncSituationDto { | ||
| 25 | + private String clusterId; | ||
| 26 | + private String nodeId; | ||
| 27 | + private String hostIp; | ||
| 28 | + private String nodeName; | ||
| 29 | + private String primaryAddr; | ||
| 30 | + private String localAddr; | ||
| 31 | + private String role; | ||
| 32 | + private State nodeState; | ||
| 33 | + private String sync; | ||
| 34 | + private State syncState; | ||
| 35 | + private String syncPriority; | ||
| 36 | + private String receivedDelay; | ||
| 37 | + private String writeDelay; | ||
| 38 | + private String replayDelay; | ||
| 39 | + | ||
| 40 | + private String walSyncState; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * getDefaultSituationDto | ||
| 44 | + * | ||
| 45 | + * syncSituation SyncSituation | ||
| 46 | + * clusterNodes List<OpsClusterNodeVO> | ||
| 47 | + * clusterId String | ||
| 48 | + * SyncSituationDto | ||
| 49 | + */ | ||
| 50 | + public static SyncSituationDto getDefaultSituationDto(SyncSituation syncSituation, | ||
| 51 | + List<OpsClusterNodeVO> clusterNodes, String clusterId) { | ||
| 52 | + SyncSituationDto dto = new SyncSituationDto(); | ||
| 53 | + dto.setClusterId(clusterId); | ||
| 54 | + Optional<OpsClusterNodeVO> nodeVO = clusterNodes.stream().filter( | ||
| 55 | + n -> n.getPublicIp().equals(syncSituation.getHostIp())).findFirst(); | ||
| 56 | + nodeVO.ifPresent(node -> dto.setNodeId(node.getNodeId())); | ||
| 57 | + dto.setHostIp(syncSituation.getHostIp()); | ||
| 58 | + dto.setSync(syncSituation.getSync()); | ||
| 59 | + dto.setSyncState(syncSituation.getWalSyncState()); | ||
| 60 | + dto.setSyncPriority(syncSituation.getSyncPriority()); | ||
| 61 | + dto.setReceivedDelay(syncSituation.getReceivedDelay()); | ||
| 62 | + dto.setWriteDelay(syncSituation.getWriteDelay()); | ||
| 63 | + dto.setReplayDelay(syncSituation.getReplayDelay()); | ||
| 64 | + return dto; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + public void setNodeState(String state) { | ||
| 68 | + this.nodeState = new State("cluster.node.state." + state); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + public String getRole() { | ||
| 72 | + return MessageSourceUtil.getMsg("cluster.node.role." + role); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + public String getSync() { | ||
| 76 | + return MessageSourceUtil.getMsg("cluster.node.sync." + sync); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + public void setSyncState(String state) { | ||
| 80 | + this.syncState = new State("cluster.node.syncState." + state); | ||
| 81 | + } | ||
| 82 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/topsql/TopSQLListReq.java+31-1
| @@ -4,6 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | package com.nctigba.observability.instance.dto.topsql; | 5 | package com.nctigba.observability.instance.dto.topsql; |
| 6 | 6 | ||
| 7 | +import java.sql.Timestamp; | ||
| 8 | + | ||
| 9 | +import cn.hutool.core.util.StrUtil; | ||
| 7 | import lombok.Data; | 10 | import lombok.Data; |
| 8 | 11 | ||
| 9 | /** | 12 | /** |
| @@ -20,4 +23,31 @@ public class TopSQLListReq { | |||
| 20 | private String startTime; | 23 | private String startTime; |
| 21 | private String finishTime; | 24 | private String finishTime; |
| 22 | private String orderField; | 25 | private String orderField; |
| 23 | -} | 26 | + |
| 27 | + /** | ||
| 28 | + * getStartTimeTime | ||
| 29 | + * | ||
| 30 | + * Timestamp | ||
| 31 | + */ | ||
| 32 | + public Timestamp getStartTimeTime() { | ||
| 33 | + return Timestamp.valueOf(getStartTime()); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * getFinishTimeTime | ||
| 38 | + * | ||
| 39 | + * Timestamp | ||
| 40 | + */ | ||
| 41 | + public Timestamp getFinishTimeTime() { | ||
| 42 | + return Timestamp.valueOf(getFinishTime()); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * getOrderField | ||
| 47 | + * | ||
| 48 | + * String | ||
| 49 | + */ | ||
| 50 | + public String getOrderField() { | ||
| 51 | + return StrUtil.isBlank(orderField) ? "execution_time" : orderField; | ||
| 52 | + } | ||
| 53 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/ParamInfo.java+3-3
| @@ -26,7 +26,7 @@ public class ParamInfo { | |||
| 26 | 26 | ||
| 27 | Integer id; | 27 | Integer id; |
| 28 | 28 | ||
| 29 | - type paramType; | 29 | + ParamType paramType; |
| 30 | 30 | ||
| 31 | String paramName; | 31 | String paramName; |
| 32 | String paramDetail; | 32 | String paramDetail; |
| @@ -39,7 +39,7 @@ public class ParamInfo { | |||
| 39 | 39 | ||
| 40 | String diagnosisRule; | 40 | String diagnosisRule; |
| 41 | 41 | ||
| 42 | - public enum type { | 42 | + public enum ParamType { |
| 43 | OS, | 43 | OS, |
| 44 | DB | 44 | DB |
| 45 | } | 45 | } |
| @@ -50,7 +50,7 @@ public class ParamInfo { | |||
| 50 | var info = new ParamInfo(); | 50 | var info = new ParamInfo(); |
| 51 | info.setId(rs.getInt("id")); | 51 | info.setId(rs.getInt("id")); |
| 52 | info.setParamName(rs.getString("paramName")); | 52 | info.setParamName(rs.getString("paramName")); |
| 53 | - info.setParamType(type.valueOf(rs.getString("paramType"))); | 53 | + info.setParamType(ParamType.valueOf(rs.getString("paramType"))); |
| 54 | info.setSuggestValue(rs.getString("suggestValue")); | 54 | info.setSuggestValue(rs.getString("suggestValue")); |
| 55 | info.setDefaultValue(rs.getString("defaultValue")); | 55 | info.setDefaultValue(rs.getString("defaultValue")); |
| 56 | list.add(info); | 56 | list.add(info); |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/PgSettings.java+35-0
| @@ -0,0 +1,35 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 8 | + | ||
| 9 | +import lombok.Data; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * PgSettings.java | ||
| 13 | + * | ||
| 14 | + * 2023-08-25 | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class PgSettings { | ||
| 19 | + String name; | ||
| 20 | + String setting; | ||
| 21 | + String unit; | ||
| 22 | + String category; | ||
| 23 | + String shortDesc; | ||
| 24 | + String extraDesc; | ||
| 25 | + String context; | ||
| 26 | + String vartype; | ||
| 27 | + String source; | ||
| 28 | + String minVal; | ||
| 29 | + String maxVal; | ||
| 30 | + String enumvals; | ||
| 31 | + String bootVal; | ||
| 32 | + String resetVal; | ||
| 33 | + String sourcefile; | ||
| 34 | + String sourceline; | ||
| 35 | +} | ||
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/WdrSnapshotVO.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/Snapshot.java+23-23
| @@ -1,24 +1,24 @@ | |||
| 1 | -/* | 1 | +/* |
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | - */ | 3 | + */ |
| 4 | - | 4 | + |
| 5 | -package com.nctigba.observability.instance.model; | 5 | +package com.nctigba.observability.instance.entity; |
| 6 | - | 6 | + |
| 7 | -import java.util.Date; | 7 | +import java.util.Date; |
| 8 | - | 8 | + |
| 9 | -import com.baomidou.mybatisplus.annotation.TableField; | 9 | +import com.baomidou.mybatisplus.annotation.TableName; |
| 10 | -import com.baomidou.mybatisplus.annotation.TableId; | 10 | + |
| 11 | -import com.baomidou.mybatisplus.annotation.TableName; | 11 | +import lombok.Data; |
| 12 | - | 12 | + |
| 13 | -import lombok.Data; | 13 | +/** |
| 14 | - | 14 | + * Snapshot.java |
| 15 | -@Data | 15 | + * |
| 16 | -@TableName(value = "snapshot.snapshot", autoResultMap = true) | 16 | + * @since 2023-08-25 |
| 17 | -public class WdrSnapshotVO { | 17 | + */ |
| 18 | - @TableId("snapshot_id") | 18 | +@Data |
| 19 | - private Integer snapshotId; | 19 | +@TableName("snapshot.snapshot") |
| 20 | - @TableField("start_ts") | 20 | +public class Snapshot { |
| 21 | - private Date startTs; | 21 | + private Long snapshotId; |
| 22 | - @TableField("end_ts") | 22 | + private Date startTs; |
| 23 | - private Date endTs; | 23 | + private Date endTs; |
| 24 | } | 24 | } |
Rplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/BaseI18nException.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/exception/BaseI18nException.java+1-1
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | -package com.nctigba.common.web.exception; | 5 | +package com.nctigba.observability.instance.exception; |
| 6 | 6 | ||
| 7 | import com.nctigba.observability.instance.util.MessageSourceUtil; | 7 | import com.nctigba.observability.instance.util.MessageSourceUtil; |
| 8 | 8 | ||
Rplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/InstanceException.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/exception/InstanceException.java+1-1
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | -package com.nctigba.common.web.exception; | 5 | +package com.nctigba.observability.instance.exception; |
| 6 | 6 | ||
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | import lombok.EqualsAndHashCode; | 8 | import lombok.EqualsAndHashCode; |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/MonitoringHandlerFactory.java+0-57
| @@ -1,57 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.factory; | ||
| 5 | - | ||
| 6 | -import javax.annotation.PostConstruct; | ||
| 7 | -import javax.annotation.Resource; | ||
| 8 | -import java.util.List; | ||
| 9 | -import java.util.Map; | ||
| 10 | -import java.util.function.Function; | ||
| 11 | -import java.util.stream.Collectors; | ||
| 12 | - | ||
| 13 | -import com.alibaba.fastjson.JSON; | ||
| 14 | -import com.nctigba.observability.instance.constants.MonitoringType; | ||
| 15 | -import com.nctigba.observability.instance.handler.monitoring.MonitoringHandler; | ||
| 16 | - | ||
| 17 | -import lombok.extern.slf4j.Slf4j; | ||
| 18 | -import org.springframework.aop.support.AopUtils; | ||
| 19 | -import org.springframework.stereotype.Component; | ||
| 20 | - | ||
| 21 | -/** | ||
| 22 | - * The monitoring implementation class of MonitoringHandler uses the self | ||
| 23 | - * implemented bean name of monitoringType, such as prometheus<br> | ||
| 24 | - * | ||
| 25 | - * yangjie | ||
| 26 | - */ | ||
| 27 | - | ||
| 28 | - | ||
| 29 | - | ||
| 30 | -public class MonitoringHandlerFactory { | ||
| 31 | - | ||
| 32 | - private Map<String, MonitoringHandler> handlerMap; | ||
| 33 | - | ||
| 34 | - | ||
| 35 | - private List<MonitoringHandler> handlerList; | ||
| 36 | - | ||
| 37 | - | ||
| 38 | - public void init() { | ||
| 39 | - handlerMap = handlerList.stream() | ||
| 40 | - .collect(Collectors.toMap(MonitoringHandler::getMonitorType, Function.identity())); | ||
| 41 | - log.info("load MonitoringHandler complete. entity:{}", JSON.toJSONString(handlerMap.entrySet().stream() | ||
| 42 | - .collect(Collectors.toMap(Map.Entry::getKey, entity -> AopUtils.getTargetClass(entity.getValue()))))); | ||
| 43 | - | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - /** | ||
| 47 | - * Return the processing class of the monitoring according to the monitoring | ||
| 48 | - * type. If it is not found, return the default processing class | ||
| 49 | - * | ||
| 50 | - * monitoringType Monitoring type | ||
| 51 | - * MonitoringHandler Monitoring and processing class | ||
| 52 | - */ | ||
| 53 | - public MonitoringHandler getInstance(String monitoringType) { | ||
| 54 | - return handlerMap.containsKey(monitoringType) ? handlerMap.get(monitoringType) | ||
| 55 | - : handlerMap.get(MonitoringType.DEFAULT.getMonitoringType()); | ||
| 56 | - } | ||
| 57 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/SessionHandlerFactory.java+0-47
| @@ -1,47 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.factory; | ||
| 5 | - | ||
| 6 | -import com.alibaba.fastjson.JSON; | ||
| 7 | -import com.nctigba.observability.instance.constants.DatabaseType; | ||
| 8 | -import com.nctigba.observability.instance.handler.session.SessionHandler; | ||
| 9 | -import lombok.extern.slf4j.Slf4j; | ||
| 10 | -import org.springframework.aop.support.AopUtils; | ||
| 11 | -import org.springframework.stereotype.Component; | ||
| 12 | - | ||
| 13 | -import javax.annotation.PostConstruct; | ||
| 14 | -import javax.annotation.Resource; | ||
| 15 | -import java.util.List; | ||
| 16 | -import java.util.Map; | ||
| 17 | -import java.util.function.Function; | ||
| 18 | -import java.util.stream.Collectors; | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | -public class SessionHandlerFactory { | ||
| 23 | - private Map<String, SessionHandler> handlerMap; | ||
| 24 | - | ||
| 25 | - | ||
| 26 | - private List<SessionHandler> handlerList; | ||
| 27 | - | ||
| 28 | - | ||
| 29 | - public void init() { | ||
| 30 | - handlerMap = handlerList.stream() | ||
| 31 | - .collect(Collectors.toMap(SessionHandler::getDatabaseType, Function.identity())); | ||
| 32 | - log.info("load TopSQLHandler complete. entity:{}", JSON.toJSONString(handlerMap.entrySet().stream() | ||
| 33 | - .collect(Collectors.toMap(Map.Entry::getKey, entity -> AopUtils.getTargetClass(entity.getValue()))))); | ||
| 34 | - | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - /** | ||
| 38 | - * get TopSQL handler for different types of databases | ||
| 39 | - * | ||
| 40 | - * databaseType database type | ||
| 41 | - * TopSQL handler | ||
| 42 | - */ | ||
| 43 | - public SessionHandler getInstance(String databaseType) { | ||
| 44 | - return handlerMap.containsKey(databaseType) ? handlerMap.get(databaseType) | ||
| 45 | - : handlerMap.get(DatabaseType.DEFAULT.getDbType()); | ||
| 46 | - } | ||
| 47 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/TopSQLHandlerFactory.java+0-56
| @@ -1,56 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.factory; | ||
| 5 | - | ||
| 6 | -import com.alibaba.fastjson.JSON; | ||
| 7 | -import com.nctigba.observability.instance.constants.DatabaseType; | ||
| 8 | -import com.nctigba.observability.instance.handler.topsql.TopSQLHandler; | ||
| 9 | - | ||
| 10 | -import lombok.extern.slf4j.Slf4j; | ||
| 11 | -import org.springframework.aop.support.AopUtils; | ||
| 12 | -import org.springframework.stereotype.Component; | ||
| 13 | - | ||
| 14 | -import javax.annotation.PostConstruct; | ||
| 15 | -import javax.annotation.Resource; | ||
| 16 | -import java.util.List; | ||
| 17 | -import java.util.Map; | ||
| 18 | -import java.util.function.Function; | ||
| 19 | -import java.util.stream.Collectors; | ||
| 20 | - | ||
| 21 | -/** | ||
| 22 | - * <p> | ||
| 23 | - * store TopSQL Handlers | ||
| 24 | - * </p> | ||
| 25 | - * | ||
| 26 | - * zhanggr.com.cn | ||
| 27 | - * 2022/9/15 15:58 | ||
| 28 | - */ | ||
| 29 | - | ||
| 30 | - | ||
| 31 | -public class TopSQLHandlerFactory { | ||
| 32 | - private Map<String, TopSQLHandler> handlerMap; | ||
| 33 | - | ||
| 34 | - | ||
| 35 | - private List<TopSQLHandler> handlerList; | ||
| 36 | - | ||
| 37 | - | ||
| 38 | - public void init() { | ||
| 39 | - handlerMap = handlerList.stream() | ||
| 40 | - .collect(Collectors.toMap(TopSQLHandler::getDatabaseType, Function.identity())); | ||
| 41 | - log.info("load TopSQLHandler complete. entity:{}", JSON.toJSONString(handlerMap.entrySet().stream() | ||
| 42 | - .collect(Collectors.toMap(Map.Entry::getKey, entity -> AopUtils.getTargetClass(entity.getValue()))))); | ||
| 43 | - | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - /** | ||
| 47 | - * get TopSQL handler for different types of databases | ||
| 48 | - * | ||
| 49 | - * databaseType database type | ||
| 50 | - * TopSQL handler | ||
| 51 | - */ | ||
| 52 | - public TopSQLHandler getInstance(String databaseType) { | ||
| 53 | - return handlerMap.containsKey(databaseType) ? handlerMap.get(databaseType) | ||
| 54 | - : handlerMap.get(DatabaseType.DEFAULT.getDbType()); | ||
| 55 | - } | ||
| 56 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/monitoring/MonitoringHandler.java+0-66
| @@ -1,66 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.handler.monitoring; | ||
| 5 | - | ||
| 6 | -import java.util.List; | ||
| 7 | -import java.util.Map; | ||
| 8 | - | ||
| 9 | -import com.nctigba.observability.instance.model.monitoring.MonitoringMetric; | ||
| 10 | -import com.nctigba.observability.instance.model.monitoring.MonitoringParam; | ||
| 11 | - | ||
| 12 | -public interface MonitoringHandler { | ||
| 13 | - /** | ||
| 14 | - * Monitoring system type | ||
| 15 | - * | ||
| 16 | - * | ||
| 17 | - */ | ||
| 18 | - String getMonitorType(); | ||
| 19 | - | ||
| 20 | - /** | ||
| 21 | - * Get time period monitoring data | ||
| 22 | - * | ||
| 23 | - * query | ||
| 24 | - * start prot | ||
| 25 | - * end Connect Users | ||
| 26 | - * step Connection password | ||
| 27 | - * Indicator set | ||
| 28 | - */ | ||
| 29 | - List<MonitoringMetric> rangeQuery(String query, String start, String end, String step); | ||
| 30 | - | ||
| 31 | - /** | ||
| 32 | - * Get the monitoring data of the specified time node | ||
| 33 | - * | ||
| 34 | - * query ip | ||
| 35 | - * time Specify time | ||
| 36 | - * Indicator set | ||
| 37 | - */ | ||
| 38 | - List<MonitoringMetric> pointQuery(String query, String time); | ||
| 39 | - | ||
| 40 | - /** | ||
| 41 | - * Convert indicator data format to table | ||
| 42 | - * | ||
| 43 | - * rangeMetricList Range Indicator List | ||
| 44 | - * param Indicator Query Parameters | ||
| 45 | - * Indicator set in tabular format | ||
| 46 | - */ | ||
| 47 | - List<Object> metricToTable(List<MonitoringMetric> rangeMetricList, MonitoringParam param); | ||
| 48 | - | ||
| 49 | - /** | ||
| 50 | - * Convert indicator data format to line chart | ||
| 51 | - * | ||
| 52 | - * rangeMetricList Range Indicator List | ||
| 53 | - * param query parameters | ||
| 54 | - * Indicator set in polyline format | ||
| 55 | - */ | ||
| 56 | - List<Object> metricToLine(List<MonitoringMetric> rangeMetricList, MonitoringParam param); | ||
| 57 | - | ||
| 58 | - /** | ||
| 59 | - * Sort the monitoring data | ||
| 60 | - * | ||
| 61 | - * tableList Table Data | ||
| 62 | - * param Monitoring query parameters | ||
| 63 | - * Sorted indicator set | ||
| 64 | - */ | ||
| 65 | - List<Map<String, String>> sortList(List<Object> tableList, MonitoringParam param); | ||
| 66 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/monitoring/NormalMonitoringHandler.java+0-386
| @@ -1,386 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.handler.monitoring; | ||
| 5 | - | ||
| 6 | -import java.math.BigDecimal; | ||
| 7 | -import java.text.SimpleDateFormat; | ||
| 8 | -import java.util.ArrayList; | ||
| 9 | -import java.util.Collections; | ||
| 10 | -import java.util.Date; | ||
| 11 | -import java.util.HashMap; | ||
| 12 | -import java.util.HashSet; | ||
| 13 | -import java.util.LinkedHashMap; | ||
| 14 | -import java.util.List; | ||
| 15 | -import java.util.Map; | ||
| 16 | -import java.util.Set; | ||
| 17 | -import java.util.stream.Collectors; | ||
| 18 | - | ||
| 19 | -import org.apache.commons.lang3.ObjectUtils; | ||
| 20 | -import org.apache.commons.lang3.StringUtils; | ||
| 21 | -import org.opengauss.admin.common.exception.CustomException; | ||
| 22 | -import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 23 | -import org.springframework.beans.factory.annotation.Autowired; | ||
| 24 | -import org.springframework.stereotype.Component; | ||
| 25 | -import org.springframework.util.CollectionUtils; | ||
| 26 | -import org.springframework.web.util.UriComponentsBuilder; | ||
| 27 | - | ||
| 28 | -import com.alibaba.fastjson.JSON; | ||
| 29 | -import com.alibaba.fastjson.JSONArray; | ||
| 30 | -import com.alibaba.fastjson.JSONObject; | ||
| 31 | -import com.alibaba.fastjson.TypeReference; | ||
| 32 | -import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 33 | -import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 34 | -import com.nctigba.observability.instance.constants.CommonConstants; | ||
| 35 | -import com.nctigba.observability.instance.constants.MonitoringConstants; | ||
| 36 | -import com.nctigba.observability.instance.constants.MonitoringType; | ||
| 37 | -import com.nctigba.observability.instance.entity.NctigbaEnv; | ||
| 38 | -import com.nctigba.observability.instance.entity.NctigbaEnv.envType; | ||
| 39 | -import com.nctigba.observability.instance.mapper.NctigbaEnvMapper; | ||
| 40 | -import com.nctigba.observability.instance.model.monitoring.MonitoringMetric; | ||
| 41 | -import com.nctigba.observability.instance.model.monitoring.MonitoringParam; | ||
| 42 | -import com.nctigba.observability.instance.util.HttpUtils; | ||
| 43 | - | ||
| 44 | -import cn.hutool.core.map.MapUtil; | ||
| 45 | -import lombok.extern.slf4j.Slf4j; | ||
| 46 | - | ||
| 47 | - | ||
| 48 | - | ||
| 49 | -public class NormalMonitoringHandler implements MonitoringHandler { | ||
| 50 | - | ||
| 51 | - protected NctigbaEnvMapper envMapper; | ||
| 52 | - | ||
| 53 | - | ||
| 54 | - protected HostFacade hostFacade; | ||
| 55 | - | ||
| 56 | - private String getPrometheusUrl() { | ||
| 57 | - var env = envMapper.selectOne(Wrappers.<NctigbaEnv>lambdaQuery().eq(NctigbaEnv::getType, envType.PROMETHEUS)); | ||
| 58 | - if (env == null) | ||
| 59 | - throw new RuntimeException("Prometheus not found"); | ||
| 60 | - var host = hostFacade.getById(env.getHostid()); | ||
| 61 | - return "http://" + host.getPublicIp() + ":" + env.getPort(); | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - | ||
| 65 | - public String getMonitorType() { | ||
| 66 | - return MonitoringType.DEFAULT.getMonitoringType(); | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - /** | ||
| 70 | - * Querying prometheus data for a period of time | ||
| 71 | - * | ||
| 72 | - * query Indicator parameters | ||
| 73 | - * start start time | ||
| 74 | - * end End time | ||
| 75 | - * step step | ||
| 76 | - * List<MonitoringMetric> | ||
| 77 | - */ | ||
| 78 | - | ||
| 79 | - public List<MonitoringMetric> rangeQuery(String query, String start, String end, String step) { | ||
| 80 | - List<MonitoringMetric> monitoringMetricList = null; | ||
| 81 | - UriComponentsBuilder builder = UriComponentsBuilder | ||
| 82 | - .fromHttpUrl(getPrometheusUrl() + MonitoringConstants.PROMETHEUS_QUERY_RANGE); | ||
| 83 | - builder.queryParam("query", query); | ||
| 84 | - builder.queryParam("start", start); | ||
| 85 | - builder.queryParam("end", end); | ||
| 86 | - builder.queryParam("step", step); | ||
| 87 | - String url = builder.build().encode().toUriString(); | ||
| 88 | - log.info("request url:[{}]", url); | ||
| 89 | - try { | ||
| 90 | - String response = HttpUtils.sendGet(url.replace("+", "%2B"), ""); | ||
| 91 | - JSONObject responseJson = JSONObject.parseObject(response); | ||
| 92 | - if ("success".equals(responseJson.get("status"))) { | ||
| 93 | - JSONObject dataJson = JSONObject.parseObject(responseJson.getString("data")); | ||
| 94 | - monitoringMetricList = JSON.parseArray(dataJson.getString("result"), MonitoringMetric.class); | ||
| 95 | - } else { | ||
| 96 | - log.info("query prometheus range data failed ! please check the log, the error message is:{}", | ||
| 97 | - response); | ||
| 98 | - throw new CustomException(""); | ||
| 99 | - } | ||
| 100 | - } catch (CustomException e) { | ||
| 101 | - log.error(e.getMessage()); | ||
| 102 | - throw new CustomException("create URI failed"); | ||
| 103 | - } | ||
| 104 | - return monitoringMetricList; | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - /** | ||
| 108 | - * Query prometheus data at a specified time | ||
| 109 | - * | ||
| 110 | - * query Indicator parameters | ||
| 111 | - * time Specify the timestamp. The default is the current system time of | ||
| 112 | - * prometheus | ||
| 113 | - * List<MonitoringMetric> | ||
| 114 | - */ | ||
| 115 | - | ||
| 116 | - public List<MonitoringMetric> pointQuery(String query, String time) { | ||
| 117 | - List<MonitoringMetric> monitoringMetricList; | ||
| 118 | - String baseUrl = getPrometheusUrl() + MonitoringConstants.PROMETHEUS_QUERY_POINT; | ||
| 119 | - UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl); | ||
| 120 | - builder.queryParam("query", query); | ||
| 121 | - if (StringUtils.isNotEmpty(time)) { | ||
| 122 | - builder.queryParam("time", time); | ||
| 123 | - } | ||
| 124 | - String url = builder.build().encode().toUriString(); | ||
| 125 | - log.info("request url:[{}]", url); | ||
| 126 | - try { | ||
| 127 | - String response = HttpUtils.sendGet(url.replace("+", "%2B"), ""); | ||
| 128 | - JSONObject responseJson = JSONObject.parseObject(response); | ||
| 129 | - if ("success".equals(responseJson.get("status"))) { | ||
| 130 | - JSONObject dataJson = JSONObject.parseObject(responseJson.getString("data")); | ||
| 131 | - monitoringMetricList = JSON.parseArray(dataJson.getString("result"), MonitoringMetric.class); | ||
| 132 | - } else { | ||
| 133 | - log.info("query prometheus range data failed ! please check the log, the error message is:{}", | ||
| 134 | - response); | ||
| 135 | - throw new CustomException(""); | ||
| 136 | - } | ||
| 137 | - } catch (CustomException e) { | ||
| 138 | - log.error(e.getMessage()); | ||
| 139 | - throw new CustomException("create URI failed"); | ||
| 140 | - } | ||
| 141 | - return monitoringMetricList; | ||
| 142 | - } | ||
| 143 | - | ||
| 144 | - | ||
| 145 | - public List<Object> metricToTable(List<MonitoringMetric> metricList, MonitoringParam param) { | ||
| 146 | - log.info("Monitoring data starts to be converted into tabular data"); | ||
| 147 | - List<Object> tableList = null; | ||
| 148 | - // Get timestamp data in descending order | ||
| 149 | - Map<String, List<Object>> timeMetricMap = transToTimeList(metricList); | ||
| 150 | - if (MapUtil.isEmpty(timeMetricMap)) { | ||
| 151 | - log.error("prometheus to table: data is empty!"); | ||
| 152 | - throw new CustomException("601", 601); | ||
| 153 | - } | ||
| 154 | - List<Object> data = new ArrayList<>(); | ||
| 155 | - List<String> columnNames = new ArrayList<>(); | ||
| 156 | - for (List<Object> timeMetricList : timeMetricMap.values()) { | ||
| 157 | - List<Map<String, Object>> timeMertic = JSON.parseObject(JSON.toJSONString(timeMetricList), | ||
| 158 | - new TypeReference<List<Map<String, Object>>>() { | ||
| 159 | - }); | ||
| 160 | - ArrayList<ArrayList<String>> result = new ArrayList<>(); | ||
| 161 | - // Record the metricData length | ||
| 162 | - int max = 0; | ||
| 163 | - for (Map<String, Object> timeMetricObj : timeMertic) { | ||
| 164 | - ArrayList<String> metricData = JSON.parseObject(timeMetricObj.get("metricData").toString(), | ||
| 165 | - new TypeReference<ArrayList<String>>() { | ||
| 166 | - }); | ||
| 167 | - if (ObjectUtils.isNotEmpty(metricData) && metricData.size() > 0) { | ||
| 168 | - max = Math.max(max, metricData.size()); | ||
| 169 | - String title = timeMetricObj.get("metricName").toString(); | ||
| 170 | - if (!columnNames.contains(title)) { | ||
| 171 | - columnNames.add(title); | ||
| 172 | - } | ||
| 173 | - result.add(metricData); | ||
| 174 | - } | ||
| 175 | - } | ||
| 176 | - // Store the converted structure into data in turn | ||
| 177 | - for (int i = 0; i < max; i++) { | ||
| 178 | - Map<String, Object> map = new HashMap<>(); | ||
| 179 | - for (int j = 0; j < columnNames.size(); j++) { | ||
| 180 | - String title = columnNames.get(j); | ||
| 181 | - map.put(title, result.get(j).get(i)); | ||
| 182 | - } | ||
| 183 | - data.add(map); | ||
| 184 | - } | ||
| 185 | - } | ||
| 186 | - tableList = data; | ||
| 187 | - // Determine whether to sort | ||
| 188 | - if (StringUtils.isNotEmpty(param.getField())) { | ||
| 189 | - log.info("Start of monitoring data sorting"); | ||
| 190 | - List<Map<String, String>> tableSortList = this.sortList(tableList, param); | ||
| 191 | - JSONArray jsonArray = new JSONArray(); | ||
| 192 | - jsonArray.addAll(tableSortList); | ||
| 193 | - log.info("Monitoring data sorting completed"); | ||
| 194 | - return jsonArray.toJavaList(Object.class); | ||
| 195 | - } | ||
| 196 | - log.info("Monitoring data completion converted to tabular data"); | ||
| 197 | - return tableList; | ||
| 198 | - } | ||
| 199 | - | ||
| 200 | - private Map<String, List<Object>> transToTimeList(List<MonitoringMetric> metricList) { | ||
| 201 | - if (CollectionUtils.isEmpty(metricList)) { | ||
| 202 | - log.error("transToTimeList: prometheus data is empty!"); | ||
| 203 | - throw new CustomException("601", 601); | ||
| 204 | - } | ||
| 205 | - // 1. Processing of original data and extracting duplicates__ name__ Value Data | ||
| 206 | - Map<String, List<MonitoringMetric>> metricMap = new HashMap<>(); | ||
| 207 | - for (MonitoringMetric metric : metricList) { | ||
| 208 | - String metricName = metric.getMetric().getString(CommonConstants.NAME); | ||
| 209 | - List<MonitoringMetric> list; | ||
| 210 | - if (metricMap.containsKey(metricName)) { | ||
| 211 | - list = metricMap.get(metricName); | ||
| 212 | - } else { | ||
| 213 | - list = new ArrayList<>(); | ||
| 214 | - } | ||
| 215 | - list.add(metric); | ||
| 216 | - metricMap.put(metricName, list); | ||
| 217 | - } | ||
| 218 | - // 2. Process the data and return it in the form of a map. The key is a | ||
| 219 | - // timestamp, the value is a metric list, and the timeMetricMap is used to store | ||
| 220 | - // the processed data | ||
| 221 | - if (metricMap.isEmpty()) { | ||
| 222 | - log.error("The first processing of the raw data results in a null result!"); | ||
| 223 | - throw new CustomException("601", 601); | ||
| 224 | - } | ||
| 225 | - Map<String, List<Object>> timeMetricMap = new HashMap<>(); | ||
| 226 | - for (List<MonitoringMetric> metrics : metricMap.values()) { | ||
| 227 | - for (MonitoringMetric metric : metrics) { | ||
| 228 | - // Get the corresponding field | ||
| 229 | - String metricName = metric.getMetric().getString(CommonConstants.NAME); | ||
| 230 | - String warningMsg = metric.getMetric().getString("warning_msg"); | ||
| 231 | - Object metricData = JSON.parse(metric.getMetric().getString("table")); | ||
| 232 | - JSONArray values = metric.getValues(); | ||
| 233 | - for (Object value : values) { | ||
| 234 | - JSONArray valueArray = JSONArray.parseArray(JSONObject.toJSON(value).toString()); | ||
| 235 | - List<Object> list; | ||
| 236 | - String curTimeStamp = valueArray.get(0).toString(); | ||
| 237 | - if (timeMetricMap.containsKey(curTimeStamp)) { | ||
| 238 | - list = timeMetricMap.get(curTimeStamp); | ||
| 239 | - } else { | ||
| 240 | - list = new ArrayList<>(); | ||
| 241 | - } | ||
| 242 | - Map<String, Object> map = new HashMap<>(); | ||
| 243 | - map.put("metricData", metricData); | ||
| 244 | - map.put("metricName", metricName); | ||
| 245 | - map.put("warning_msg", warningMsg); | ||
| 246 | - list.add(map); | ||
| 247 | - timeMetricMap.put(curTimeStamp, list); | ||
| 248 | - } | ||
| 249 | - } | ||
| 250 | - } | ||
| 251 | - // Sort in descending order | ||
| 252 | - LinkedHashMap<String, List<Object>> result = new LinkedHashMap<>(); | ||
| 253 | - timeMetricMap.entrySet().stream().sorted((c1, c2) -> c2.getKey().compareTo(c1.getKey())) | ||
| 254 | - .forEachOrdered(x -> result.put(x.getKey(), x.getValue())); | ||
| 255 | - return result; | ||
| 256 | - } | ||
| 257 | - | ||
| 258 | - | ||
| 259 | - public List<Object> metricToLine(List<MonitoringMetric> metricList, MonitoringParam param) { | ||
| 260 | - log.info("Monitoring data starts to be converted into line data"); | ||
| 261 | - if (CollectionUtils.isEmpty(metricList)) { | ||
| 262 | - return Collections.singletonList(metricList); | ||
| 263 | - } | ||
| 264 | - List<Map<String, Object>> result = new ArrayList<>(); | ||
| 265 | - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | ||
| 266 | - for (MonitoringMetric metric : metricList) { | ||
| 267 | - // Index name | ||
| 268 | - String metricName = metric.getMetric().getString(CommonConstants.NAME); | ||
| 269 | - if (StringUtils.isNotBlank(param.getLegendName())) { | ||
| 270 | - metricName = metric.getMetric().getString(param.getLegendName()); | ||
| 271 | - } | ||
| 272 | - JSONArray lineValues = metric.getValues(); | ||
| 273 | - Map<String, Object> item = new HashMap<>(); | ||
| 274 | - // Get data of time and value | ||
| 275 | - List<String> timeList = new ArrayList<>(); | ||
| 276 | - List<String> dataList = new ArrayList<>(); | ||
| 277 | - for (Object value : lineValues) { | ||
| 278 | - JSONArray valueArray = JSONArray.parseArray(JSONObject.toJSON(value).toString()); | ||
| 279 | - if (valueArray.size() > 1) { | ||
| 280 | - // Convert timestamp to date format | ||
| 281 | - String time = simpleDateFormat | ||
| 282 | - .format(new Date(Long.parseLong(valueArray.get(0).toString()) * 1000)); | ||
| 283 | - timeList.add(time); | ||
| 284 | - dataList.add(valueArray.get(1).toString()); | ||
| 285 | - } | ||
| 286 | - } | ||
| 287 | - | ||
| 288 | - // Encapsulated into the echarts data | ||
| 289 | - item.put("name", metricName); | ||
| 290 | - item.put("data", dataList); | ||
| 291 | - item.put("time", timeList); | ||
| 292 | - item.put("type", "line"); | ||
| 293 | - | ||
| 294 | - result.add(item); | ||
| 295 | - } | ||
| 296 | - log.info("Monitoring data completed convert to line data"); | ||
| 297 | - return Collections.singletonList(result); | ||
| 298 | - } | ||
| 299 | - | ||
| 300 | - | ||
| 301 | - public List<Map<String, String>> sortList(List<Object> tableList, MonitoringParam param) { | ||
| 302 | - String field = param.getField(); | ||
| 303 | - if (StringUtils.isEmpty(field)) { | ||
| 304 | - log.error("field cannot be null!"); | ||
| 305 | - throw new CustomException("field cannot be null!", 400); | ||
| 306 | - } | ||
| 307 | - if (StringUtils.isEmpty(param.getOrder())) { | ||
| 308 | - log.error("order cannot be null!"); | ||
| 309 | - throw new CustomException("order cannot be null!", 400); | ||
| 310 | - } | ||
| 311 | - if (ObjectUtils.isEmpty(tableList)) { | ||
| 312 | - log.error("result is null!"); | ||
| 313 | - throw new CustomException("result cannot be null!", 400); | ||
| 314 | - } | ||
| 315 | - // Sort by field | ||
| 316 | - List<Map<String, String>> listMapSort = JSON.parseObject(JSON.toJSONString(tableList), | ||
| 317 | - new TypeReference<List<Map<String, String>>>() { | ||
| 318 | - }); | ||
| 319 | - // Sorting is divided into numerical type and time interval type | ||
| 320 | - String firstValue = listMapSort.get(0).get(field); | ||
| 321 | - if (firstValue.contains(":")) { | ||
| 322 | - // Interval type | ||
| 323 | - listMapSort = listMapSort.stream() | ||
| 324 | - .sorted((x, y) -> (int) (resolutionInterval(y.get(field)) - resolutionInterval(x.get(field)))) | ||
| 325 | - .collect(Collectors.toList()); | ||
| 326 | - | ||
| 327 | - } else { | ||
| 328 | - // Digital | ||
| 329 | - listMapSort = listMapSort.stream() | ||
| 330 | - .sorted((x, y) -> BigDecimal.valueOf(Double.parseDouble(y.get(field))) | ||
| 331 | - .compareTo(BigDecimal.valueOf(Double.parseDouble(x.get(field))))) | ||
| 332 | - .collect(Collectors.toList()); | ||
| 333 | - } | ||
| 334 | - // De duplication according to filter | ||
| 335 | - if (StringUtils.isNotEmpty(param.getFilter())) { | ||
| 336 | - listMapSort = distinctByKey(listMapSort, param.getFilter()); | ||
| 337 | - } | ||
| 338 | - // Intercept the first 10 lines of listMapSort | ||
| 339 | - int listMapSortLength = listMapSort.size(); | ||
| 340 | - if (listMapSortLength <= 10) { | ||
| 341 | - return listMapSort; | ||
| 342 | - } | ||
| 343 | - // Desc in reverse order, the default is positive order | ||
| 344 | - if (!"desc".equalsIgnoreCase(param.getOrder())) { | ||
| 345 | - Collections.reverse(listMapSort); | ||
| 346 | - } | ||
| 347 | - log.info("monitoring data sort finish! sortType:{}", param.getOrder()); | ||
| 348 | - return listMapSort.subList(0, 10); | ||
| 349 | - } | ||
| 350 | - | ||
| 351 | - private List<Map<String, String>> distinctByKey(List<Map<String, String>> listMapSort, String filter) { | ||
| 352 | - Set<String> set = new HashSet<>(); | ||
| 353 | - List<Map<String, String>> newListMapSort = new ArrayList<>(); | ||
| 354 | - for (Map<String, String> stringStringMap : listMapSort) { | ||
| 355 | - String text = stringStringMap.get(filter); | ||
| 356 | - if (!set.contains(text)) { | ||
| 357 | - set.add(text); | ||
| 358 | - newListMapSort.add(stringStringMap); | ||
| 359 | - } | ||
| 360 | - } | ||
| 361 | - log.info("monitoring data distinct finish! distinct filed:{}", filter); | ||
| 362 | - return newListMapSort; | ||
| 363 | - } | ||
| 364 | - | ||
| 365 | - private long resolutionInterval(String interval) { | ||
| 366 | - if (StringUtils.isEmpty(interval)) { | ||
| 367 | - return 0; | ||
| 368 | - } | ||
| 369 | - long stamp = 0; | ||
| 370 | - String time = interval; | ||
| 371 | - if (interval.contains(",")) { | ||
| 372 | - String[] intervalArr = interval.split(","); | ||
| 373 | - String timeDay = intervalArr[0].trim(); | ||
| 374 | - time = intervalArr[1].trim(); | ||
| 375 | - long timeDayNumber = Long.parseLong(timeDay.substring(0, timeDay.indexOf("day")).trim()); | ||
| 376 | - stamp = stamp + timeDayNumber * 86400; | ||
| 377 | - } | ||
| 378 | - if (interval.contains(".")) { | ||
| 379 | - String[] timeArr = time.split(".")[0].split(":"); | ||
| 380 | - int timeCount = Integer.parseInt(timeArr[0]) * 3600 + Integer.parseInt(timeArr[1]) * 60 | ||
| 381 | - + Integer.parseInt(timeArr[2]); | ||
| 382 | - stamp = stamp + timeCount; | ||
| 383 | - } | ||
| 384 | - return stamp; | ||
| 385 | - } | ||
| 386 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/session/SessionHandler.java+0-36
| @@ -1,36 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.handler.session; | ||
| 5 | - | ||
| 6 | -import com.alibaba.fastjson.JSONObject; | ||
| 7 | -import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | ||
| 8 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | ||
| 9 | - | ||
| 10 | -import java.io.Closeable; | ||
| 11 | -import java.sql.Connection; | ||
| 12 | -import java.util.List; | ||
| 13 | - | ||
| 14 | -public interface SessionHandler { | ||
| 15 | - /** | ||
| 16 | - * target database type | ||
| 17 | - * database type | ||
| 18 | - */ | ||
| 19 | - String getDatabaseType(); | ||
| 20 | - | ||
| 21 | - Connection getConnection(InstanceNodeInfo nodeInfo); | ||
| 22 | - | ||
| 23 | - void close(Connection connection); | ||
| 24 | - | ||
| 25 | - JSONObject detailGeneral(Connection conn, String sessionid); | ||
| 26 | - | ||
| 27 | - List<DetailStatisticDto> detailStatistic(Connection conn, String sessionid); | ||
| 28 | - | ||
| 29 | - List<JSONObject> detailWaiting(Connection conn, String sessionid); | ||
| 30 | - | ||
| 31 | - List<JSONObject> detailBlockTree(Connection conn, String sessionid); | ||
| 32 | - | ||
| 33 | - JSONObject simpleStatistic(Connection conn); | ||
| 34 | - | ||
| 35 | - List<JSONObject> longTxc(Connection conn); | ||
| 36 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/topsql/OpenGaussTopSQLHandler.java+0-719
| @@ -1,719 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.handler.topsql; | ||
| 6 | - | ||
| 7 | -import com.alibaba.fastjson.JSON; | ||
| 8 | -import com.alibaba.fastjson.JSONArray; | ||
| 9 | -import com.alibaba.fastjson.JSONObject; | ||
| 10 | -import com.nctigba.observability.instance.constants.CommonConstants; | ||
| 11 | -import com.nctigba.observability.instance.constants.DatabaseType; | ||
| 12 | -import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; | ||
| 13 | -import com.nctigba.observability.instance.dto.topsql.TopSQLNowReq; | ||
| 14 | -import com.nctigba.observability.instance.model.ExecutionPlan; | ||
| 15 | -import com.nctigba.observability.instance.model.IndexAdvice; | ||
| 16 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | ||
| 17 | -import com.nctigba.observability.instance.service.ClusterManager; | ||
| 18 | -import lombok.RequiredArgsConstructor; | ||
| 19 | -import lombok.extern.slf4j.Slf4j; | ||
| 20 | -import org.apache.commons.lang3.ObjectUtils; | ||
| 21 | -import org.apache.commons.lang3.StringUtils; | ||
| 22 | -import org.opengauss.admin.common.exception.CustomException; | ||
| 23 | -import org.springframework.stereotype.Component; | ||
| 24 | - | ||
| 25 | -import java.sql.Connection; | ||
| 26 | -import java.sql.PreparedStatement; | ||
| 27 | -import java.sql.ResultSet; | ||
| 28 | -import java.sql.SQLException; | ||
| 29 | -import java.sql.Statement; | ||
| 30 | -import java.sql.Timestamp; | ||
| 31 | -import java.util.ArrayList; | ||
| 32 | -import java.util.Arrays; | ||
| 33 | -import java.util.LinkedList; | ||
| 34 | -import java.util.List; | ||
| 35 | - | ||
| 36 | -/** | ||
| 37 | - * <p> | ||
| 38 | - * TopSQL business of openGauss | ||
| 39 | - * </p> | ||
| 40 | - * | ||
| 41 | - * zhanggr.com.cn | ||
| 42 | - * 2022/9/15 14:39 | ||
| 43 | - */ | ||
| 44 | - | ||
| 45 | - | ||
| 46 | - | ||
| 47 | -public class OpenGaussTopSQLHandler implements TopSQLHandler { | ||
| 48 | - private static final String TEST_SQL = "select 1"; | ||
| 49 | - private static final String TOP_SQL_LIST_SQL = "select unique_query_id,debug_query_id,db_name,schema_name,user_name,application_name,start_time,finish_time,db_time,cpu_time,execution_time from dbe_perf.statement_history where debug_query_id != 0 and finish_time >= ? and finish_time <= ? order by %s desc,execution_time desc,cpu_time desc,db_time desc limit 10"; | ||
| 50 | - private static final String TOP_SQL_Now_SQL = "select round(extract(epoch FROM (now() - query_start)),2) as duration,query_start,unique_sql_id,datname ,usename,application_name ,datid,pid,sessionid,usesysid,usename,client_addr ,client_hostname,client_port,backend_start ,xact_start ,state_change ,waiting,enqueue,state ,resource_pool,query_id ,query ,connection_info,trace_id\n" | ||
| 51 | - + "from pg_stat_activity where query_start is not null and unique_sql_id != 0 and duration != 0 order by (now() - query_start) desc limit 10"; | ||
| 52 | - // private static final String TOP_SQL_LIST_SQL = "select | ||
| 53 | - // unique_query_id,debug_query_id,db_name,schema_name,user_name,application_name,start_time,finish_time,db_time,cpu_time,execution_time | ||
| 54 | - // from dbe_perf.statement_history where debug_query_id != 0 and finish_time >= | ||
| 55 | - // ? and finish_time <= ? order by %s desc,execution_time desc,cpu_time | ||
| 56 | - // desc,db_time desc"; | ||
| 57 | - private static final String PRE_CHECK_SET_SQL = "select name,setting from pg_settings where name in('enable_stmt_track','enable_resource_track','track_stmt_stat_level')"; | ||
| 58 | - private static final String STATISTICAL_INFO_SQL = "select query,debug_query_id,unique_query_id,db_name,schema_name,\n" | ||
| 59 | - + "substring(start_time,0,20) start_time,substring(finish_time,0,20) finish_time,\n" | ||
| 60 | - + "user_name,application_name,client_addr||':'||client_port socket,\n" | ||
| 61 | - + "n_returned_rows,n_tuples_fetched,n_tuples_returned,n_tuples_inserted,n_tuples_updated,n_tuples_deleted,lock_count,lock_wait_count,lock_max_count,\n" | ||
| 62 | - + "(case when n_blocks_fetched=0 then '-' else substring((n_blocks_hit/n_blocks_fetched)*100,0,6)||'%' end) as blocks_hit_rate,\n" | ||
| 63 | - + "net_send_info::json->'size' net_send_info_size,net_recv_info::json->'size' net_recv_info_size,\n" | ||
| 64 | - + "net_stream_send_info::json->'size' net_stream_send_info_size,net_stream_recv_info::json->'size' net_stream_recv_info_size,\n" | ||
| 65 | - + "net_send_info::json->'n_calls' net_send_info_calls,net_recv_info::json->'n_calls' net_recv_info_calls,\n" | ||
| 66 | - + "net_stream_send_info::json->'n_calls' net_stream_send_info_calls,net_stream_recv_info::json->'n_calls' net_stream_recv_info_calls,\n" | ||
| 67 | - + "net_send_info::json->'time' net_send_info_time,net_recv_info::json->'time' net_recv_info_time,\n" | ||
| 68 | - + "net_stream_send_info::json->'time' net_stream_send_info_time,net_stream_recv_info::json->'time' net_stream_recv_info_time,\n" | ||
| 69 | - + "n_soft_parse,n_hard_parse,db_time,cpu_time,(db_time-cpu_time) wait_time,lock_time,lock_wait_time,\n" | ||
| 70 | - + "execution_time,parse_time,plan_time,rewrite_time,pl_execution_time,pl_compilation_time,data_io_time\n" | ||
| 71 | - + "from dbe_perf.statement_history\n" + "where debug_query_id=?"; | ||
| 72 | - private static final String EXECUTION_PLAN_SQL = "select query_plan,query from dbe_perf.statement_history where debug_query_id=?;"; | ||
| 73 | - private static final String SELECT_QUERY_SQL = "select query from dbe_perf.statement_history where debug_query_id=?"; | ||
| 74 | - private static final String TABLE_METADATA_SQL = "select row_to_json(t) from (select schemaname,t1.relname,pg_relation_size(relid) object_size, relkind object_type,n_live_tup,n_dead_tup,\n" | ||
| 75 | - + "case when n_live_tup+n_dead_tup=0 then '0.00%' else round(n_dead_tup*100/(n_dead_tup+n_live_tup),2)||'%' end dead_tup_ratio,\n" | ||
| 76 | - + "last_vacuum,last_autovacuum,last_analyze,last_autoanalyze\n" + "from pg_catalog.pg_stat_all_tables t1\n" | ||
| 77 | - + "left join pg_catalog.pg_class t2 on t1.relid = t2.oid\n" + "where t1.relname=?)t"; | ||
| 78 | - private static final String INDEX_SQL = "select row_to_json(t) from (select c2.relname,i.indisprimary,i.indisunique,i.indisclustered,i.indisvalid,\n" | ||
| 79 | - + "i.indisreplident,pg_catalog.pg_get_indexdef(i.indexrelid,0,true) as def\n" | ||
| 80 | - + "from pg_catalog.pg_class c, pg_catalog.pg_class c2,pg_catalog.pg_index i\n" | ||
| 81 | - + "where c.relname=? and c.oid=i.indrelid and c2.oid=i.indexrelid) t"; | ||
| 82 | - private static final String TABLE_STRUCTURE_SQL = "select row_to_json(t) from (select a.attnum,a.attname,t.typname,a.attlen,a.attnotnull,b.description\n" | ||
| 83 | - + "from pg_catalog.pg_class c,pg_catalog.pg_attribute a\n" | ||
| 84 | - + "left outer join pg_catalog.pg_description b on a.attrelid=b.objoid and a.attnum=b.objsubid,pg_catalog.pg_type t\n" | ||
| 85 | - + "where c.relname=? and a.attnum>0 and a.attrelid=c.oid and a.atttypid=t.oid\n" + "order by a.attnum) t"; | ||
| 86 | - private static final String WORK_MEM_SQL = "select setting from pg_settings WHERE name = 'work_mem'"; | ||
| 87 | - private static final String PARTITION_LIST_SQL = "select partstrategy, partkey, relpages, reltuples, relallvisible, interval from pg_partition WHERE parttype = 'r'"; | ||
| 88 | - private int totalPlanRows = 0; | ||
| 89 | - private int totalPlanWidth = 0; | ||
| 90 | - private List<String> objectNameList = new ArrayList<>(); | ||
| 91 | - private final ClusterManager clusterManager; | ||
| 92 | - | ||
| 93 | - private boolean testConnection(Connection conn) { | ||
| 94 | - if (ObjectUtils.isNotEmpty(conn)) { | ||
| 95 | - try (PreparedStatement preparedStatement = conn.prepareStatement(TEST_SQL)) { | ||
| 96 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 97 | - return true; | ||
| 98 | - } | ||
| 99 | - } catch (Exception e) { | ||
| 100 | - log.error("test connection fail:{}", e.getMessage()); | ||
| 101 | - throw new CustomException(e.getMessage()); | ||
| 102 | - } | ||
| 103 | - } | ||
| 104 | - return false; | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - | ||
| 108 | - public Connection getConnection(InstanceNodeInfo nodeInfo) { | ||
| 109 | - Connection connection = clusterManager.getConnectionByNodeInfo(nodeInfo); | ||
| 110 | - if (!testConnection(connection)) { | ||
| 111 | - return null; | ||
| 112 | - } | ||
| 113 | - return connection; | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - | ||
| 117 | - public String getDatabaseType() { | ||
| 118 | - return DatabaseType.DEFAULT.getDbType(); | ||
| 119 | - } | ||
| 120 | - | ||
| 121 | - | ||
| 122 | - public List<JSONObject> getTopSQLList(InstanceNodeInfo nodeInfo, TopSQLListReq topSQLListReq) { | ||
| 123 | - // nodeInfo.setDbUserPassword(RSAUtil.decrypt(nodeInfo.getDbUserPassword())); | ||
| 124 | - List<JSONObject> list = new ArrayList<>(); | ||
| 125 | - try (Connection conn = getConnection(nodeInfo)) { | ||
| 126 | - if (conn == null) { | ||
| 127 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 128 | - } | ||
| 129 | - // param pre check | ||
| 130 | - if (topSqlListPreCheck(conn)) { | ||
| 131 | - return null; | ||
| 132 | - } | ||
| 133 | - try (PreparedStatement preparedStatement = conn.prepareStatement(String.format(TOP_SQL_LIST_SQL, | ||
| 134 | - StringUtils.isBlank(topSQLListReq.getOrderField()) ? "execution_time" | ||
| 135 | - : topSQLListReq.getOrderField()))) { | ||
| 136 | - preparedStatement.setTimestamp(1, Timestamp.valueOf(topSQLListReq.getStartTime())); | ||
| 137 | - preparedStatement.setTimestamp(2, Timestamp.valueOf(topSQLListReq.getFinishTime())); | ||
| 138 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 139 | - while (rs.next()) { | ||
| 140 | - JSONObject object = new JSONObject(); | ||
| 141 | - for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { | ||
| 142 | - object.put(rs.getMetaData().getColumnLabel(i), rs.getString(i)); | ||
| 143 | - } | ||
| 144 | - list.add(object); | ||
| 145 | - } | ||
| 146 | - } | ||
| 147 | - } | ||
| 148 | - } catch (SQLException e) { | ||
| 149 | - log.error("get TopSQL list fail:{}", e.getMessage()); | ||
| 150 | - throw new CustomException(e.getMessage()); | ||
| 151 | - } | ||
| 152 | - return list; | ||
| 153 | - } | ||
| 154 | - | ||
| 155 | - | ||
| 156 | - public List<JSONObject> getTopSQLNow(InstanceNodeInfo nodeInfo, TopSQLNowReq topSQLNowReq) { | ||
| 157 | - List<JSONObject> list = new ArrayList<>(); | ||
| 158 | - try (Connection conn = getConnection(nodeInfo)) { | ||
| 159 | - if (conn == null) { | ||
| 160 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 161 | - } | ||
| 162 | - // param pre check | ||
| 163 | - if (topSqlListPreCheck(conn)) { | ||
| 164 | - return null; | ||
| 165 | - } | ||
| 166 | - try (PreparedStatement preparedStatement = conn.prepareStatement(TOP_SQL_Now_SQL)) { | ||
| 167 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 168 | - while (rs.next()) { | ||
| 169 | - JSONObject object = new JSONObject(); | ||
| 170 | - for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { | ||
| 171 | - object.put(rs.getMetaData().getColumnLabel(i), rs.getString(i)); | ||
| 172 | - } | ||
| 173 | - list.add(object); | ||
| 174 | - } | ||
| 175 | - } | ||
| 176 | - } | ||
| 177 | - } catch (SQLException e) { | ||
| 178 | - log.error("get TopSQL list fail:{}", e.getMessage()); | ||
| 179 | - throw new CustomException(e.getMessage()); | ||
| 180 | - } | ||
| 181 | - return list; | ||
| 182 | - } | ||
| 183 | - | ||
| 184 | - /** | ||
| 185 | - * pre-check top sql list job | ||
| 186 | - * | ||
| 187 | - * connection connection info | ||
| 188 | - */ | ||
| 189 | - private boolean topSqlListPreCheck(Connection connection) { | ||
| 190 | - try (Statement statement = connection.createStatement()) { | ||
| 191 | - try (ResultSet rs = statement.executeQuery(PRE_CHECK_SET_SQL)) { | ||
| 192 | - while (rs.next()) { | ||
| 193 | - String name = rs.getString(1); | ||
| 194 | - String setting = rs.getString(2); | ||
| 195 | - // "track_stmt_stat_level".equalsIgnoreCase(name) && | ||
| 196 | - // StringUtils.startsWith(setting, "OFF") || "off".equalsIgnoreCase(setting) | ||
| 197 | - if (("enable_resource_track".equalsIgnoreCase(name) && "off".equalsIgnoreCase(setting)) | ||
| 198 | - || ("enable_stmt_track".equalsIgnoreCase(name) && "off".equalsIgnoreCase(setting)) | ||
| 199 | - || ("track_stmt_stat_level".equalsIgnoreCase(name) && dealTrackStmtStatLevel(setting))) { | ||
| 200 | - return true; | ||
| 201 | - } | ||
| 202 | - } | ||
| 203 | - } | ||
| 204 | - } catch (SQLException e) { | ||
| 205 | - log.error("pre check fail:{}", e.getMessage()); | ||
| 206 | - throw new CustomException(e.getMessage()); | ||
| 207 | - } | ||
| 208 | - return false; | ||
| 209 | - } | ||
| 210 | - | ||
| 211 | - private boolean dealTrackStmtStatLevel(String setting) { | ||
| 212 | - if (StringUtils.isEmpty(setting) || !setting.contains(",")) { | ||
| 213 | - return true; | ||
| 214 | - } | ||
| 215 | - String[] settingArr = setting.split(","); | ||
| 216 | - if ("off".equalsIgnoreCase(settingArr[0])) { | ||
| 217 | - return true; | ||
| 218 | - } | ||
| 219 | - return false; | ||
| 220 | - } | ||
| 221 | - | ||
| 222 | - | ||
| 223 | - public JSONObject getStatisticalInfo(InstanceNodeInfo nodeInfo, String sqlId) { | ||
| 224 | - // nodeInfo.setDbUserPassword(RSAUtil.decrypt(nodeInfo.getDbUserPassword())); | ||
| 225 | - JSONObject result = new JSONObject(); | ||
| 226 | - // get connection then execute query | ||
| 227 | - try (Connection connection = getConnection(nodeInfo)) { | ||
| 228 | - if (connection == null) { | ||
| 229 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 230 | - } | ||
| 231 | - // get prepared statement then put parameters in | ||
| 232 | - try (PreparedStatement preparedStatement = connection.prepareStatement(STATISTICAL_INFO_SQL)) { | ||
| 233 | - preparedStatement.setString(1, sqlId); | ||
| 234 | - // get result from result set | ||
| 235 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 236 | - while (rs.next()) { | ||
| 237 | - for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { | ||
| 238 | - result.put(rs.getMetaData().getColumnLabel(i), rs.getString(i)); | ||
| 239 | - } | ||
| 240 | - } | ||
| 241 | - } | ||
| 242 | - } | ||
| 243 | - } catch (SQLException e) { | ||
| 244 | - log.error("get TopSQL statistical info fail:{}", e.getMessage()); | ||
| 245 | - throw new CustomException(e.getMessage()); | ||
| 246 | - } | ||
| 247 | - return result; | ||
| 248 | - } | ||
| 249 | - | ||
| 250 | - public String getPeakMemory(String planStr) { | ||
| 251 | - if (StringUtils.isEmpty(planStr)) { | ||
| 252 | - return ""; | ||
| 253 | - } | ||
| 254 | - if (planStr.contains("Peak Memory")) { | ||
| 255 | - String[] planArr = planStr.split("Peak Memory:"); | ||
| 256 | - if (planArr.length > 1) { | ||
| 257 | - return planArr[1].substring(0, planArr[1].indexOf("(KB)")); | ||
| 258 | - } | ||
| 259 | - } | ||
| 260 | - return ""; | ||
| 261 | - } | ||
| 262 | - | ||
| 263 | - public String getWorkMem(Connection connection) throws SQLException { | ||
| 264 | - try (PreparedStatement preparedStatement = connection.prepareStatement(WORK_MEM_SQL)) { | ||
| 265 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 266 | - while (rs.next()) { | ||
| 267 | - return rs.getString(1); | ||
| 268 | - } | ||
| 269 | - } | ||
| 270 | - } | ||
| 271 | - return ""; | ||
| 272 | - } | ||
| 273 | - | ||
| 274 | - public List<JSONObject> getRowsDiff(String planStr) { | ||
| 275 | - List<JSONObject> result = new ArrayList<>(); | ||
| 276 | - List<String> planStrList = Arrays.asList(planStr.split("\n")); | ||
| 277 | - LinkedList<String> modifyLines = new LinkedList<>(planStrList); | ||
| 278 | - try { | ||
| 279 | - for (String item : planStrList) { | ||
| 280 | - if ((item.contains("cost=") && !item.contains("Result")) || item.contains(CommonConstants.HASH_COND) | ||
| 281 | - || item.contains("->")) { | ||
| 282 | - continue; | ||
| 283 | - } | ||
| 284 | - modifyLines.remove(item); | ||
| 285 | - } | ||
| 286 | - for (String mItem : modifyLines) { | ||
| 287 | - String[] mItemArr = mItem.split("rows="); | ||
| 288 | - if (mItem.length() <= 2) { | ||
| 289 | - continue; | ||
| 290 | - } | ||
| 291 | - // there are two rows | ||
| 292 | - JSONObject jsonObject = new JSONObject(); | ||
| 293 | - String firstStr = mItemArr[0]; | ||
| 294 | - if (!firstStr.contains(CommonConstants.COST)) { | ||
| 295 | - continue; | ||
| 296 | - } | ||
| 297 | - if (firstStr.contains("->")) { | ||
| 298 | - jsonObject.put("stepName", firstStr | ||
| 299 | - .substring(firstStr.indexOf("->") + 2, firstStr.indexOf(CommonConstants.COST)).trim()); | ||
| 300 | - } else { | ||
| 301 | - jsonObject.put("stepName", firstStr.substring(0, firstStr.indexOf(CommonConstants.COST)).trim()); | ||
| 302 | - } | ||
| 303 | - jsonObject.put("estimateRows", mItemArr[1].substring(0, mItemArr[1].indexOf(CommonConstants.BLANK))); | ||
| 304 | - jsonObject.put("actualRows", mItemArr[2].substring(0, mItemArr[2].indexOf(CommonConstants.BLANK))); | ||
| 305 | - result.add(jsonObject); | ||
| 306 | - } | ||
| 307 | - return result; | ||
| 308 | - } catch (Exception e) { | ||
| 309 | - log.error("get Rows diff fail:{}", e.getMessage()); | ||
| 310 | - return result; | ||
| 311 | - } | ||
| 312 | - } | ||
| 313 | - | ||
| 314 | - | ||
| 315 | - public JSONObject getExecutionPlan(InstanceNodeInfo nodeInfo, String sqlId, String type) { | ||
| 316 | - // nodeInfo.setDbUserPassword(RSAUtil.decrypt(nodeInfo.getDbUserPassword())); | ||
| 317 | - // store return result | ||
| 318 | - JSONObject parsedResult = new JSONObject(); | ||
| 319 | - // get connection then execute query | ||
| 320 | - try (Connection connection = getConnection(nodeInfo)) { | ||
| 321 | - if (connection == null) { | ||
| 322 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 323 | - } | ||
| 324 | - // pre-check track_stmt_stat_leve full sql level at least L1 | ||
| 325 | - if (executionPlanPreCheck(connection)) { | ||
| 326 | - return null; | ||
| 327 | - } | ||
| 328 | - // get prepared statement | ||
| 329 | - try (PreparedStatement preparedStatement = connection.prepareStatement(EXECUTION_PLAN_SQL)) { | ||
| 330 | - preparedStatement.setString(1, sqlId); | ||
| 331 | - // native plan | ||
| 332 | - if ("native".equals(type)) { | ||
| 333 | - JSONArray nativePlanArray = new JSONArray(); | ||
| 334 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 335 | - while (rs.next()) { | ||
| 336 | - JSONObject jsonObject = new JSONObject(); | ||
| 337 | - String planStr = rs.getString(1); | ||
| 338 | - jsonObject.put("rowsDiff", getRowsDiff(planStr)); | ||
| 339 | - jsonObject.put("queryPlan", planStr); | ||
| 340 | - jsonObject.put("peakMem", getPeakMemory(planStr)); | ||
| 341 | - jsonObject.put("workMem", getWorkMem(connection)); | ||
| 342 | - nativePlanArray.add(jsonObject); | ||
| 343 | - } | ||
| 344 | - } | ||
| 345 | - parsedResult.put("plan", nativePlanArray); | ||
| 346 | - return parsedResult; | ||
| 347 | - } | ||
| 348 | - // json plan | ||
| 349 | - // get result from result set | ||
| 350 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 351 | - while (rs.next()) { | ||
| 352 | - List<String> splitLines = new ArrayList<>(); | ||
| 353 | - String executionPlan = rs.getString(1); | ||
| 354 | - if (StringUtils.isBlank(executionPlan)) { | ||
| 355 | - throw new CustomException("failGetExecutionPlan"); | ||
| 356 | - } else { | ||
| 357 | - splitLines = Arrays.asList(executionPlan.split("\n")); | ||
| 358 | - } | ||
| 359 | - LinkedList<String> modifySplitLines = new LinkedList<>(splitLines); | ||
| 360 | - // remove non-operation or non-condition lines | ||
| 361 | - for (String line : splitLines) { | ||
| 362 | - if ((line.contains("cost=") && !line.contains("Result")) | ||
| 363 | - || line.contains(CommonConstants.HASH_COND)) { | ||
| 364 | - continue; | ||
| 365 | - } | ||
| 366 | - modifySplitLines.remove(line); | ||
| 367 | - } | ||
| 368 | - if (modifySplitLines.size() == 0) { | ||
| 369 | - throw new CustomException("failResolveExecutionPlan"); | ||
| 370 | - } | ||
| 371 | - // get base execution plan object | ||
| 372 | - totalPlanWidth = 0; | ||
| 373 | - totalPlanRows = 0; | ||
| 374 | - ExecutionPlan plan = processExecutionPlanString(modifySplitLines.get(0)); | ||
| 375 | - // get tree shape execution plan object | ||
| 376 | - assert plan != null; | ||
| 377 | - processExecutionPlan(modifySplitLines.subList(1, modifySplitLines.size()), 0, plan, | ||
| 378 | - plan.getChildren()); | ||
| 379 | - // put plan node | ||
| 380 | - JSONObject result = JSONObject.parseObject(JSON.toJSONString(plan)); | ||
| 381 | - JSONArray data = new JSONArray(); | ||
| 382 | - data.add(result); | ||
| 383 | - parsedResult.put("data", data); | ||
| 384 | - // put total rows and width | ||
| 385 | - JSONObject total = new JSONObject(); | ||
| 386 | - total.put("totalPlanRows", totalPlanRows); | ||
| 387 | - total.put("totalPlanWidth", totalPlanWidth); | ||
| 388 | - parsedResult.put("total", total); | ||
| 389 | - } | ||
| 390 | - } | ||
| 391 | - } | ||
| 392 | - } catch (SQLException e) { | ||
| 393 | - log.error("get TopSQL execute plan fail:{}", e.getMessage()); | ||
| 394 | - throw new CustomException(e.getMessage()); | ||
| 395 | - } | ||
| 396 | - return parsedResult; | ||
| 397 | - } | ||
| 398 | - | ||
| 399 | - /** | ||
| 400 | - * pre-check execution plan job | ||
| 401 | - * | ||
| 402 | - * connection connection info | ||
| 403 | - */ | ||
| 404 | - private boolean executionPlanPreCheck(Connection connection) { | ||
| 405 | - try (Statement statement = connection.createStatement()) { | ||
| 406 | - try (ResultSet rs = statement.executeQuery(PRE_CHECK_SET_SQL)) { | ||
| 407 | - while (rs.next()) { | ||
| 408 | - String name = rs.getString(1); | ||
| 409 | - String setting = rs.getString(2); | ||
| 410 | - if ("track_stmt_stat_level".equalsIgnoreCase(name)) { | ||
| 411 | - if (StringUtils.startsWith(setting, "OFF") || StringUtils.startsWith(setting, "L0")) { | ||
| 412 | - return true; | ||
| 413 | - } | ||
| 414 | - } | ||
| 415 | - } | ||
| 416 | - } | ||
| 417 | - } catch (SQLException e) { | ||
| 418 | - log.error("pre check fail:{}", e.getMessage()); | ||
| 419 | - throw new CustomException(e.getMessage()); | ||
| 420 | - } | ||
| 421 | - return false; | ||
| 422 | - } | ||
| 423 | - | ||
| 424 | - /** | ||
| 425 | - * generate execution plan tree shape json object | ||
| 426 | - * | ||
| 427 | - * lines lines of execution plan and condition | ||
| 428 | - * previousIndent last level indent length | ||
| 429 | - * plan last level plan | ||
| 430 | - * children last level plan children | ||
| 431 | - */ | ||
| 432 | - public void processExecutionPlan(List<String> lines, int previousIndent, ExecutionPlan plan, | ||
| 433 | - List<ExecutionPlan> children) { | ||
| 434 | - for (int i = 0; i < lines.size(); i++) { | ||
| 435 | - String line = lines.get(i); | ||
| 436 | - // process condition | ||
| 437 | - if (line.contains(CommonConstants.HASH_COND)) { | ||
| 438 | - String[] split = line.split(": "); | ||
| 439 | - plan.setJoinType(split[1]); | ||
| 440 | - continue; | ||
| 441 | - } | ||
| 442 | - // skip processed lines | ||
| 443 | - if (line.isEmpty()) { | ||
| 444 | - continue; | ||
| 445 | - } | ||
| 446 | - String[] indentPlanSplit = line.split("->"); | ||
| 447 | - int currentIndent = indentPlanSplit[0].length(); | ||
| 448 | - // when current indent greater than previous indent, add new children node and | ||
| 449 | - // go into next tree level | ||
| 450 | - if (currentIndent > previousIndent) { | ||
| 451 | - lines.set(i, ""); | ||
| 452 | - ExecutionPlan subPlan = processExecutionPlanString(line); | ||
| 453 | - children.add(subPlan); | ||
| 454 | - assert subPlan != null; | ||
| 455 | - processExecutionPlan(lines.subList(i + 1, lines.size()), currentIndent, subPlan, subPlan.getChildren()); | ||
| 456 | - } | ||
| 457 | - // when current indent less than or equals previous indent, return to last level | ||
| 458 | - if (currentIndent <= previousIndent) { | ||
| 459 | - return; | ||
| 460 | - } | ||
| 461 | - } | ||
| 462 | - } | ||
| 463 | - | ||
| 464 | - /** | ||
| 465 | - * parse execution plan line string into object | ||
| 466 | - * | ||
| 467 | - * line execution plan line string | ||
| 468 | - * execution plan line object | ||
| 469 | - */ | ||
| 470 | - public ExecutionPlan processExecutionPlanString(String line) { | ||
| 471 | - if (line.contains(CommonConstants.HASH_COND)) { | ||
| 472 | - return null; | ||
| 473 | - } | ||
| 474 | - ExecutionPlan plan = new ExecutionPlan(); | ||
| 475 | - // check if first line | ||
| 476 | - String planString; | ||
| 477 | - if (line.contains("->")) { | ||
| 478 | - String[] indentPlanSplit = line.split("->"); | ||
| 479 | - planString = indentPlanSplit[1]; | ||
| 480 | - } else { | ||
| 481 | - planString = line; | ||
| 482 | - } | ||
| 483 | - String[] operationParameterSplit = planString.split("\\("); | ||
| 484 | - // set operation name and alias name | ||
| 485 | - String operation = operationParameterSplit[0]; | ||
| 486 | - if (operation.contains(" on ")) { | ||
| 487 | - String[] split = operation.split(" on "); | ||
| 488 | - plan.setNodeType(split[0].trim()); | ||
| 489 | - // only show object name, remove alias name | ||
| 490 | - String objectName = split[1]; | ||
| 491 | - String alias; | ||
| 492 | - if (objectName.contains(CommonConstants.BLANK)) { | ||
| 493 | - String[] aliasSplit = objectName.split(CommonConstants.BLANK); | ||
| 494 | - alias = aliasSplit[0]; | ||
| 495 | - } else { | ||
| 496 | - alias = objectName; | ||
| 497 | - } | ||
| 498 | - plan.setAlias(alias); | ||
| 499 | - if (!objectNameList.contains(alias)) { | ||
| 500 | - objectNameList.add(alias); | ||
| 501 | - } | ||
| 502 | - } else { | ||
| 503 | - plan.setNodeType(operation.trim()); | ||
| 504 | - } | ||
| 505 | - // set parameters | ||
| 506 | - String parameters = operationParameterSplit[1].replace(")", ""); | ||
| 507 | - String[] parametersSplit = parameters.split(CommonConstants.BLANK); | ||
| 508 | - for (String parameterSplit : parametersSplit) { | ||
| 509 | - if (StringUtils.startsWith(parameterSplit, "cost")) { | ||
| 510 | - // set start cost and total cost | ||
| 511 | - String[] costSplit = parameterSplit.split("="); | ||
| 512 | - String[] startCostTotalCostSplit = costSplit[1].split("\\.\\."); | ||
| 513 | - plan.setStartupCost(Double.parseDouble(startCostTotalCostSplit[0])); | ||
| 514 | - plan.setTotalCost(Double.parseDouble(startCostTotalCostSplit[1])); | ||
| 515 | - } else if (StringUtils.startsWith(parameterSplit, "rows=")) { | ||
| 516 | - // set plan rows | ||
| 517 | - String[] rowSplit = parameterSplit.split("="); | ||
| 518 | - int rowsNum = Integer.parseInt(rowSplit[1]); | ||
| 519 | - plan.setPlanRows(rowsNum); | ||
| 520 | - totalPlanRows += rowsNum; | ||
| 521 | - } else if (StringUtils.startsWith(parameterSplit, "width=")) { | ||
| 522 | - // set plan width | ||
| 523 | - String[] widthSplit = parameterSplit.split("="); | ||
| 524 | - int widthNum = Integer.parseInt(widthSplit[1]); | ||
| 525 | - plan.setPlanWidth(widthNum); | ||
| 526 | - totalPlanWidth += widthNum; | ||
| 527 | - } | ||
| 528 | - } | ||
| 529 | - return plan; | ||
| 530 | - } | ||
| 531 | - | ||
| 532 | - | ||
| 533 | - public List<JSONObject> getPartitionList(InstanceNodeInfo nodeInfo, String sqlId) { | ||
| 534 | - // nodeInfo.setDbUserPassword(RSAUtil.decrypt(nodeInfo.getDbUserPassword())); | ||
| 535 | - List<JSONObject> results = new ArrayList<>(); | ||
| 536 | - try (Connection connection = getConnection(nodeInfo)) { | ||
| 537 | - if (connection == null) { | ||
| 538 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 539 | - } | ||
| 540 | - // get prepared statement then put parameters in | ||
| 541 | - try (PreparedStatement preparedStatement = connection.prepareStatement(PARTITION_LIST_SQL)) { | ||
| 542 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 543 | - while (rs.next()) { | ||
| 544 | - JSONObject jsonObject = new JSONObject(); | ||
| 545 | - jsonObject.put("partstrategy", rs.getString(1)); | ||
| 546 | - jsonObject.put("partkey", rs.getString(2)); | ||
| 547 | - jsonObject.put("relpages", rs.getString(3)); | ||
| 548 | - jsonObject.put("reltuples", rs.getString(4)); | ||
| 549 | - jsonObject.put("relallvisible", rs.getString(5)); | ||
| 550 | - jsonObject.put("interval", rs.getString(6)); | ||
| 551 | - results.add(jsonObject); | ||
| 552 | - } | ||
| 553 | - } | ||
| 554 | - } | ||
| 555 | - } catch (SQLException e) { | ||
| 556 | - log.error("get TopSQL Partition List fail:{}", e.getMessage()); | ||
| 557 | - return results; | ||
| 558 | - } | ||
| 559 | - return results; | ||
| 560 | - } | ||
| 561 | - | ||
| 562 | - | ||
| 563 | - public List<String> getIndexAdvice(InstanceNodeInfo nodeInfo, String sqlId) { | ||
| 564 | - // nodeInfo.setDbUserPassword(RSAUtil.decrypt(nodeInfo.getDbUserPassword())); | ||
| 565 | - List<String> results = new ArrayList<>(); | ||
| 566 | - List<IndexAdvice> advices = new ArrayList<>(); | ||
| 567 | - String queryText = ""; | ||
| 568 | - // get connection then execute query | ||
| 569 | - try (Connection connection = getConnection(nodeInfo)) { | ||
| 570 | - if (connection == null) { | ||
| 571 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 572 | - } | ||
| 573 | - // get prepared statement then put parameters in | ||
| 574 | - try (PreparedStatement preparedStatement = connection.prepareStatement(SELECT_QUERY_SQL)) { | ||
| 575 | - preparedStatement.setString(1, sqlId); | ||
| 576 | - // get query text from result set | ||
| 577 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 578 | - while (rs.next()) { | ||
| 579 | - for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { | ||
| 580 | - queryText = rs.getString(i); | ||
| 581 | - } | ||
| 582 | - } | ||
| 583 | - } | ||
| 584 | - } | ||
| 585 | - // check if queryText is empty | ||
| 586 | - if (queryText.isEmpty()) { | ||
| 587 | - throw new CustomException("get query text fail"); | ||
| 588 | - } | ||
| 589 | - String completeQueryText = "select * from gs_index_advise('" | ||
| 590 | - + queryText.replace("\n", CommonConstants.BLANK).replace("'", "''") + "')"; | ||
| 591 | - log.info("get complete query text: {}", completeQueryText); | ||
| 592 | - // get prepared statement | ||
| 593 | - try (PreparedStatement preparedStatement = connection.prepareStatement(completeQueryText)) { | ||
| 594 | - // get index advice from result set | ||
| 595 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 596 | - while (rs.next()) { | ||
| 597 | - IndexAdvice advice = new IndexAdvice(); | ||
| 598 | - advice.setSchema(rs.getString(1)); | ||
| 599 | - advice.setTable(rs.getString(2)); | ||
| 600 | - advice.setColumn(rs.getString(3)); | ||
| 601 | - advice.setIndexType(rs.getString(4)); | ||
| 602 | - advices.add(advice); | ||
| 603 | - } | ||
| 604 | - } | ||
| 605 | - } | ||
| 606 | - } catch (SQLException e) { | ||
| 607 | - log.error("get TopSQL index advice fail:{}", e.getMessage()); | ||
| 608 | - results.add("No index suggestions"); | ||
| 609 | - return results; | ||
| 610 | - } | ||
| 611 | - processAdvice(results, advices); | ||
| 612 | - return results; | ||
| 613 | - } | ||
| 614 | - | ||
| 615 | - /** | ||
| 616 | - * generate readable index advice | ||
| 617 | - * | ||
| 618 | - * results return result | ||
| 619 | - * advices list of index advice | ||
| 620 | - */ | ||
| 621 | - private void processAdvice(List<String> results, List<IndexAdvice> advices) { | ||
| 622 | - String indexTemplate = "建议为%s模式下的%t表的%c列创建索引"; | ||
| 623 | - String multiColumnIndexTemplate = "建议为%s模式下的%t表的%c创建复合索引"; | ||
| 624 | - // return specific message when get no index advice | ||
| 625 | - if (advices.isEmpty()) { | ||
| 626 | - results.add("No index suggestions"); | ||
| 627 | - return; | ||
| 628 | - } | ||
| 629 | - // process index advice for every returned line | ||
| 630 | - for (IndexAdvice advice : advices) { | ||
| 631 | - String column = advice.getColumn(); | ||
| 632 | - if (StringUtils.isNotEmpty(column)) { | ||
| 633 | - String result = column.contains(",") ? multiColumnIndexTemplate : indexTemplate; | ||
| 634 | - result = result.replace("%s", advice.getSchema()); | ||
| 635 | - result = result.replace("%t", advice.getTable()); | ||
| 636 | - result = result.replace("%c", advice.getColumn()); | ||
| 637 | - results.add(result); | ||
| 638 | - } | ||
| 639 | - } | ||
| 640 | - } | ||
| 641 | - | ||
| 642 | - | ||
| 643 | - public JSONObject getObjectInfo(InstanceNodeInfo nodeInfo, String sqlId) { | ||
| 644 | - // init objectNameList via get execution plan | ||
| 645 | - this.objectNameList = new ArrayList<>(); | ||
| 646 | - if (null == this.getExecutionPlan(nodeInfo, sqlId, "")) { | ||
| 647 | - throw new CustomException("failGetExecutionPlan"); | ||
| 648 | - } | ||
| 649 | - List<String> curObjectNameList = this.objectNameList; | ||
| 650 | - LinkedList<String> modifyObjectNameList = new LinkedList<>(curObjectNameList); | ||
| 651 | - // get connection then execute query | ||
| 652 | - JSONObject results = new JSONObject(); | ||
| 653 | - JSONObject tableMetadata = new JSONObject(); | ||
| 654 | - JSONObject tableStructure = new JSONObject(); | ||
| 655 | - JSONObject tableIndex = new JSONObject(); | ||
| 656 | - try (Connection connection = getConnection(nodeInfo)) { | ||
| 657 | - if (connection == null) { | ||
| 658 | - throw new CustomException(CommonConstants.CONNECTION_FAIL); | ||
| 659 | - } | ||
| 660 | - // query table metadata | ||
| 661 | - try (PreparedStatement preparedStatement = connection.prepareStatement(TABLE_METADATA_SQL)) { | ||
| 662 | - for (String name : curObjectNameList) { | ||
| 663 | - preparedStatement.setString(1, name); | ||
| 664 | - // get result from result set | ||
| 665 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 666 | - while (rs.next()) { | ||
| 667 | - JSONObject result = JSONObject.parseObject(rs.getString(1)); | ||
| 668 | - tableMetadata.put(name, result); | ||
| 669 | - } | ||
| 670 | - } catch (SQLException e) { | ||
| 671 | - modifyObjectNameList.remove(name); | ||
| 672 | - } | ||
| 673 | - } | ||
| 674 | - } | ||
| 675 | - // query table structure | ||
| 676 | - try (PreparedStatement preparedStatement = connection.prepareStatement(TABLE_STRUCTURE_SQL)) { | ||
| 677 | - for (String name : curObjectNameList) { | ||
| 678 | - preparedStatement.setString(1, name); | ||
| 679 | - // get result from result set | ||
| 680 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 681 | - JSONArray resultArray = new JSONArray(); | ||
| 682 | - while (rs.next()) { | ||
| 683 | - resultArray.add(JSONObject.parseObject(rs.getString(1))); | ||
| 684 | - } | ||
| 685 | - tableStructure.put(name, resultArray); | ||
| 686 | - } catch (SQLException e) { | ||
| 687 | - modifyObjectNameList.remove(name); | ||
| 688 | - } | ||
| 689 | - } | ||
| 690 | - } | ||
| 691 | - // query index info | ||
| 692 | - try (PreparedStatement preparedStatement = connection.prepareStatement(INDEX_SQL)) { | ||
| 693 | - for (String name : curObjectNameList) { | ||
| 694 | - preparedStatement.setString(1, name); | ||
| 695 | - // get result from result set | ||
| 696 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 697 | - JSONArray parsedResult = new JSONArray(); | ||
| 698 | - while (rs.next()) { | ||
| 699 | - for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { | ||
| 700 | - parsedResult.add(JSONObject.parseObject(rs.getString(1))); | ||
| 701 | - } | ||
| 702 | - } | ||
| 703 | - tableIndex.put(name, parsedResult); | ||
| 704 | - } catch (SQLException e) { | ||
| 705 | - modifyObjectNameList.remove(name); | ||
| 706 | - } | ||
| 707 | - } | ||
| 708 | - } | ||
| 709 | - } catch (SQLException e) { | ||
| 710 | - log.error("get TopSQL object information fail:{}", e.getMessage()); | ||
| 711 | - throw new CustomException(e.getMessage()); | ||
| 712 | - } | ||
| 713 | - results.put("object_name_list", modifyObjectNameList); | ||
| 714 | - results.put("table_metadata", tableMetadata); | ||
| 715 | - results.put("table_structure", tableStructure); | ||
| 716 | - results.put("table_index", tableIndex); | ||
| 717 | - return results; | ||
| 718 | - } | ||
| 719 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/topsql/TopSQLHandler.java+0-92
| @@ -1,92 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.handler.topsql; | ||
| 5 | - | ||
| 6 | -import java.sql.Connection; | ||
| 7 | -import java.util.List; | ||
| 8 | - | ||
| 9 | -import com.alibaba.fastjson.JSONObject; | ||
| 10 | -import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; | ||
| 11 | -import com.nctigba.observability.instance.dto.topsql.TopSQLNowReq; | ||
| 12 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | ||
| 13 | - | ||
| 14 | -public interface TopSQLHandler { | ||
| 15 | - /** | ||
| 16 | - * target database type | ||
| 17 | - * | ||
| 18 | - * database type | ||
| 19 | - */ | ||
| 20 | - String getDatabaseType(); | ||
| 21 | - | ||
| 22 | - /** | ||
| 23 | - * test instance is success | ||
| 24 | - * | ||
| 25 | - * nodeInfo instance node info | ||
| 26 | - * Connection | ||
| 27 | - */ | ||
| 28 | - Connection getConnection(InstanceNodeInfo nodeInfo); | ||
| 29 | - | ||
| 30 | - /** | ||
| 31 | - * fetch TopSQL list from database | ||
| 32 | - * | ||
| 33 | - * nodeInfo instance node info | ||
| 34 | - * topSQLListReq dto | ||
| 35 | - * TopSQL list | ||
| 36 | - */ | ||
| 37 | - List<JSONObject> getTopSQLList(InstanceNodeInfo nodeInfo, TopSQLListReq topSQLListReq); | ||
| 38 | - | ||
| 39 | - /** | ||
| 40 | - * fetch TopSQL now list from database | ||
| 41 | - * | ||
| 42 | - * nodeInfo instance node info | ||
| 43 | - * topSQLNowReq dto | ||
| 44 | - * TopSQL list | ||
| 45 | - */ | ||
| 46 | - List<JSONObject> getTopSQLNow(InstanceNodeInfo nodeInfo, TopSQLNowReq topSQLNowReq); | ||
| 47 | - | ||
| 48 | - /** | ||
| 49 | - * fetch TopSQL statistical information from database | ||
| 50 | - * | ||
| 51 | - * nodeInfo instance node info | ||
| 52 | - * sqlId TopSQL debug query id | ||
| 53 | - * TopSQL statistical information | ||
| 54 | - */ | ||
| 55 | - JSONObject getStatisticalInfo(InstanceNodeInfo nodeInfo, String sqlId); | ||
| 56 | - | ||
| 57 | - /** | ||
| 58 | - * fetch TopSQL execution plan from database | ||
| 59 | - * | ||
| 60 | - * nodeInfo instance node info | ||
| 61 | - * sqlId TopSQL debug query id | ||
| 62 | - * TopSQL execution plan | ||
| 63 | - */ | ||
| 64 | - JSONObject getExecutionPlan(InstanceNodeInfo nodeInfo, String sqlId, String type); | ||
| 65 | - | ||
| 66 | - /** | ||
| 67 | - * fetch TopSQL Partition List from database | ||
| 68 | - * | ||
| 69 | - * nodeInfo instance node info | ||
| 70 | - * sqlId TopSQL debug query id | ||
| 71 | - * TopSQL Partition List | ||
| 72 | - */ | ||
| 73 | - List<JSONObject> getPartitionList(InstanceNodeInfo nodeInfo, String sqlId); | ||
| 74 | - | ||
| 75 | - /** | ||
| 76 | - * fetch TopSQL index advice from database | ||
| 77 | - * | ||
| 78 | - * nodeInfo instance node info | ||
| 79 | - * sqlId TopSQL debug query id | ||
| 80 | - * TopSQL index advice | ||
| 81 | - */ | ||
| 82 | - List<String> getIndexAdvice(InstanceNodeInfo nodeInfo, String sqlId); | ||
| 83 | - | ||
| 84 | - /** | ||
| 85 | - * fetch TopSQL object information from database | ||
| 86 | - * | ||
| 87 | - * nodeInfo instance node info | ||
| 88 | - * sqlId TopSQL debug query id | ||
| 89 | - * TopSQL object information | ||
| 90 | - */ | ||
| 91 | - JSONObject getObjectInfo(InstanceNodeInfo nodeInfo, String sqlId); | ||
| 92 | -} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/listener/PluginListener.java+2-0
| @@ -37,6 +37,8 @@ public class PluginListener implements ApplicationListener<ApplicationEvent> { | |||
| 37 | firstMenu.getMenuId()); | 37 | firstMenu.getMenuId()); |
| 38 | menuFacade.savePluginRoute(pluginId, "会话详情", "Session Details", "vem/sessionDetail", | 38 | menuFacade.savePluginRoute(pluginId, "会话详情", "Session Details", "vem/sessionDetail", |
| 39 | firstMenu.getMenuId()); | 39 | firstMenu.getMenuId()); |
| 40 | + menuFacade.savePluginMenu(pluginId, "集群监控", "Cluster OPS", 10, "vem/dashboard/clusters", | ||
| 41 | + firstMenu.getMenuId()); | ||
| 40 | } | 42 | } |
| 41 | } else if (event instanceof ContextClosedEvent) { | 43 | } else if (event instanceof ContextClosedEvent) { |
| 42 | MainApplicationContext context = ((ContextClosedEvent) event).getApplicationContext() | 44 | MainApplicationContext context = ((ContextClosedEvent) event).getApplicationContext() |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/AspMapper.java+67-0
| @@ -0,0 +1,67 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.mapper; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +import org.apache.ibatis.annotations.Mapper; | ||
| 11 | +import org.apache.ibatis.annotations.Select; | ||
| 12 | + | ||
| 13 | +import com.nctigba.observability.instance.dto.asp.AnalysisDto; | ||
| 14 | +import com.nctigba.observability.instance.dto.asp.AspCountReq; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * AspMapper.java | ||
| 18 | + * | ||
| 19 | + * 2023-08-25 | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | +public interface AspMapper { | ||
| 23 | + /** | ||
| 24 | + * count | ||
| 25 | + * | ||
| 26 | + * req AspCountReq | ||
| 27 | + * List<Map<String, Object>> | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | + + "select LOCAL_ACTIVE_SESSION1.sampleid,sample_time,session_count from ( " | ||
| 31 | + + "select sampleid,count(*) session_count from dbe_perf.LOCAL_ACTIVE_SESSION " + "group by sampleid " | ||
| 32 | + + ")LOCAL_ACTIVE_SESSION1 " + "left join ( " | ||
| 33 | + + "SELECT sampleid, MIN(sample_time) AS sample_time FROM dbe_perf.LOCAL_ACTIVE_SESSION " | ||
| 34 | + + "GROUP BY sampleid " | ||
| 35 | + + ")LOCAL_ACTIVE_SESSION2 on LOCAL_ACTIVE_SESSION1.sampleid = LOCAL_ACTIVE_SESSION2.sampleid " | ||
| 36 | + + "union all " + "select gs_asp1.sampleid,sample_time,session_count from ( " | ||
| 37 | + + "select sampleid,count(*) session_count from gs_asp " + "group by sampleid " + ")gs_asp1 " | ||
| 38 | + + "left join ( " + "SELECT sampleid, MIN(sample_time) AS sample_time FROM gs_asp " + "GROUP BY sampleid " | ||
| 39 | + + ")gs_asp2 on gs_asp1.sampleid = gs_asp2.sampleid " + ")a " | ||
| 40 | + + "where a.sample_time >= #{startTime} and a.sample_time <= #{finishTime} " + "order by a.sample_time ") | ||
| 41 | + List<Map<String, Object>> count(AspCountReq req); | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * analysis | ||
| 45 | + * | ||
| 46 | + * req AspCountReq | ||
| 47 | + * List<AnalysisDto> | ||
| 48 | + */ | ||
| 49 | + | ||
| 50 | + + "'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') sample_time,gs_asp1.databaseid, " | ||
| 51 | + + "gs_asp1.thread_id,gs_asp1.sessionid,gs_asp1.start_time,gs_asp1.event,gs_asp1.userid, " | ||
| 52 | + + "gs_asp1.application_name,host(gs_asp1.client_addr) client_addr,gs_asp1.client_hostname, " | ||
| 53 | + + "gs_asp1.client_port,gs_asp1.query_id,gs_asp1.unique_query_id,gs_asp1.user_id, " | ||
| 54 | + + "gs_asp1.cn_id,gs_asp1.unique_query,gs_asp1.lockmode,gs_asp1.wait_status " + "from GS_ASP gs_asp1 " | ||
| 55 | + + "left join ( " + "SELECT sampleid, MIN(sample_time) AS sample_time FROM gs_asp " | ||
| 56 | + + "GROUP BY sampleid) gs_asp2 on gs_asp1.sampleid = gs_asp2.sampleid " | ||
| 57 | + + "where gs_asp2.sample_time >= #{startTime} and gs_asp2.sample_time <= " + "#{finishTime} " | ||
| 58 | + + "union all " + "select s1.sampleid,TO_CHAR(s2.sample_time,'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') " | ||
| 59 | + + "sample_time,s1.databaseid, " + "s1.thread_id,s1.sessionid,s1.start_time,s1.event,s1.userid, " | ||
| 60 | + + "s1.application_name,host(s1.client_addr) client_addr,s1.client_hostname, " | ||
| 61 | + + "s1.client_port,s1.query_id,s1.unique_query_id,s1.user_id, " | ||
| 62 | + + "s1.cn_id,s1.unique_query,s1.lockmode,s1.wait_status " + "from dbe_perf.LOCAL_ACTIVE_SESSION s1 " | ||
| 63 | + + "left join ( " + "SELECT sampleid, MIN(sample_time) AS sample_time FROM dbe_perf.LOCAL_ACTIVE_SESSION " | ||
| 64 | + + "GROUP BY sampleid) s2 on s1.sampleid = s2.sampleid " | ||
| 65 | + + "where s2.sample_time >= #{startTime} and s2.sample_time <= #{finishTime}) " + "order by sample_time; ") | ||
| 66 | + List<AnalysisDto> analysis(AspCountReq req); | ||
| 67 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/ClustersMapper.java+51-0
| @@ -0,0 +1,51 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.mapper; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +import org.apache.ibatis.annotations.Mapper; | ||
| 10 | +import org.apache.ibatis.annotations.Select; | ||
| 11 | + | ||
| 12 | +import com.nctigba.observability.instance.aop.Ds; | ||
| 13 | +import com.nctigba.observability.instance.dto.cluster.NodeRelationDto; | ||
| 14 | +import com.nctigba.observability.instance.dto.cluster.SyncSituation; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * ClustersMapper | ||
| 18 | + * | ||
| 19 | + * liupengfei | ||
| 20 | + * 2023/8/25 | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | +public interface ClustersMapper { | ||
| 24 | + /** | ||
| 25 | + * getSyncSituation | ||
| 26 | + * | ||
| 27 | + * id String | ||
| 28 | + * List<SyncSituation> | ||
| 29 | + */ | ||
| 30 | + | ||
| 31 | + + "pg_size_pretty(pg_xlog_location_diff(s.sender_sent_location,s.receiver_received_location)) " | ||
| 32 | + + "received_delay, " | ||
| 33 | + + "pg_size_pretty(pg_xlog_location_diff(s.sender_write_location,s.receiver_write_location)) write_delay, " | ||
| 34 | + + "pg_size_pretty(pg_xlog_location_diff(s.sender_replay_location,s.receiver_replay_location)) " | ||
| 35 | + + "replay_delay, " + "s.sync_state as sync, s.state as wal_sync_state, s.sync_priority " | ||
| 36 | + + "FROM pg_stat_replication r , pg_stat_get_wal_senders() s " + "where r.pid = s.pid;") | ||
| 37 | + | ||
| 38 | + List<SyncSituation> getSyncSituation(String id); | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * relation | ||
| 42 | + * | ||
| 43 | + * id String | ||
| 44 | + * List<NodeRelationDto> | ||
| 45 | + */ | ||
| 46 | + | ||
| 47 | + + "pg_xlog_location_diff(sender_sent_location,receiver_replay_location) replay_delay, " | ||
| 48 | + + "sync_state FROM pg_stat_replication") | ||
| 49 | + | ||
| 50 | + List<NodeRelationDto> relation(String id); | ||
| 51 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/DbConfigMapper.java+81-4
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.mapper; | 5 | package com.nctigba.observability.instance.mapper; |
| 5 | 6 | ||
| 6 | import java.util.List; | 7 | import java.util.List; |
| @@ -9,14 +10,90 @@ import java.util.Map; | |||
| 9 | import org.apache.ibatis.annotations.Mapper; | 10 | import org.apache.ibatis.annotations.Mapper; |
| 10 | import org.apache.ibatis.annotations.Select; | 11 | import org.apache.ibatis.annotations.Select; |
| 11 | 12 | ||
| 13 | +/** | ||
| 14 | + * DbConfigMapper.java | ||
| 15 | + * | ||
| 16 | + * 2023-08-28 | ||
| 17 | + */ | ||
| 12 | 18 | ||
| 13 | public interface DbConfigMapper { | 19 | public interface DbConfigMapper { |
| 20 | + /** | ||
| 21 | + * memoryNodeDetail | ||
| 22 | + * | ||
| 23 | + * List | ||
| 24 | + */ | ||
| 14 | 25 | ||
| 15 | List<Map<String, Object>> memoryNodeDetail(); | 26 | List<Map<String, Object>> memoryNodeDetail(); |
| 16 | 27 | ||
| 17 | - @Select("select name, decode(unit,null,setting,setting||'('||unit||')') as value " | 28 | + /** |
| 18 | - + "from dbe_perf.GLOBAL_CONFIG_SETTINGS where name in ('max_process_memory'," | 29 | + * memoryConfig |
| 19 | - + "'shared_buffers','temp_buffers','work_mem','query_mem','query_max_mem'," | 30 | + * |
| 20 | - + "'maintenance_work_mem','cstore_buffers','memorypool_enable','memorypool_size')") | 31 | + * @return List |
| 32 | + */ | ||
| 33 | + | ||
| 34 | + + "else decode(unit,null,setting,setting||'('||unit||')') end as value from dbe_perf.GLOBAL_CONFIG_SETTINGS" | ||
| 35 | + + " where name in ('max_process_memory', 'shared_buffers', 'temp_buffers', 'work_mem', 'query_mem', " | ||
| 36 | + + "'query_max_mem', 'maintenance_work_mem', 'cstore_buffers', 'memorypool_enable', 'memorypool_size')") | ||
| 21 | List<Map<String, Object>> memoryConfig(); | 37 | List<Map<String, Object>> memoryConfig(); |
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * settings | ||
| 41 | + * | ||
| 42 | + * List | ||
| 43 | + */ | ||
| 44 | + | ||
| 45 | + List<Map<String, String>> settings(); | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * workMem | ||
| 49 | + * | ||
| 50 | + * String | ||
| 51 | + */ | ||
| 52 | + | ||
| 53 | + String workMem(); | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * version | ||
| 57 | + * | ||
| 58 | + * String | ||
| 59 | + */ | ||
| 60 | + | ||
| 61 | + String version(); | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * starttime | ||
| 65 | + * | ||
| 66 | + * String | ||
| 67 | + */ | ||
| 68 | + | ||
| 69 | + String starttime(); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * archiveMode | ||
| 73 | + * | ||
| 74 | + * String | ||
| 75 | + */ | ||
| 76 | + | ||
| 77 | + String archiveMode(); | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * env | ||
| 81 | + * | ||
| 82 | + * Map | ||
| 83 | + */ | ||
| 84 | + | ||
| 85 | + Map<String, String> env(); | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * waitEvents | ||
| 89 | + * | ||
| 90 | + * List | ||
| 91 | + */ | ||
| 92 | + | ||
| 93 | + + "coalesce(s.block_sessionid, 0) block_sessionid, a.query_id, s.wait_status, s.wait_event, " | ||
| 94 | + + "coalesce(s.lockmode, ' ' ) lockmode, coalesce(s.locktag, ' ') locktag, " | ||
| 95 | + + "coalesce(locktag_decode(locktag), ' ') tag from pg_stat_activity a " | ||
| 96 | + + "left join dbe_perf.THREAD_WAIT_STATUS s on a.sessionid = s.sessionid " | ||
| 97 | + + "where state = 'active' and a.pid <> pg_backend_pid()") | ||
| 98 | + List<Map<String, Object>> waitEvents(); | ||
| 22 | } | 99 | } |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/ParamInfoMapper.java+5-5
| @@ -16,14 +16,14 @@ import org.springframework.stereotype.Service; | |||
| 16 | import com.nctigba.observability.instance.config.ParamInfoInitConfig; | 16 | import com.nctigba.observability.instance.config.ParamInfoInitConfig; |
| 17 | import com.nctigba.observability.instance.constants.CommonConstants; | 17 | import com.nctigba.observability.instance.constants.CommonConstants; |
| 18 | import com.nctigba.observability.instance.entity.ParamInfo; | 18 | import com.nctigba.observability.instance.entity.ParamInfo; |
| 19 | -import com.nctigba.observability.instance.entity.ParamInfo.type; | 19 | +import com.nctigba.observability.instance.entity.ParamInfo.ParamType; |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | public class ParamInfoMapper implements InitializingBean { | 22 | public class ParamInfoMapper implements InitializingBean { |
| 23 | private static final String SQL = "select * from param_info"; | 23 | private static final String SQL = "select * from param_info"; |
| 24 | private static final List<ParamInfo> LIST = new ArrayList<>(); | 24 | private static final List<ParamInfo> LIST = new ArrayList<>(); |
| 25 | private static final Map<Integer, ParamInfo> IDS = new HashMap<>(); | 25 | private static final Map<Integer, ParamInfo> IDS = new HashMap<>(); |
| 26 | - private static final Map<ParamInfo.type, Map<String, ParamInfo>> MAP = new HashMap<>(); | 26 | + private static final Map<ParamInfo.ParamType, Map<String, ParamInfo>> MAP = new HashMap<>(); |
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | public void afterPropertiesSet() throws Exception { | 29 | public void afterPropertiesSet() throws Exception { |
| @@ -41,7 +41,7 @@ public class ParamInfoMapper implements InitializingBean { | |||
| 41 | IDS.put(paramInfo.getId(), paramInfo); | 41 | IDS.put(paramInfo.getId(), paramInfo); |
| 42 | } | 42 | } |
| 43 | synchronized (MAP) { | 43 | synchronized (MAP) { |
| 44 | - for (type v : ParamInfo.type.values()) | 44 | + for (ParamType v : ParamInfo.ParamType.values()) |
| 45 | MAP.put(v, new HashMap<>()); | 45 | MAP.put(v, new HashMap<>()); |
| 46 | for (ParamInfo paramInfo : list) | 46 | for (ParamInfo paramInfo : list) |
| 47 | MAP.get(paramInfo.getParamType()).put(paramInfo.getParamName(), paramInfo); | 47 | MAP.get(paramInfo.getParamType()).put(paramInfo.getParamName(), paramInfo); |
| @@ -60,11 +60,11 @@ public class ParamInfoMapper implements InitializingBean { | |||
| 60 | return LIST; | 60 | return LIST; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | - public static ParamInfo getParamInfo(ParamInfo.type type, String name) { | 63 | + public static ParamInfo getParamInfo(ParamInfo.ParamType type, String name) { |
| 64 | return MAP.get(type).get(name); | 64 | return MAP.get(type).get(name); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | - public static List<Integer> getIds(type t) { | 67 | + public static List<Integer> getIds(ParamType t) { |
| 68 | return MAP.get(t).values().stream().map(ParamInfo::getId).collect(Collectors.toList()); | 68 | return MAP.get(t).values().stream().map(ParamInfo::getId).collect(Collectors.toList()); |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/PgSettingMapper.java+19-0
| @@ -0,0 +1,19 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.mapper; | ||
| 6 | + | ||
| 7 | +import org.apache.ibatis.annotations.Mapper; | ||
| 8 | + | ||
| 9 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 10 | +import com.nctigba.observability.instance.entity.PgSettings; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * PgSettingMapper.java | ||
| 14 | + * | ||
| 15 | + * 2023-08-25 | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +public interface PgSettingMapper extends BaseMapper<PgSettings> { | ||
| 19 | +} | ||
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/session/OpenGaussSessionHandler.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/SessionMapper.java+172-345
| @@ -1,346 +1,173 @@ | |||
| 1 | -/* | 1 | +/* |
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | - */ | 3 | + */ |
| 4 | - | 4 | + |
| 5 | -package com.nctigba.observability.instance.handler.session; | 5 | +package com.nctigba.observability.instance.mapper; |
| 6 | - | 6 | + |
| 7 | -import com.alibaba.fastjson.JSONObject; | 7 | +import java.util.List; |
| 8 | -import com.nctigba.common.web.exception.InstanceException; | 8 | +import java.util.Map; |
| 9 | -import com.nctigba.observability.instance.constants.CommonConstants; | 9 | + |
| 10 | -import com.nctigba.observability.instance.constants.DatabaseType; | 10 | +import org.apache.ibatis.annotations.Mapper; |
| 11 | -import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | 11 | +import org.apache.ibatis.annotations.Select; |
| 12 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | 12 | + |
| 13 | -import com.nctigba.observability.instance.service.ClusterManager; | 13 | +/** |
| 14 | -import lombok.RequiredArgsConstructor; | 14 | + * SessionMapper |
| 15 | -import lombok.extern.slf4j.Slf4j; | 15 | + * |
| 16 | -import org.apache.commons.lang3.ObjectUtils; | 16 | + * @author liupengfei |
| 17 | -import org.apache.commons.lang3.StringUtils; | 17 | + * @since 2023/8/25 |
| 18 | -import org.springframework.stereotype.Component; | 18 | + */ |
| 19 | - | 19 | +@Mapper |
| 20 | -import java.sql.Connection; | 20 | +public interface SessionMapper { |
| 21 | -import java.sql.PreparedStatement; | 21 | + /** |
| 22 | -import java.sql.ResultSet; | 22 | + * sessionIsWaiting |
| 23 | -import java.sql.SQLException; | 23 | + * |
| 24 | -import java.util.ArrayList; | 24 | + * @param session session |
| 25 | -import java.util.HashMap; | 25 | + * @return int |
| 26 | -import java.util.LinkedList; | 26 | + */ |
| 27 | -import java.util.List; | 27 | + @Select("select count(waiting) as count from pg_stat_activity where sessionid = #{session} and waiting") |
| 28 | -import java.util.Map; | 28 | + int sessionIsWaiting(String session); |
| 29 | -import java.util.Set; | 29 | + |
| 30 | -import java.util.stream.Collectors; | 30 | + /** |
| 31 | - | 31 | + * generalMesList |
| 32 | -@Component | 32 | + * |
| 33 | -@RequiredArgsConstructor | 33 | + * @param session session |
| 34 | -@Slf4j | 34 | + * @return List |
| 35 | -public class OpenGaussSessionHandler implements SessionHandler { | 35 | + */ |
| 36 | - private static final String TEST_SQL = "select 1"; | 36 | + @Select("select a.state, a.sessionid, a.datname, a.usename, " |
| 37 | - private static final String CHECK_SESSION_IS_WAIT_SQL = "select count(waiting) as count from pg_stat_activity " | 37 | + + "a.resource_pool, b.lwtid , TO_CHAR(a.backend_start,'YYYY-MM-DD HH:MI:SS') as backend_start, " |
| 38 | - + "where sessionid = ? and waiting"; | 38 | + + "TO_CHAR((now()- a.backend_start),'HH24:MI:SS') as backend_runtime, " |
| 39 | - private static final String SESSION_GENERAL_MES_SQL = "select a.state, a.sessionid, a.datname, a.usename, " | 39 | + + "a.client_addr, a.application_name, a.client_hostname, a.client_port, " |
| 40 | - + "a.resource_pool, b.lwtid , TO_CHAR(a.backend_start,'YYYY-MM-DD HH:MI:SS') as backend_start, " | 40 | + + "TO_CHAR(a.xact_start ,'YYYY-MM-DD HH:MI:SS') as xact_start, " |
| 41 | - + "TO_CHAR((now()- a.backend_start),'HH24:MI:SS') as backend_runtime, " | 41 | + + "TO_CHAR(a.query_start ,'YYYY-MM-DD HH:MI:SS') as query_start, " + "a.datname, a.query_id, a.query " |
| 42 | - + "a.client_addr, a.application_name, a.client_hostname, a.client_port, " | 42 | + + "from pg_stat_activity a left join pg_thread_wait_status b on a.sessionid=b.sessionid " |
| 43 | - + "TO_CHAR(a.xact_start ,'YYYY-MM-DD HH:MI:SS') as xact_start, " | 43 | + + "where a.sessionid = #{session}") |
| 44 | - + "TO_CHAR(a.query_start ,'YYYY-MM-DD HH:MI:SS') as query_start, " + "a.datname, a.query_id, a.query " | 44 | + List<Map<String, Object>> generalMesList(String session); |
| 45 | - + "from pg_stat_activity a left join pg_thread_wait_status b on a.sessionid=b.sessionid " | 45 | + |
| 46 | - + "where a.sessionid = ?"; | 46 | + /** |
| 47 | - private static final String SESSION_BLOCK_MES_SQL = "select a.block_sessionid, pg_relation_filepath(b.relation)" | 47 | + * blockList |
| 48 | - + " as filepath, b.page, b.tuple, b.bucket, a.wait_status, a.wait_event, a.lockmode, " | 48 | + * |
| 49 | - + "(select d.nspname || '.' || c.relname from pg_class c left join pg_namespace d " | 49 | + * @param session String |
| 50 | - + "on c.relnamespace = d.oid " + "where c.oid = b.relation) as namespace_relation " | 50 | + * @return List |
| 51 | - + "from pg_thread_wait_status a left join pg_locks b on a.sessionid = b.sessionid " | 51 | + */ |
| 52 | - + "where a.sessionid = ? and not granted"; | 52 | + @Select("select a.block_sessionid, pg_relation_filepath(b.relation)" |
| 53 | - private static final String SESSION_STATISTIC_SQL = "select stat_name,value from GS_SESSION_TIME " | 53 | + + " as filepath, b.page, b.tuple, b.bucket, a.wait_status, a.wait_event, a.lockmode, " |
| 54 | - + "where sessid like '%' || ?"; | 54 | + + "(select d.nspname || '.' || c.relname from pg_class c left join pg_namespace d " |
| 55 | - private static final String SESSION_RUNTIME_SQL = "select statname,value from GS_SESSION_STAT " | 55 | + + "on c.relnamespace = d.oid " + "where c.oid = b.relation) as namespace_relation " |
| 56 | - + "where sessid like '%' || ?"; | 56 | + + "from pg_thread_wait_status a left join pg_locks b on a.sessionid = b.sessionid " |
| 57 | - private static final String SESSION_WAITING_REC_SQL = "select sample_time,wait_status,event,lockmode,locktag_decode" | 57 | + + "where a.sessionid = #{session} and not granted") |
| 58 | - + "(locktag) as locktag from GS_ASP where sessionid = ? order by sample_time desc limit 10"; | 58 | + List<Map<String, Object>> blockList(String session); |
| 59 | - private static final String SESSION_BLOCK_TREE = "with recursive tmp_lock as ( " + " select distinct " | 59 | + |
| 60 | - + " w.sessionid as id, " + " r.sessionid as parentid, " | 60 | + /** |
| 61 | - + " w.wait_status as wait_status, " + " w.wait_event as wait_event, " | 61 | + * statistic |
| 62 | - + " w.lockmode as lockmode " + " from ( " | 62 | + * |
| 63 | - + " select a.sessionid,a.locktype,a.database, " | 63 | + * @param session session |
| 64 | - + " a.relation,a.page,a.tuple,a.classid, " | 64 | + * @return List |
| 65 | - + " a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid, " | 65 | + */ |
| 66 | - + " a.transactionid, b.query as query, " | 66 | + @Select("select stat_name,value from GS_SESSION_TIME where sessid like '%' || #{session}") |
| 67 | - + " b.xact_start,b.query_start,b.usename,b.datname ,c.wait_status,c.wait_event,c.lockmode " | 67 | + List<Map<String, Object>> statistic(String session); |
| 68 | - + " from pg_locks a " + " left join pg_stat_activity b on a.sessionid=b.sessionid " | 68 | + |
| 69 | - + " left join pg_thread_wait_status c on b.sessionid=c.sessionid " | 69 | + /** |
| 70 | - + " where not a.granted " + " ) w, " + " ( " | 70 | + * runtime |
| 71 | - + " select a.sessionid,a.locktype,a.database, " | 71 | + * |
| 72 | - + " a.relation,a.page,a.tuple,a.classid, " | 72 | + * @param session session |
| 73 | - + " a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid, " | 73 | + * @return List |
| 74 | - + " a.transactionid, b.query as query, " | 74 | + */ |
| 75 | - + " b.xact_start,b.query_start,b.usename,b.datname ,c.wait_status,c.wait_event,c.lockmode " | 75 | + @Select("select statname,value from GS_SESSION_STAT where sessid like '%' || #{session}") |
| 76 | - + " from pg_locks a " + " left join pg_stat_activity b on a.sessionid=b.sessionid " | 76 | + List<Map<String, Object>> runtime(String session); |
| 77 | - + " left join pg_thread_wait_status c on b.sessionid=c.sessionid " | 77 | + |
| 78 | - + " where a.granted " + " ) r " + " where 1=1 " | 78 | + /** |
| 79 | - + " and r.locktype is not distinct from w.locktype " | 79 | + * detailWaiting |
| 80 | - + " and r.database is not distinct from w.database " | 80 | + * |
| 81 | - + " and r.relation is not distinct from w.relation " | 81 | + * @param session session |
| 82 | - + " and r.page is not distinct from w.page " + " and r.tuple is not distinct from w.tuple " | 82 | + * @return List |
| 83 | - + " and r.classid is not distinct from w.classid " | 83 | + */ |
| 84 | - + " and r.objid is not distinct from w.objid " | 84 | + @Select("select sample_time,wait_status,event,lockmode,locktag_decode" |
| 85 | - + " and r.objsubid is not distinct from w.objsubid " | 85 | + + "(locktag) as locktag from GS_ASP where sessionid = #{session} order by sample_time desc limit 10") |
| 86 | - + " and r.transactionid is not distinct from w.transactionid " | 86 | + List<Map<String, Object>> detailWaiting(String session); |
| 87 | - + " and r.sessionid <> w.sessionid " + "),tmp0 as ( " + " select * " + " from tmp_lock tl " | 87 | + |
| 88 | - + " union all " + " select t1.parentid,0::int4,p.wait_status,p.wait_event,null " | 88 | + /** |
| 89 | - + " from tmp_lock t1 left join pg_thread_wait_status p on t1.parentid=p.sessionid " + " where 1=1 " | 89 | + * blockTree |
| 90 | - + " and t1.parentid not in (select id from tmp_lock) " + "), " + " tmp3 as ( " | 90 | + * |
| 91 | - + " SELECT array[id]::text[] as pathid,1 as depth,id,parentid,wait_status,wait_event,lockmode " | 91 | + * @return List |
| 92 | - + " FROM tmp0 " + " where 1=1 " + " and parentid=0 " + " union " | 92 | + */ |
| 93 | - + " SELECT t0.pathid||array[t1.id]::text[] as pathid,t0.depth+1 as depth,t1.id,t1.parentid, " | 93 | + @Select("with recursive tmp_lock as ( " + " select distinct " + " w.sessionid as id, " |
| 94 | - + " t1.wait_status,t1.wait_event,t1.lockmode " + " FROM tmp0 t1, " + " tmp3 t0 " | 94 | + + " r.sessionid as parentid, " + " w.wait_status as wait_status, " |
| 95 | - + " where 1=1 " + " and t1.parentid=t0.id " + ") " + "select distinct " | 95 | + + " w.wait_event as wait_event, " + " w.lockmode as lockmode " + " from ( " |
| 96 | - + " '/'||array_to_string(a0.pathid,'/') as pathid, " + " a0.depth, " | 96 | + + " select a.sessionid,a.locktype,a.database, " |
| 97 | - + " a0.id,a0.parentid, a0.pathid[1] as tree_id, " | 97 | + + " a.relation,a.page,a.tuple,a.classid, " |
| 98 | - + " lpad(a0.id::text, 2*a0.depth-1+length(a0.id::text),' ') as tree, " | 98 | + + " a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid, " |
| 99 | - + " a2.datname,a2.usename,a2.application_name,a2.client_addr,a2.state, " | 99 | + + " a.transactionid, b.query as query, " |
| 100 | - + " TO_CHAR(a2.backend_start,'YYYY-MM-DD HH:MI:SS') as backend_start,a2.query, " | 100 | + + " b.xact_start,b.query_start,b.usename,b.datname ,c.wait_status,c.wait_event,c.lockmode " |
| 101 | - + " a0.wait_status,a0.wait_event,a0.lockmode " + " from tmp3 a0 " | 101 | + + " from pg_locks a " + " left join pg_stat_activity b on a.sessionid=b.sessionid " |
| 102 | - + " left outer join (select distinct '/'||id||'/' as prefix_id,id " | 102 | + + " left join pg_thread_wait_status c on b.sessionid=c.sessionid " |
| 103 | - + " from tmp0 " + " where 1=1 ) a1 " | 103 | + + " where not a.granted " + " ) w, " + " ( " |
| 104 | - + " on position( a1.prefix_id in '/'||array_to_string(a0.pathid,'/')||'/' ) >0 " | 104 | + + " select a.sessionid,a.locktype,a.database, " |
| 105 | - + " left outer join pg_stat_activity a2 " + " on a0.id = a2.sessionid " | 105 | + + " a.relation,a.page,a.tuple,a.classid, " |
| 106 | - + "order by '/'||array_to_string(a0.pathid,'/'),a0.depth;"; | 106 | + + " a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid, " |
| 107 | - private final String SESSION_SIMPLE_MES_SQL = "select a.max_conn, b.active, c.waiting, d.max_runtime from " | 107 | + + " a.transactionid, b.query as query, " |
| 108 | - + "(select setting::int max_conn, 1 as key from pg_settings where name='max_connections') a " | 108 | + + " b.xact_start,b.query_start,b.usename,b.datname ,c.wait_status,c.wait_event,c.lockmode " |
| 109 | - + "left join " + "(select count(*) as active, 1 as key from pg_stat_activity where state = 'active') b " | 109 | + + " from pg_locks a " + " left join pg_stat_activity b on a.sessionid=b.sessionid " |
| 110 | - + "on a.key=b.key " + " left join " | 110 | + + " left join pg_thread_wait_status c on b.sessionid=c.sessionid " |
| 111 | - + " (select count(*) as waiting, 1 as key from pg_stat_activity where waiting is true) c " | 111 | + + " where a.granted " + " ) r " + " where 1=1 " |
| 112 | - + " on b.key=c.key " + " left join " | 112 | + + " and r.locktype is not distinct from w.locktype " |
| 113 | - + " (select extract(EPOCH from(max(now() - backend_start)))::INTEGER as max_runtime, 1 as key from " | 113 | + + " and r.database is not distinct from w.database " |
| 114 | - + "pg_stat_activity where application_name not in " | 114 | + + " and r.relation is not distinct from w.relation " |
| 115 | - + "('WLMArbiter','workload','WorkloadMonitor','WDRSnapshot','JobScheduler','PercentileJob'" | 115 | + + " and r.page is not distinct from w.page " + " and r.tuple is not distinct from w.tuple " |
| 116 | - + ",'statement flush thread','Asp','ApplyLauncher') and application_name not like 'DataKit%' ) d " | 116 | + + " and r.classid is not distinct from w.classid " |
| 117 | - + " on c.key = d.key"; | 117 | + + " and r.objid is not distinct from w.objid " |
| 118 | - private final String LONG_TXC_SQL = "SELECT pid,sessionid,usename,datname,application_name," | 118 | + + " and r.objsubid is not distinct from w.objsubid " |
| 119 | - + "client_addr,query, xact_start, now() - xact_start xact_duration, query_start, now() - query_start " | 119 | + + " and r.transactionid is not distinct from w.transactionid " |
| 120 | - + "query_duration, STATE FROM pg_stat_activity WHERE STATE <>'idle' and application_name not in " | 120 | + + " and r.sessionid <> w.sessionid " + "),tmp0 as ( " + " select * " + " from tmp_lock tl " |
| 121 | - + "('WLMArbiter','workload'," | 121 | + + " union all " + " select t1.parentid,0::int4,p.wait_status,p.wait_event,null " |
| 122 | - + "'WorkloadMonitor','WDRSnapshot','JobScheduler','PercentileJob','statement flush thread','Asp'," | 122 | + + " from tmp_lock t1 left join pg_thread_wait_status p on t1.parentid=p.sessionid " + " where 1=1 " |
| 123 | - + "'ApplyLauncher') and application_name not like 'DataKit%' " | 123 | + + " and t1.parentid not in (select id from tmp_lock) " + "), " + " tmp3 as ( " |
| 124 | - + "and now()-xact_start > interval '30 SECOND' " + "ORDER BY xact_start;"; | 124 | + + " SELECT array[id]::text[] as pathid,1 as depth,id,parentid,wait_status,wait_event,lockmode " |
| 125 | - private final ClusterManager clusterManager; | 125 | + + " FROM tmp0 " + " where 1=1 " + " and parentid=0 " + " union " |
| 126 | - | 126 | + + " SELECT t0.pathid||array[t1.id]::text[] as pathid,t0.depth+1 as depth,t1.id,t1.parentid, " |
| 127 | - @Override | 127 | + + " t1.wait_status,t1.wait_event,t1.lockmode " + " FROM tmp0 t1, " + " tmp3 t0 " |
| 128 | - public String getDatabaseType() { | 128 | + + " where 1=1 " + " and t1.parentid=t0.id " + ") " + "select distinct " |
| 129 | - return DatabaseType.DEFAULT.getDbType(); | 129 | + + " '/'||array_to_string(a0.pathid,'/') as pathid, " + " a0.depth, " |
| 130 | - } | 130 | + + " a0.id,a0.parentid, a0.pathid[1] as tree_id, " |
| 131 | - | 131 | + + " lpad(a0.id::text, 2*a0.depth-1+length(a0.id::text),' ') as tree, " |
| 132 | - @Override | 132 | + + " a2.datname,a2.usename,a2.application_name,a2.client_addr::text client_addr,a2.state, " |
| 133 | - public Connection getConnection(InstanceNodeInfo nodeInfo) { | 133 | + + " TO_CHAR(a2.backend_start,'YYYY-MM-DD HH:MI:SS') as backend_start,a2.query, " |
| 134 | - Connection connection = clusterManager.getConnectionByNodeInfo(nodeInfo); | 134 | + + " a0.wait_status,a0.wait_event,a0.lockmode " + " from tmp3 a0 " |
| 135 | - if (!testConnection(connection)) { | 135 | + + " left outer join (select distinct '/'||id||'/' as prefix_id,id " |
| 136 | - return null; | 136 | + + " from tmp0 " + " where 1=1 ) a1 " |
| 137 | - } | 137 | + + " on position( a1.prefix_id in '/'||array_to_string(a0.pathid,'/')||'/' ) >0 " |
| 138 | - return connection; | 138 | + + " left outer join pg_stat_activity a2 " + " on a0.id = a2.sessionid " |
| 139 | - } | 139 | + + "order by '/'||array_to_string(a0.pathid,'/'),a0.depth;") |
| 140 | - | 140 | + List<Map<String, Object>> blockTree(); |
| 141 | - @Override | 141 | + |
| 142 | - public void close(Connection connection) { | 142 | + /** |
| 143 | - if (connection != null) { | 143 | + * simpleStatistic |
| 144 | - try { | 144 | + * |
| 145 | - connection.close(); | 145 | + * @return Map |
| 146 | - } catch (SQLException e) { | 146 | + */ |
| 147 | - throw new InstanceException("", e); | 147 | + @Select("select a.max_conn, b.active, c.waiting, d.max_runtime from " |
| 148 | - } | 148 | + + "(select setting::int max_conn, 1 as key from pg_settings where name='max_connections') a " |
| 149 | - } | 149 | + + "left join " + "(select count(*) as active, 1 as key from pg_stat_activity where state = 'active') b " |
| 150 | - } | 150 | + + "on a.key=b.key " + " left join " |
| 151 | - | 151 | + + " (select count(*) as waiting, 1 as key from pg_stat_activity where waiting is true) c " |
| 152 | - @Override | 152 | + + " on b.key=c.key " + " left join " |
| 153 | - public JSONObject detailGeneral(Connection conn, String sessionid) { | 153 | + + " (select extract(EPOCH from(max(now() - backend_start)))::INTEGER as max_runtime, 1 as key from " |
| 154 | - JSONObject res = new JSONObject(); | 154 | + + "pg_stat_activity where application_name not in " |
| 155 | - try { | 155 | + + "('WLMArbiter','workload','WorkloadMonitor','WDRSnapshot','JobScheduler','PercentileJob'" |
| 156 | - if (conn == null) { | 156 | + + ",'statement flush thread','Asp','ApplyLauncher') and application_name not like 'DataKit%' ) d " |
| 157 | - throw new InstanceException(CommonConstants.CONNECTION_FAIL); | 157 | + + " on c.key = d.key") |
| 158 | - } | 158 | + Map<String, Object> simpleStatistic(); |
| 159 | - PreparedStatement generalMesStm = conn.prepareStatement(SESSION_GENERAL_MES_SQL); | 159 | + |
| 160 | - generalMesStm.setLong(1, Long.parseLong(sessionid)); | 160 | + /** |
| 161 | - List<JSONObject> generalMesList = executeQuery(generalMesStm); | 161 | + * longTxc |
| 162 | - if (generalMesList.size() == 0) { | 162 | + * |
| 163 | - throw new InstanceException("session.detail.general.message"); | 163 | + * @return List |
| 164 | - } | 164 | + */ |
| 165 | - res.putAll(generalMesList.get(0)); | 165 | + @Select("SELECT pid,sessionid,usename,datname,application_name," |
| 166 | - if (!checkSessionIsWaiting(conn, sessionid)) { | 166 | + + "client_addr::text client_addr,query, xact_start, (now() - xact_start)::text xact_duration, query_start," |
| 167 | - return res; | 167 | + + " (now() - query_start)::text query_duration, STATE FROM pg_stat_activity WHERE STATE <>'idle' " |
| 168 | - } | 168 | + + "and application_name not in ('WLMArbiter','workload'," |
| 169 | - PreparedStatement blockStm = conn.prepareStatement(SESSION_BLOCK_MES_SQL); | 169 | + + "'WorkloadMonitor','WDRSnapshot','JobScheduler','PercentileJob','statement flush thread','Asp'," |
| 170 | - blockStm.setLong(1, Long.parseLong(sessionid)); | 170 | + + "'ApplyLauncher') and application_name not like 'DataKit%' " |
| 171 | - List<JSONObject> blockList = executeQuery(blockStm); | 171 | + + "and now()-xact_start > interval '30 SECOND' " + "ORDER BY xact_start;") |
| 172 | - if (blockList.size() != 0) { | 172 | + List<Map<String, Object>> longTxc(); |
| 173 | - res.putAll(blockList.get(0)); | ||
| 174 | - // throw new InstanceException(SESSION_DETAIL_BLOCK_MESSAGE, blockList.size()); | ||
| 175 | - } | ||
| 176 | - } catch (SQLException e) { | ||
| 177 | - log.error("get session_general_mes list fail", e); | ||
| 178 | - throw new InstanceException(e.getMessage(), e); | ||
| 179 | - } | ||
| 180 | - return res; | ||
| 181 | - } | ||
| 182 | - | ||
| 183 | - | ||
| 184 | - public List<DetailStatisticDto> detailStatistic(Connection conn, String sessionid) { | ||
| 185 | - ArrayList<DetailStatisticDto> list = new ArrayList<>(); | ||
| 186 | - if (conn == null) { | ||
| 187 | - throw new InstanceException(CommonConstants.CONNECTION_FAIL); | ||
| 188 | - } | ||
| 189 | - try { | ||
| 190 | - PreparedStatement statisticStm = conn.prepareStatement(SESSION_STATISTIC_SQL); | ||
| 191 | - statisticStm.setLong(1, Long.parseLong(sessionid)); | ||
| 192 | - List<JSONObject> statisticList = executeQuery(statisticStm); | ||
| 193 | - PreparedStatement runtimeStm = conn.prepareStatement(SESSION_RUNTIME_SQL); | ||
| 194 | - runtimeStm.setLong(1, Long.parseLong(sessionid)); | ||
| 195 | - List<JSONObject> runtimeList = executeQuery(runtimeStm); | ||
| 196 | - List<DetailStatisticDto> list1 = statisticList.stream() | ||
| 197 | - .map(ob -> new DetailStatisticDto(DetailStatisticDto.Type.STATUS, ob.getString("stat_name"), | ||
| 198 | - ob.getString("value"))) | ||
| 199 | - .collect(Collectors.toList()); | ||
| 200 | - List<DetailStatisticDto> list2 = runtimeList.stream() | ||
| 201 | - .map(ob -> new DetailStatisticDto(DetailStatisticDto.Type.RUNTIME, ob.getString("statname"), | ||
| 202 | - ob.getString("value"))) | ||
| 203 | - .collect(Collectors.toList()); | ||
| 204 | - list.addAll(list1); | ||
| 205 | - list.addAll(list2); | ||
| 206 | - } catch (SQLException e) { | ||
| 207 | - throw new RuntimeException(e); | ||
| 208 | - } | ||
| 209 | - return list; | ||
| 210 | - } | ||
| 211 | - | ||
| 212 | - | ||
| 213 | - public List<JSONObject> detailWaiting(Connection conn, String sessionid) { | ||
| 214 | - List<JSONObject> list = new ArrayList<>(); | ||
| 215 | - if (conn == null) { | ||
| 216 | - throw new InstanceException(CommonConstants.CONNECTION_FAIL); | ||
| 217 | - } | ||
| 218 | - try { | ||
| 219 | - PreparedStatement stm = conn.prepareStatement(SESSION_WAITING_REC_SQL); | ||
| 220 | - stm.setLong(1, Long.parseLong(sessionid)); | ||
| 221 | - list = executeQuery(stm); | ||
| 222 | - } catch (SQLException e) { | ||
| 223 | - throw new RuntimeException(e); | ||
| 224 | - } | ||
| 225 | - return list; | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | - | ||
| 229 | - public List<JSONObject> detailBlockTree(Connection conn, String sessionid) { | ||
| 230 | - List<JSONObject> queryList; | ||
| 231 | - if (conn == null) { | ||
| 232 | - throw new InstanceException(CommonConstants.CONNECTION_FAIL); | ||
| 233 | - } | ||
| 234 | - try { | ||
| 235 | - PreparedStatement stm = conn.prepareStatement(SESSION_BLOCK_TREE); | ||
| 236 | - queryList = executeQuery(stm); | ||
| 237 | - } catch (SQLException e) { | ||
| 238 | - throw new RuntimeException(e); | ||
| 239 | - } | ||
| 240 | - if (StringUtils.isNotEmpty(sessionid)) { | ||
| 241 | - Set<String> treeIdSet = queryList.stream().filter(obj -> obj.getString("pathid").contains(sessionid)) | ||
| 242 | - .map(obj -> obj.getString("tree_id")).collect(Collectors.toSet()); | ||
| 243 | - queryList = queryList.stream().filter(obj -> treeIdSet.contains(obj.getString("tree_id"))) | ||
| 244 | - .collect(Collectors.toList()); | ||
| 245 | - } | ||
| 246 | - return toTreeData(queryList); | ||
| 247 | - } | ||
| 248 | - | ||
| 249 | - | ||
| 250 | - public JSONObject simpleStatistic(Connection conn) { | ||
| 251 | - List<JSONObject> queryList; | ||
| 252 | - if (conn == null) { | ||
| 253 | - throw new InstanceException(CommonConstants.CONNECTION_FAIL); | ||
| 254 | - } | ||
| 255 | - try { | ||
| 256 | - PreparedStatement stm = conn.prepareStatement(SESSION_SIMPLE_MES_SQL); | ||
| 257 | - queryList = executeQuery(stm); | ||
| 258 | - } catch (SQLException e) { | ||
| 259 | - throw new RuntimeException(e); | ||
| 260 | - } | ||
| 261 | - return queryList.get(0); | ||
| 262 | - } | ||
| 263 | - | ||
| 264 | - | ||
| 265 | - public List<JSONObject> longTxc(Connection conn) { | ||
| 266 | - List<JSONObject> queryList; | ||
| 267 | - if (conn == null) { | ||
| 268 | - throw new InstanceException(CommonConstants.CONNECTION_FAIL); | ||
| 269 | - } | ||
| 270 | - try { | ||
| 271 | - PreparedStatement stm = conn.prepareStatement(LONG_TXC_SQL); | ||
| 272 | - queryList = executeQuery(stm); | ||
| 273 | - } catch (SQLException e) { | ||
| 274 | - throw new RuntimeException(e); | ||
| 275 | - } | ||
| 276 | - return queryList; | ||
| 277 | - } | ||
| 278 | - | ||
| 279 | - private List<JSONObject> executeQuery(PreparedStatement stm) throws SQLException { | ||
| 280 | - List<JSONObject> resList = new ArrayList<>(); | ||
| 281 | - ResultSet rs = stm.executeQuery(); | ||
| 282 | - while (rs.next()) { | ||
| 283 | - JSONObject object = new JSONObject(); | ||
| 284 | - for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { | ||
| 285 | - object.put(rs.getMetaData().getColumnLabel(i), rs.getString(i)); | ||
| 286 | - } | ||
| 287 | - resList.add(object); | ||
| 288 | - } | ||
| 289 | - return resList; | ||
| 290 | - } | ||
| 291 | - | ||
| 292 | - private boolean testConnection(Connection conn) { | ||
| 293 | - if (ObjectUtils.isNotEmpty(conn)) { | ||
| 294 | - try (PreparedStatement preparedStatement = conn.prepareStatement(TEST_SQL)) { | ||
| 295 | - try (ResultSet rs = preparedStatement.executeQuery()) { | ||
| 296 | - return true; | ||
| 297 | - } | ||
| 298 | - } catch (Exception e) { | ||
| 299 | - log.error("test connection fail:{}", e.getMessage()); | ||
| 300 | - throw new InstanceException(e.getMessage()); | ||
| 301 | - } | ||
| 302 | - } | ||
| 303 | - return false; | ||
| 304 | - } | ||
| 305 | - | ||
| 306 | - private List<JSONObject> toTreeData(List<JSONObject> list) { | ||
| 307 | - // Classify by parentid | ||
| 308 | - Map<String, List<JSONObject>> map = new HashMap<>(); | ||
| 309 | - for (JSONObject object : list) { | ||
| 310 | - object.put("children", new ArrayList<>()); | ||
| 311 | - if (!map.containsKey(object.getString("parentid"))) { | ||
| 312 | - LinkedList<JSONObject> obs = new LinkedList<>(); | ||
| 313 | - obs.add(object); | ||
| 314 | - map.put(object.getString("parentid"), obs); | ||
| 315 | - } else { | ||
| 316 | - List<JSONObject> obs = map.get(object.getString("parentid")); | ||
| 317 | - obs.add(object); | ||
| 318 | - } | ||
| 319 | - } | ||
| 320 | - // Get top parent list, wrapper the final tree result | ||
| 321 | - List<JSONObject> topParentList = map.getOrDefault("0", new ArrayList<>()); | ||
| 322 | - // Get all child values recursively | ||
| 323 | - recursionTreeChild(map, topParentList); | ||
| 324 | - | ||
| 325 | - return topParentList; | ||
| 326 | - } | ||
| 327 | - | ||
| 328 | - | ||
| 329 | - public void recursionTreeChild(Map<String, List<JSONObject>> map, List<JSONObject> parentList) { | ||
| 330 | - for (JSONObject object : parentList) { | ||
| 331 | - if (map.containsKey(object.getString("id"))) { | ||
| 332 | - List<JSONObject> newChildren = map.get(object.getString("id")); | ||
| 333 | - List<JSONObject> allChildren = (List<JSONObject>) object.get("children"); | ||
| 334 | - allChildren.addAll(newChildren); | ||
| 335 | - recursionTreeChild(map, allChildren); | ||
| 336 | - } | ||
| 337 | - } | ||
| 338 | - } | ||
| 339 | - | ||
| 340 | - private boolean checkSessionIsWaiting(Connection conn, String sessionid) throws SQLException { | ||
| 341 | - PreparedStatement statement = conn.prepareStatement(CHECK_SESSION_IS_WAIT_SQL); | ||
| 342 | - statement.setLong(1, Long.parseLong(sessionid)); | ||
| 343 | - List<JSONObject> query = executeQuery(statement); | ||
| 344 | - return query.get(0).getIntValue("count") != 0; | ||
| 345 | - } | ||
| 346 | } | 173 | } |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/SnapshotMapper.java+38-0
| @@ -0,0 +1,38 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.mapper; | ||
| 6 | + | ||
| 7 | +import java.util.Date; | ||
| 8 | + | ||
| 9 | +import org.apache.ibatis.annotations.Mapper; | ||
| 10 | + | ||
| 11 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 12 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 13 | +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; | ||
| 14 | +import com.nctigba.observability.instance.aop.Ds; | ||
| 15 | +import com.nctigba.observability.instance.entity.Snapshot; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * SnapshotMapper.java | ||
| 19 | + * | ||
| 20 | + * 2023-08-28 | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | +public interface SnapshotMapper extends BaseMapper<Snapshot> { | ||
| 24 | + /** | ||
| 25 | + * getIdByTime | ||
| 26 | + * | ||
| 27 | + * id id | ||
| 28 | + * column column | ||
| 29 | + * start start | ||
| 30 | + * end end | ||
| 31 | + * Long | ||
| 32 | + */ | ||
| 33 | + | ||
| 34 | + default Long getIdByTime(String id, SFunction<Snapshot, ?> column, Date start, Date end) { | ||
| 35 | + var snapshot = selectOne(Wrappers.<Snapshot>lambdaQuery().between(column, start, end).last(" limit 1")); | ||
| 36 | + return snapshot == null ? 0 : snapshot.getSnapshotId(); | ||
| 37 | + } | ||
| 38 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/TopSqlMapper.java+189-1
| @@ -1,13 +1,201 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.mapper; | 5 | package com.nctigba.observability.instance.mapper; |
| 5 | 6 | ||
| 7 | +import java.util.Collections; | ||
| 8 | +import java.util.List; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 6 | import org.apache.ibatis.annotations.Mapper; | 11 | import org.apache.ibatis.annotations.Mapper; |
| 7 | import org.apache.ibatis.annotations.Select; | 12 | import org.apache.ibatis.annotations.Select; |
| 13 | +import org.opengauss.util.PSQLException; | ||
| 14 | + | ||
| 15 | +import com.nctigba.observability.instance.constants.CommonConstants; | ||
| 16 | +import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; | ||
| 17 | +import com.nctigba.observability.instance.model.IndexAdvice; | ||
| 18 | + | ||
| 19 | +import cn.hutool.core.util.StrUtil; | ||
| 8 | 20 | ||
| 9 | 21 | ||
| 10 | public interface TopSqlMapper { | 22 | public interface TopSqlMapper { |
| 11 | - @Select("select statement_detail_decode(details,'plaintext',false) w from dbe_perf.statement_history where debug_query_id=#{id}") | 23 | + /** |
| 24 | + * current top sql list | ||
| 25 | + * | ||
| 26 | + * curr list top sql | ||
| 27 | + */ | ||
| 28 | + | ||
| 29 | + + "usename,application_name ,datid,pid,sessionid,usesysid,usename,client_addr ,client_hostname,client_port," | ||
| 30 | + + "backend_start ,xact_start ,state_change ,waiting,enqueue,state ,resource_pool,query_id ,query ," | ||
| 31 | + + "connection_info,trace_id from pg_stat_activity where query_start is not null and unique_sql_id != 0 " | ||
| 32 | + + "and duration != 0 order by (now() - query_start) desc limit 10") | ||
| 33 | + List<Map<String, Object>> currentTopsqlList(); | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * history top sql list | ||
| 37 | + * | ||
| 38 | + * topSQLListReq req | ||
| 39 | + * list top sql | ||
| 40 | + */ | ||
| 41 | + | ||
| 42 | + + "finish_time,db_time,cpu_time,execution_time, data_io_time " | ||
| 43 | + + "from dbe_perf.statement_history where debug_query_id != 0 " | ||
| 44 | + + "and finish_time >= #{startTimeTime} and finish_time <= #{finishTimeTime} order by ${orderField} desc," | ||
| 45 | + + "execution_time desc,cpu_time desc,db_time desc limit 10") | ||
| 46 | + List<Map<String, Object>> historyTopsqlList(TopSQLListReq topSQLListReq); | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * sql detail | ||
| 50 | + * | ||
| 51 | + * id sqlId | ||
| 52 | + * detail | ||
| 53 | + */ | ||
| 54 | + | ||
| 55 | + + " application_name , query_start start_time, client_addr || ':' || client_port socket , sessionid " | ||
| 56 | + + "from pg_stat_activity where query_id = #{id} limit 1") | ||
| 57 | + Map<String, Object> currentDetail(String id); | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * statistical info list | ||
| 61 | + * | ||
| 62 | + * id sqlId | ||
| 63 | + * statistical info | ||
| 64 | + */ | ||
| 65 | + | ||
| 66 | + + "start_time, substring(finish_time, 0, 20) finish_time, user_name, application_name, client_addr || ':' " | ||
| 67 | + + "|| client_port socket, n_returned_rows, n_tuples_fetched, n_tuples_returned, n_tuples_inserted," | ||
| 68 | + + " n_tuples_updated, n_tuples_deleted, lock_count, lock_wait_count, lock_max_count, (case when " | ||
| 69 | + + "n_blocks_fetched = 0 then '-' else substring((n_blocks_hit / n_blocks_fetched)* 100, 0, 6)|| '%' end) " | ||
| 70 | + + "as blocks_hit_rate, " + "json_extract_path_text(net_send_info::json,'size') net_send_info_size, " | ||
| 71 | + + "json_extract_path_text(net_recv_info::json,'size') net_recv_info_size, " | ||
| 72 | + + "json_extract_path_text(net_stream_send_info::json,'size') net_stream_send_info_size, " | ||
| 73 | + + "json_extract_path_text(net_stream_recv_info::json,'size') net_stream_recv_info_size, " | ||
| 74 | + + "json_extract_path_text(net_send_info::json,'n_calls') net_send_info_calls, " | ||
| 75 | + + "json_extract_path_text(net_recv_info::json,'n_calls') net_recv_info_calls, " | ||
| 76 | + + "json_extract_path_text(net_stream_send_info::json,'n_calls') net_stream_send_info_calls, " | ||
| 77 | + + "json_extract_path_text(net_stream_recv_info::json,'n_calls') net_stream_recv_info_calls, " | ||
| 78 | + + "json_extract_path_text(net_send_info::json,'time') net_send_info_time, " | ||
| 79 | + + "json_extract_path_text(net_recv_info::json,'time') net_recv_info_time, " | ||
| 80 | + + "json_extract_path_text(net_stream_send_info::json,'time') net_stream_send_info_time, " | ||
| 81 | + + "json_extract_path_text(net_stream_recv_info::json,'time') net_stream_recv_info_time," | ||
| 82 | + + " n_soft_parse, n_hard_parse, db_time/1000 db_time, " | ||
| 83 | + + "cpu_time/1000 cpu_time, (db_time-cpu_time)/1000 wait_time, lock_time/1000 lock_time, " | ||
| 84 | + + "lock_wait_time/1000 lock_wait_time, execution_time/1000 execution_time, parse_time/1000 parse_time," | ||
| 85 | + + " plan_time/1000 plan_time,rewrite_time/1000 rewrite_time, pl_execution_time/ 1000 pl_execution_time, " | ||
| 86 | + + "pl_compilation_time/1000 pl_compilation_time, data_io_time/1000 data_io_time" | ||
| 87 | + + " from dbe_perf.statement_history where debug_query_id = #{id} limit 1") | ||
| 88 | + Map<String, Object> historyDetail(String id); | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * current query plan | ||
| 92 | + * | ||
| 93 | + * id sqlId | ||
| 94 | + * query plan string | ||
| 95 | + */ | ||
| 96 | + | ||
| 97 | + String currentPlan(String id); | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * history query plan for sql | ||
| 101 | + * | ||
| 102 | + * id sqlId | ||
| 103 | + * query plan string | ||
| 104 | + */ | ||
| 105 | + | ||
| 106 | + String historyPlan(String id); | ||
| 107 | + | ||
| 108 | + /** | ||
| 109 | + * history sqlId to sql | ||
| 110 | + * | ||
| 111 | + * id sqlId | ||
| 112 | + * sql string | ||
| 113 | + */ | ||
| 114 | + | ||
| 115 | + String sql(String id); | ||
| 116 | + | ||
| 117 | + /** | ||
| 118 | + * advise for sql | ||
| 119 | + * | ||
| 120 | + * sql sql string | ||
| 121 | + * advises | ||
| 122 | + */ | ||
| 123 | + default List<IndexAdvice> advise(String sql) { | ||
| 124 | + try { | ||
| 125 | + return defAdvise(sql.replace(StrUtil.LF, CommonConstants.BLANK).replace("'", "''")); | ||
| 126 | + } catch (PSQLException e) { | ||
| 127 | + return Collections.emptyList(); | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * advice for sql from db | ||
| 133 | + * | ||
| 134 | + * sql formatted sql string, "{@code '}" to "{@code ''}" and { \n} | ||
| 135 | + * to "{@code }" | ||
| 136 | + * advise map | ||
| 137 | + * PSQLException when sql error | ||
| 138 | + */ | ||
| 139 | + | ||
| 140 | + List<IndexAdvice> defAdvise(String sql) throws PSQLException; | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * current wait event | ||
| 144 | + * | ||
| 145 | + * id sqlId | ||
| 146 | + * wait event | ||
| 147 | + */ | ||
| 148 | + | ||
| 149 | + + "locktag_decode(locktag) as locktag, block_sessionid lo from dbe_perf.LOCAL_ACTIVE_SESSION " | ||
| 150 | + + "where query_id = #{id} union all " | ||
| 151 | + + "select query_id, sessionid, sample_time, wait_status, event, lockmode, locktag_decode(locktag), " | ||
| 152 | + + "block_sessionid lo from GS_ASP where query_id = #{id} ) order by sample_time") | ||
| 153 | + List<Map<String, Object>> currentWaitEvent(String id); | ||
| 154 | + | ||
| 155 | + /** | ||
| 156 | + * history sql wait event | ||
| 157 | + * | ||
| 158 | + * id sqlId | ||
| 159 | + * wait event json | ||
| 160 | + */ | ||
| 161 | + | ||
| 162 | + + "where debug_query_id=#{id}") | ||
| 12 | String waitEvent(String id); | 163 | String waitEvent(String id); |
| 164 | + | ||
| 165 | + /** | ||
| 166 | + * table meta data | ||
| 167 | + * | ||
| 168 | + * relname table relname | ||
| 169 | + * meta data | ||
| 170 | + */ | ||
| 171 | + | ||
| 172 | + + "n_dead_tup, case when n_live_tup + n_dead_tup = 0 then '0.00%' else round(n_dead_tup * 100 /(n_dead_tup " | ||
| 173 | + + "+ n_live_tup), 2)|| '%' end dead_tup_ratio, last_vacuum, last_autovacuum, last_analyze, last_autoanalyze " | ||
| 174 | + + "from pg_catalog.pg_stat_all_tables t1 left join pg_catalog.pg_class t2 on t1.relid = t2.oid " | ||
| 175 | + + "where t1.relname =#{relname} limit 1") | ||
| 176 | + Map<String, Object> tableMetaData(String relname); | ||
| 177 | + | ||
| 178 | + /** | ||
| 179 | + * table structure | ||
| 180 | + * | ||
| 181 | + * relname table relname | ||
| 182 | + * table structure | ||
| 183 | + */ | ||
| 184 | + | ||
| 185 | + + "pg_catalog.pg_attribute a left outer join pg_catalog.pg_description b on a.attrelid = b.objoid and " | ||
| 186 | + + "a.attnum = b.objsubid, pg_catalog.pg_type t where c.relname = #{relname} and a.attnum>0 " | ||
| 187 | + + "and a.attrelid = c.oid and a.atttypid = t.oid limit 1") | ||
| 188 | + List<Map<String, Object>> tableStructure(String relname); | ||
| 189 | + | ||
| 190 | + /** | ||
| 191 | + * index info for table | ||
| 192 | + * | ||
| 193 | + * relname table relname | ||
| 194 | + * index info | ||
| 195 | + */ | ||
| 196 | + | ||
| 197 | + + "pg_catalog.pg_attribute a left outer join pg_catalog.pg_description b on a.attrelid = b.objoid and " | ||
| 198 | + + "a.attnum = b.objsubid, pg_catalog.pg_type t where c.relname = #{relname} and a.attnum>0 and a.attrelid =" | ||
| 199 | + + " c.oid and a.atttypid = t.oid limit 1") | ||
| 200 | + List<Map<String, Object>> indexInfo(String relname); | ||
| 13 | } | 201 | } |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/DictionaryConfig.java+0-40
| @@ -1,40 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.model; | ||
| 6 | - | ||
| 7 | -import com.baomidou.mybatisplus.annotation.TableField; | ||
| 8 | -import com.baomidou.mybatisplus.annotation.TableId; | ||
| 9 | -import com.baomidou.mybatisplus.annotation.TableName; | ||
| 10 | - | ||
| 11 | -import lombok.AllArgsConstructor; | ||
| 12 | -import lombok.Data; | ||
| 13 | -import lombok.NoArgsConstructor; | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | -public class DictionaryConfig { | ||
| 20 | - | ||
| 21 | - String id; | ||
| 22 | - | ||
| 23 | - String nodeId; | ||
| 24 | - String key; | ||
| 25 | - String value; | ||
| 26 | - | ||
| 27 | - public String getId() { | ||
| 28 | - if ("0-0".equals(id)) | ||
| 29 | - return this.id; | ||
| 30 | - return this.id = nodeId + "-" + key; | ||
| 31 | - } | ||
| 32 | - | ||
| 33 | - public DictionaryConfig(String nodeId, String key, String value) { | ||
| 34 | - super(); | ||
| 35 | - this.nodeId = nodeId; | ||
| 36 | - this.key = key; | ||
| 37 | - this.value = value; | ||
| 38 | - this.id = nodeId + "-" + key; | ||
| 39 | - } | ||
| 40 | -} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/ExecutionPlan.java+184-7
| @@ -5,10 +5,19 @@ | |||
| 5 | package com.nctigba.observability.instance.model; | 5 | package com.nctigba.observability.instance.model; |
| 6 | 6 | ||
| 7 | import java.util.ArrayList; | 7 | import java.util.ArrayList; |
| 8 | +import java.util.Arrays; | ||
| 9 | +import java.util.HashSet; | ||
| 10 | +import java.util.LinkedList; | ||
| 8 | import java.util.List; | 11 | import java.util.List; |
| 12 | +import java.util.Set; | ||
| 9 | import java.util.UUID; | 13 | import java.util.UUID; |
| 10 | 14 | ||
| 15 | +import org.opengauss.admin.common.exception.CustomException; | ||
| 16 | + | ||
| 17 | +import com.nctigba.observability.instance.constants.CommonConstants; | ||
| 18 | + | ||
| 11 | import lombok.Data; | 19 | import lombok.Data; |
| 20 | +import lombok.NoArgsConstructor; | ||
| 12 | 21 | ||
| 13 | /** | 22 | /** |
| 14 | * <p> | 23 | * <p> |
| @@ -19,9 +28,10 @@ import lombok.Data; | |||
| 19 | * 2022/10/08 12:39 | 28 | * 2022/10/08 12:39 |
| 20 | */ | 29 | */ |
| 21 | 30 | ||
| 31 | + | ||
| 22 | public class ExecutionPlan { | 32 | public class ExecutionPlan { |
| 23 | // uuid; | 33 | // uuid; |
| 24 | - String id; | 34 | + String id = UUID.randomUUID().toString(); |
| 25 | // operation | 35 | // operation |
| 26 | String nodeType; | 36 | String nodeType; |
| 27 | // object | 37 | // object |
| @@ -31,16 +41,183 @@ public class ExecutionPlan { | |||
| 31 | // total cost | 41 | // total cost |
| 32 | Double totalCost; | 42 | Double totalCost; |
| 33 | // rows | 43 | // rows |
| 34 | - Integer planRows; | 44 | + Integer planRows = 0; |
| 35 | // width | 45 | // width |
| 36 | - Integer planWidth; | 46 | + Integer planWidth = 0; |
| 37 | // condition | 47 | // condition |
| 38 | String joinType; | 48 | String joinType; |
| 39 | // sub nodes | 49 | // sub nodes |
| 40 | - List<ExecutionPlan> children; | 50 | + List<ExecutionPlan> children = new ArrayList<>(); |
| 41 | 51 | ||
| 42 | - public ExecutionPlan() { | 52 | + /** |
| 43 | - this.id = UUID.randomUUID().toString(); | 53 | + * ExecutionPlan |
| 44 | - this.children = new ArrayList<>(); | 54 | + * |
| 55 | + * executionPlan executionPlan | ||
| 56 | + */ | ||
| 57 | + public ExecutionPlan(String executionPlan) { | ||
| 58 | + var splitLines = Arrays.asList(executionPlan.split("\n")); | ||
| 59 | + | ||
| 60 | + LinkedList<String> plan = new LinkedList<>(splitLines); | ||
| 61 | + // remove non-operation or non-condition lines | ||
| 62 | + for (String line : splitLines) { | ||
| 63 | + if ((line.contains("cost=") && !line.contains("Result")) || line.contains(CommonConstants.HASH_COND)) { | ||
| 64 | + continue; | ||
| 65 | + } | ||
| 66 | + plan.remove(line); | ||
| 67 | + } | ||
| 68 | + if (plan.size() == 0) { | ||
| 69 | + throw new CustomException("failResolveExecutionPlan"); | ||
| 70 | + } | ||
| 71 | + processExecutionPlanString(plan.get(0)); | ||
| 72 | + processExecutionPlan(plan.subList(1, plan.size()), 0, this, this.getChildren()); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * generate execution plan tree shape json object | ||
| 77 | + * | ||
| 78 | + * lines lines of execution plan and condition | ||
| 79 | + * previousIndent last level indent length | ||
| 80 | + * plan last level plan | ||
| 81 | + * children last level plan children | ||
| 82 | + */ | ||
| 83 | + private void processExecutionPlan(List<String> lines, int previousIndent, ExecutionPlan plan, | ||
| 84 | + List<ExecutionPlan> children) { | ||
| 85 | + for (int i = 0; i < lines.size(); i++) { | ||
| 86 | + String line = lines.get(i); | ||
| 87 | + // process condition eg. Hash Cond: (s.datid = d.oid) | ||
| 88 | + if (line.contains(CommonConstants.HASH_COND)) { | ||
| 89 | + String[] split = line.split(": "); | ||
| 90 | + plan.setJoinType(split[1]); | ||
| 91 | + continue; | ||
| 92 | + } | ||
| 93 | + // skip processed lines | ||
| 94 | + if (line.isEmpty()) { | ||
| 95 | + continue; | ||
| 96 | + } | ||
| 97 | + String[] indentPlanSplit = line.split("->"); | ||
| 98 | + int currentIndent = indentPlanSplit[0].length(); | ||
| 99 | + // when current indent greater than previous indent, add new children node and | ||
| 100 | + // go into next tree level | ||
| 101 | + if (currentIndent > previousIndent) { | ||
| 102 | + lines.set(i, ""); | ||
| 103 | + ExecutionPlan subPlan = processExecutionPlanString(line); | ||
| 104 | + children.add(subPlan); | ||
| 105 | + processExecutionPlan(lines.subList(i + 1, lines.size()), currentIndent, subPlan, subPlan.getChildren()); | ||
| 106 | + } | ||
| 107 | + // when current indent less than or equals previous indent, return to last level | ||
| 108 | + if (currentIndent <= previousIndent) { | ||
| 109 | + return; | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * parse execution plan line string into object<br> | ||
| 116 | + * e.g. | ||
| 117 | + * { Function Scan on pg_show_all_settings a (cost=0.00..12.50 rows=5 p-time=0 p-rows=0 width=32)} | ||
| 118 | + * | ||
| 119 | + * line execution plan line string | ||
| 120 | + * execution plan line object | ||
| 121 | + */ | ||
| 122 | + private ExecutionPlan processExecutionPlanString(String line) { | ||
| 123 | + if (line.contains(CommonConstants.HASH_COND)) { | ||
| 124 | + return new ExecutionPlan(); | ||
| 125 | + } | ||
| 126 | + ExecutionPlan plan = new ExecutionPlan(); | ||
| 127 | + // check if first line | ||
| 128 | + String planString; | ||
| 129 | + if (line.contains("->")) { | ||
| 130 | + String[] indentPlanSplit = line.split("->"); | ||
| 131 | + planString = indentPlanSplit[1]; | ||
| 132 | + } else { | ||
| 133 | + planString = line; | ||
| 134 | + } | ||
| 135 | + String[] operationParameterSplit = planString.split("\\("); | ||
| 136 | + // set operation name and alias name | ||
| 137 | + String operation = operationParameterSplit[0]; | ||
| 138 | + if (operation.contains(" on ")) { | ||
| 139 | + String[] split = operation.split(" on "); | ||
| 140 | + plan.setNodeType(split[0].trim()); | ||
| 141 | + // only show object name, remove alias name | ||
| 142 | + String objectName = split[1]; | ||
| 143 | + String aliasName; | ||
| 144 | + if (objectName.contains(CommonConstants.BLANK)) { | ||
| 145 | + String[] aliasSplit = objectName.split(CommonConstants.BLANK); | ||
| 146 | + aliasName = aliasSplit[0]; | ||
| 147 | + } else { | ||
| 148 | + aliasName = objectName; | ||
| 149 | + } | ||
| 150 | + plan.setAlias(aliasName); | ||
| 151 | + } else { | ||
| 152 | + plan.setNodeType(operation.trim()); | ||
| 153 | + } | ||
| 154 | + // set parameters | ||
| 155 | + String parameters = operationParameterSplit[1].replace(")", ""); | ||
| 156 | + String[] parametersSplit = parameters.split(CommonConstants.BLANK); | ||
| 157 | + for (String parameterSplit : parametersSplit) { | ||
| 158 | + String[] split = parameterSplit.split("="); | ||
| 159 | + switch (split[0].trim()) { | ||
| 160 | + case "cost": | ||
| 161 | + // set start cost and total cost | ||
| 162 | + String[] startCostTotalCostSplit = split[1].split("\\.\\."); | ||
| 163 | + plan.setStartupCost(Double.parseDouble(startCostTotalCostSplit[0])); | ||
| 164 | + plan.setTotalCost(Double.parseDouble(startCostTotalCostSplit[1])); | ||
| 165 | + break; | ||
| 166 | + case "rows": | ||
| 167 | + // set plan rows | ||
| 168 | + int rowsNum = Integer.parseInt(split[1]); | ||
| 169 | + plan.setPlanRows(rowsNum); | ||
| 170 | + break; | ||
| 171 | + case "width": | ||
| 172 | + // set plan width | ||
| 173 | + int widthNum = Integer.parseInt(split[1]); | ||
| 174 | + plan.setPlanWidth(widthNum); | ||
| 175 | + break; | ||
| 176 | + default: | ||
| 177 | + } | ||
| 178 | + } | ||
| 179 | + return plan; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + /** | ||
| 183 | + * totalPlanRows | ||
| 184 | + * | ||
| 185 | + * int | ||
| 186 | + */ | ||
| 187 | + public int totalPlanRows() { | ||
| 188 | + int rows = planRows; | ||
| 189 | + for (ExecutionPlan executionPlan : children) { | ||
| 190 | + rows += executionPlan.totalPlanRows(); | ||
| 191 | + } | ||
| 192 | + return rows; | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + /** | ||
| 196 | + * totalPlanWidth | ||
| 197 | + * | ||
| 198 | + * int | ||
| 199 | + */ | ||
| 200 | + public int totalPlanWidth() { | ||
| 201 | + int width = planWidth; | ||
| 202 | + for (ExecutionPlan executionPlan : children) { | ||
| 203 | + width += executionPlan.totalPlanWidth(); | ||
| 204 | + } | ||
| 205 | + return width; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + /** | ||
| 209 | + * allAlias | ||
| 210 | + * | ||
| 211 | + * Set | ||
| 212 | + */ | ||
| 213 | + public Set<String> allAlias() { | ||
| 214 | + Set<String> set = new HashSet<>(); | ||
| 215 | + if (alias != null) { | ||
| 216 | + set.add(alias); | ||
| 217 | + } | ||
| 218 | + for (ExecutionPlan executionPlan : children) { | ||
| 219 | + set.addAll(executionPlan.allAlias()); | ||
| 220 | + } | ||
| 221 | + return set; | ||
| 45 | } | 222 | } |
| 46 | } | 223 | } |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/IndexAdvice.java+8-0
| @@ -20,4 +20,12 @@ public class IndexAdvice { | |||
| 20 | String table; | 20 | String table; |
| 21 | String column; | 21 | String column; |
| 22 | String indexType; | 22 | String indexType; |
| 23 | + | ||
| 24 | + public void setIndexType(String indexType) { | ||
| 25 | + this.indexType = indexType; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public void setIndextype(String indexType) { | ||
| 29 | + this.indexType = indexType; | ||
| 30 | + } | ||
| 23 | } | 31 | } |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/InstanceInfo.java+0-22
| @@ -1,22 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.model; | ||
| 6 | - | ||
| 7 | -import java.util.List; | ||
| 8 | - | ||
| 9 | -import lombok.Data; | ||
| 10 | - | ||
| 11 | - | ||
| 12 | -public class InstanceInfo { | ||
| 13 | - private String name; | ||
| 14 | - | ||
| 15 | - private String type; | ||
| 16 | - | ||
| 17 | - private String dbVersion; | ||
| 18 | - | ||
| 19 | - private String remark; | ||
| 20 | - | ||
| 21 | - private List<InstanceInfo> nodeList; | ||
| 22 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/InstanceNodeInfo.java+0-30
| @@ -1,30 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.model; | ||
| 6 | - | ||
| 7 | -import lombok.Data; | ||
| 8 | - | ||
| 9 | - | ||
| 10 | -public class InstanceNodeInfo { | ||
| 11 | - | ||
| 12 | - private String id; | ||
| 13 | - | ||
| 14 | - private String instanceId; | ||
| 15 | - | ||
| 16 | - private String serverId; | ||
| 17 | - | ||
| 18 | - private String ip; | ||
| 19 | - | ||
| 20 | - private int port; | ||
| 21 | - | ||
| 22 | - private String dbUser; | ||
| 23 | - | ||
| 24 | - private String dbUserPassword; | ||
| 25 | - | ||
| 26 | - private String dbName; | ||
| 27 | - | ||
| 28 | - private String dbType; | ||
| 29 | - | ||
| 30 | -} | ||
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/param/ParamQuery.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/ParamQuery.java+1-1
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | -package com.nctigba.observability.instance.model.param; | 5 | +package com.nctigba.observability.instance.model; |
| 6 | 6 | ||
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | import lombok.experimental.Accessors; | 8 | import lombok.experimental.Accessors; |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/PartitionDataResp.java+0-18
| @@ -1,18 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.model; | ||
| 6 | - | ||
| 7 | -import lombok.Data; | ||
| 8 | - | ||
| 9 | - | ||
| 10 | -public class PartitionDataResp { | ||
| 11 | - | ||
| 12 | - String partStrategy; | ||
| 13 | - String partKey; | ||
| 14 | - String relPages; | ||
| 15 | - String relTuples; | ||
| 16 | - String relallVisible; | ||
| 17 | - String interval; | ||
| 18 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/monitoring/MonitoringMetric.java+0-17
| @@ -1,17 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.model.monitoring; | ||
| 6 | - | ||
| 7 | -import com.alibaba.fastjson.JSONArray; | ||
| 8 | -import com.alibaba.fastjson.JSONObject; | ||
| 9 | - | ||
| 10 | -import lombok.Data; | ||
| 11 | - | ||
| 12 | - | ||
| 13 | -public class MonitoringMetric { | ||
| 14 | - private JSONObject metric; | ||
| 15 | - private JSONArray value; | ||
| 16 | - private JSONArray values; | ||
| 17 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/monitoring/MonitoringParam.java+0-34
| @@ -1,34 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.model.monitoring; | ||
| 6 | - | ||
| 7 | -import lombok.Data; | ||
| 8 | - | ||
| 9 | - | ||
| 10 | -public class MonitoringParam { | ||
| 11 | - private String id; | ||
| 12 | - | ||
| 13 | - private String query; | ||
| 14 | - | ||
| 15 | - private String start; | ||
| 16 | - | ||
| 17 | - private String end; | ||
| 18 | - | ||
| 19 | - private String step; | ||
| 20 | - | ||
| 21 | - private String time; | ||
| 22 | - | ||
| 23 | - private String legendName; | ||
| 24 | - | ||
| 25 | - private String field; | ||
| 26 | - | ||
| 27 | - private String filter; | ||
| 28 | - | ||
| 29 | - private String order; | ||
| 30 | - | ||
| 31 | - private String type; | ||
| 32 | - | ||
| 33 | - private String monitoringType; | ||
| 34 | -} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/AspService.java+35-0
| @@ -0,0 +1,35 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import com.nctigba.observability.instance.dto.asp.AnalysisDto; | ||
| 8 | +import com.nctigba.observability.instance.dto.asp.AspCountReq; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * AspService | ||
| 15 | + * | ||
| 16 | + * liupengfei | ||
| 17 | + * 2023/8/11 | ||
| 18 | + */ | ||
| 19 | +public interface AspService { | ||
| 20 | + /** | ||
| 21 | + * count | ||
| 22 | + * | ||
| 23 | + * req AspCountReq | ||
| 24 | + * Map<String, List<Object>> | ||
| 25 | + */ | ||
| 26 | + Map<String, List<Object>> count(AspCountReq req); | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * analysis | ||
| 30 | + * | ||
| 31 | + * req AspCountReq | ||
| 32 | + * List<AnalysisDto> | ||
| 33 | + */ | ||
| 34 | + List<AnalysisDto> analysis(AspCountReq req); | ||
| 35 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ClusterManager.java+54-74
| @@ -4,20 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | package com.nctigba.observability.instance.service; | 5 | package com.nctigba.observability.instance.service; |
| 6 | 6 | ||
| 7 | -import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; | 7 | +import java.sql.Connection; |
| 8 | -import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; | 8 | +import java.sql.DriverManager; |
| 9 | -import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; | 9 | +import java.sql.SQLException; |
| 10 | -import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; | 10 | +import java.util.Collections; |
| 11 | -import com.gitee.starblues.bootstrap.annotation.AutowiredType; | 11 | +import java.util.List; |
| 12 | -import com.gitee.starblues.bootstrap.annotation.AutowiredType.Type; | 12 | +import java.util.Properties; |
| 13 | -import com.nctigba.common.web.exception.InstanceException; | 13 | + |
| 14 | -import com.nctigba.observability.instance.constants.CommonConstants; | 14 | +import javax.sql.DataSource; |
| 15 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | 15 | + |
| 16 | -import lombok.Data; | ||
| 17 | -import lombok.EqualsAndHashCode; | ||
| 18 | -import lombok.NoArgsConstructor; | ||
| 19 | -import lombok.extern.slf4j.Slf4j; | ||
| 20 | import org.apache.commons.lang3.StringUtils; | 16 | import org.apache.commons.lang3.StringUtils; |
| 17 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; | ||
| 21 | import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | 18 | import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; |
| 22 | import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; | 19 | import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; |
| 23 | import org.opengauss.admin.common.exception.CustomException; | 20 | import org.opengauss.admin.common.exception.CustomException; |
| @@ -29,21 +26,26 @@ import org.springframework.beans.factory.annotation.Autowired; | |||
| 29 | import org.springframework.stereotype.Service; | 26 | import org.springframework.stereotype.Service; |
| 30 | import org.springframework.util.CollectionUtils; | 27 | import org.springframework.util.CollectionUtils; |
| 31 | 28 | ||
| 32 | -import javax.sql.DataSource; | 29 | +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; |
| 33 | -import java.sql.Connection; | 30 | +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; |
| 34 | -import java.sql.DriverManager; | 31 | +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; |
| 35 | -import java.sql.SQLException; | 32 | +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; |
| 36 | -import java.util.Collections; | 33 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; |
| 37 | -import java.util.List; | 34 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType.Type; |
| 38 | -import java.util.Properties; | 35 | +import com.nctigba.observability.instance.constants.CommonConstants; |
| 36 | + | ||
| 37 | +import lombok.Data; | ||
| 38 | +import lombok.EqualsAndHashCode; | ||
| 39 | +import lombok.NoArgsConstructor; | ||
| 40 | +import lombok.extern.slf4j.Slf4j; | ||
| 39 | 41 | ||
| 40 | 42 | ||
| 41 | 43 | ||
| 42 | public class ClusterManager { | 44 | public class ClusterManager { |
| 43 | 45 | ||
| 44 | - private DataSource dataSource; | 46 | + DataSource dataSource; |
| 45 | 47 | ||
| 46 | - private DefaultDataSourceCreator dataSourceCreator; | 48 | + DefaultDataSourceCreator dataSourceCreator; |
| 47 | 49 | ||
| 48 | 50 | ||
| 49 | 51 | ||
| @@ -55,6 +57,25 @@ public class ClusterManager { | |||
| 55 | 57 | ||
| 56 | private IOpsClusterService opsClusterService; | 58 | private IOpsClusterService opsClusterService; |
| 57 | 59 | ||
| 60 | + public OpsClusterEntity getClusterByNodeId(String nodeId) { | ||
| 61 | + List<OpsClusterVO> opsClusterVOList = getAllOpsCluster(); | ||
| 62 | + if (CollectionUtils.isEmpty(opsClusterVOList)) { | ||
| 63 | + throw new CustomException(CommonConstants.NODE_NOT_FOUND); | ||
| 64 | + } | ||
| 65 | + for (OpsClusterVO cluster : opsClusterVOList) { | ||
| 66 | + List<OpsClusterNodeVO> nodes = cluster.getClusterNodes(); | ||
| 67 | + if (CollectionUtils.isEmpty(nodes)) { | ||
| 68 | + continue; | ||
| 69 | + } | ||
| 70 | + for (OpsClusterNodeVO clusterNode : nodes) { | ||
| 71 | + if (nodeId.equals(clusterNode.getNodeId())) { | ||
| 72 | + return opsClusterService.getById(cluster.getClusterId()); | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + throw new CustomException(CommonConstants.NODE_NOT_FOUND); | ||
| 77 | + } | ||
| 78 | + | ||
| 58 | public Connection getConnectionByClusterHost(String clusterId, String hostId) { | 79 | public Connection getConnectionByClusterHost(String clusterId, String hostId) { |
| 59 | var clusterEntity = opsClusterService.getById(clusterId); | 80 | var clusterEntity = opsClusterService.getById(clusterId); |
| 60 | var hostEntity = hostFacade.getById(hostId); | 81 | var hostEntity = hostFacade.getById(hostId); |
| @@ -66,11 +87,20 @@ public class ClusterManager { | |||
| 66 | try { | 87 | try { |
| 67 | return DriverManager.getConnection(sourceURL, info); | 88 | return DriverManager.getConnection(sourceURL, info); |
| 68 | } catch (SQLException e) { | 89 | } catch (SQLException e) { |
| 69 | - e.printStackTrace(); | 90 | + throw new CustomException("connection fail", e); |
| 70 | - throw new RuntimeException("connection fail"); | ||
| 71 | } | 91 | } |
| 72 | } | 92 | } |
| 73 | 93 | ||
| 94 | + /** | ||
| 95 | + * Set the current data source and manually clear it | ||
| 96 | + * | ||
| 97 | + * com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder#push(String) | ||
| 98 | + * com.nctigba.observability.instance.service.ClusterManager#pool() | ||
| 99 | + */ | ||
| 100 | + public void setCurrentDatasource(String nodeId) { | ||
| 101 | + setCurrentDatasource(nodeId, null); | ||
| 102 | + } | ||
| 103 | + | ||
| 74 | /** | 104 | /** |
| 75 | * Set the current data source and manually clear it | 105 | * Set the current data source and manually clear it |
| 76 | * | 106 | * |
| @@ -126,26 +156,6 @@ public class ClusterManager { | |||
| 126 | BeanUtils.copyProperties(opsClusterNodeVO, this); | 156 | BeanUtils.copyProperties(opsClusterNodeVO, this); |
| 127 | this.version = version; | 157 | this.version = version; |
| 128 | } | 158 | } |
| 129 | - | ||
| 130 | - public Connection connection() throws SQLException { | ||
| 131 | - var conn = DriverManager.getConnection( | ||
| 132 | - CommonConstants.JDBC_OPENGAUSS + getPublicIp() + ":" + getDbPort() + "/" + getDbName(), getDbUser(), | ||
| 133 | - getDbUserPassword()); | ||
| 134 | - try (var preparedStatement = conn.prepareStatement("select 1"); | ||
| 135 | - var rs = preparedStatement.executeQuery();) { | ||
| 136 | - return conn; | ||
| 137 | - } catch (Exception e) { | ||
| 138 | - log.error("test connection fail:{}", e.getMessage()); | ||
| 139 | - throw e; | ||
| 140 | - } | ||
| 141 | - } | ||
| 142 | - } | ||
| 143 | - | ||
| 144 | - /** | ||
| 145 | - * Directly obtain the connection of the specified node | ||
| 146 | - */ | ||
| 147 | - public Connection getConnectionByNodeId(String nodeId) throws SQLException { | ||
| 148 | - return getOpsNodeById(nodeId).connection(); | ||
| 149 | } | 159 | } |
| 150 | 160 | ||
| 151 | /** | 161 | /** |
| @@ -167,34 +177,4 @@ public class ClusterManager { | |||
| 167 | } | 177 | } |
| 168 | throw new CustomException(CommonConstants.NODE_NOT_FOUND); | 178 | throw new CustomException(CommonConstants.NODE_NOT_FOUND); |
| 169 | } | 179 | } |
| 170 | - | ||
| 171 | - /** | ||
| 172 | - * get openGauss jdbc-connection by NodeInfo | ||
| 173 | - * | ||
| 174 | - * nodeInfo nodeInfo | ||
| 175 | - * jdbc Connection | ||
| 176 | - */ | ||
| 177 | - public Connection getConnectionByNodeInfo(InstanceNodeInfo nodeInfo) { | ||
| 178 | - try { | ||
| 179 | - Connection connection; | ||
| 180 | - if (!(dataSource instanceof DynamicRoutingDataSource)) { | ||
| 181 | - throw new InstanceException("dataSource is not type of DynamicRoutingDataSource"); | ||
| 182 | - } | ||
| 183 | - var dynamicRoutingDataSource = (DynamicRoutingDataSource) dataSource; | ||
| 184 | - if (dynamicRoutingDataSource.getDataSources().containsKey(nodeInfo.getId())) { | ||
| 185 | - connection = dynamicRoutingDataSource.getDataSource(nodeInfo.getId()).getConnection(); | ||
| 186 | - } else { | ||
| 187 | - DataSource newDataSource = dataSourceCreator.createDataSource(new DataSourceProperty() | ||
| 188 | - .setDriverClassName("org.opengauss.Driver") | ||
| 189 | - .setUrl(CommonConstants.JDBC_OPENGAUSS + nodeInfo.getIp() + ":" + nodeInfo.getPort() + "/" | ||
| 190 | - + nodeInfo.getDbName()) | ||
| 191 | - .setUsername(nodeInfo.getDbUser()).setPassword(nodeInfo.getDbUserPassword())); | ||
| 192 | - dynamicRoutingDataSource.addDataSource(nodeInfo.getId(), newDataSource); | ||
| 193 | - connection = newDataSource.getConnection(); | ||
| 194 | - } | ||
| 195 | - return connection; | ||
| 196 | - } catch (SQLException e) { | ||
| 197 | - throw new InstanceException(e.getMessage(), e); | ||
| 198 | - } | ||
| 199 | - } | ||
| 200 | } | 180 | } |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ClusterOpsService.java+70-0
| @@ -0,0 +1,70 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +import com.alibaba.fastjson.JSONObject; | ||
| 11 | +import com.nctigba.observability.instance.dto.cluster.ClusterStateDto; | ||
| 12 | +import com.nctigba.observability.instance.dto.cluster.ClustersDto; | ||
| 13 | +import com.nctigba.observability.instance.dto.cluster.NodeRelationDto; | ||
| 14 | +import com.nctigba.observability.instance.dto.cluster.SyncSituationDto; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * ClusterOpsService | ||
| 18 | + * | ||
| 19 | + * liupengfei | ||
| 20 | + * 2023/8/11 | ||
| 21 | + */ | ||
| 22 | +public interface ClusterOpsService { | ||
| 23 | + /** | ||
| 24 | + * listClusters | ||
| 25 | + * | ||
| 26 | + * ClustersDto | ||
| 27 | + */ | ||
| 28 | + List<ClustersDto> listClusters(); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * nodes | ||
| 32 | + * | ||
| 33 | + * clusterId String | ||
| 34 | + * List<JSONObject> | ||
| 35 | + */ | ||
| 36 | + List<JSONObject> nodes(String clusterId); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * relation | ||
| 40 | + * | ||
| 41 | + * clusterId String | ||
| 42 | + * List<NodeRelationDto> | ||
| 43 | + */ | ||
| 44 | + List<NodeRelationDto> relation(String clusterId); | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * allClusterState | ||
| 48 | + * | ||
| 49 | + * ClusterStateDto | ||
| 50 | + */ | ||
| 51 | + List<ClusterStateDto> allClusterState(); | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * allStandbyNodes | ||
| 55 | + * | ||
| 56 | + * SyncSituationDto | ||
| 57 | + */ | ||
| 58 | + List<SyncSituationDto> allStandbyNodes(); | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * clusterMetrics | ||
| 62 | + * | ||
| 63 | + * clusterId String | ||
| 64 | + * start Long | ||
| 65 | + * end Long | ||
| 66 | + * step Integer | ||
| 67 | + * Map<String, Object> | ||
| 68 | + */ | ||
| 69 | + Map<String, Object> clusterMetrics(String clusterId, Long start, Long end, Integer step); | ||
| 70 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ExporterInstallService.java+4-3
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.service; | 5 | package com.nctigba.observability.instance.service; |
| 5 | 6 | ||
| 6 | import java.io.File; | 7 | import java.io.File; |
| @@ -16,6 +17,7 @@ import java.util.LinkedHashSet; | |||
| 16 | import java.util.Map; | 17 | import java.util.Map; |
| 17 | 18 | ||
| 18 | import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | 19 | import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; |
| 20 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 19 | import org.opengauss.admin.common.core.domain.model.ops.WsSession; | 21 | import org.opengauss.admin.common.core.domain.model.ops.WsSession; |
| 20 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
| 21 | import org.springframework.core.io.ResourceLoader; | 23 | import org.springframework.core.io.ResourceLoader; |
| @@ -26,7 +28,6 @@ import com.nctigba.observability.instance.constants.CommonConstants; | |||
| 26 | import com.nctigba.observability.instance.entity.NctigbaEnv; | 28 | import com.nctigba.observability.instance.entity.NctigbaEnv; |
| 27 | import com.nctigba.observability.instance.entity.NctigbaEnv.envType; | 29 | import com.nctigba.observability.instance.entity.NctigbaEnv.envType; |
| 28 | import com.nctigba.observability.instance.service.AbstractInstaller.Step.status; | 30 | import com.nctigba.observability.instance.service.AbstractInstaller.Step.status; |
| 29 | -import com.nctigba.observability.instance.service.ClusterManager.OpsClusterNodeVOSub; | ||
| 30 | import com.nctigba.observability.instance.service.PrometheusService.prometheusConfig; | 31 | import com.nctigba.observability.instance.service.PrometheusService.prometheusConfig; |
| 31 | import com.nctigba.observability.instance.service.PrometheusService.prometheusConfig.job; | 32 | import com.nctigba.observability.instance.service.PrometheusService.prometheusConfig.job; |
| 32 | import com.nctigba.observability.instance.util.Download; | 33 | import com.nctigba.observability.instance.util.Download; |
| @@ -236,7 +237,7 @@ public class ExporterInstallService extends AbstractInstaller { | |||
| 236 | } | 237 | } |
| 237 | } | 238 | } |
| 238 | 239 | ||
| 239 | - private void uninstallExporter(WsSession wsSession, ArrayList<Step> steps, int curr, OpsClusterNodeVOSub node) { | 240 | + private void uninstallExporter(WsSession wsSession, ArrayList<Step> steps, int curr, OpsClusterNodeVO node) { |
| 240 | var exporterList = envMapper.selectList(Wrappers.<NctigbaEnv>lambdaQuery() | 241 | var exporterList = envMapper.selectList(Wrappers.<NctigbaEnv>lambdaQuery() |
| 241 | .eq(NctigbaEnv::getType, envType.EXPORTER).eq(NctigbaEnv::getHostid, node.getHostId())); | 242 | .eq(NctigbaEnv::getType, envType.EXPORTER).eq(NctigbaEnv::getHostid, node.getHostId())); |
| 242 | var exporterenv = exporterList.isEmpty() ? null : exporterList.get(0); | 243 | var exporterenv = exporterList.isEmpty() ? null : exporterList.get(0); |
| @@ -285,7 +286,7 @@ public class ExporterInstallService extends AbstractInstaller { | |||
| 285 | } | 286 | } |
| 286 | 287 | ||
| 287 | private void uninstallNodeAndGaussExporter(WsSession wsSession, ArrayList<Step> steps, int curr, | 288 | private void uninstallNodeAndGaussExporter(WsSession wsSession, ArrayList<Step> steps, int curr, |
| 288 | - OpsClusterNodeVOSub node) throws IOException { | 289 | + OpsClusterNodeVO node) throws IOException { |
| 289 | var nodeenvList = envMapper.selectList(Wrappers.<NctigbaEnv>lambdaQuery() | 290 | var nodeenvList = envMapper.selectList(Wrappers.<NctigbaEnv>lambdaQuery() |
| 290 | .eq(NctigbaEnv::getType, envType.NODE_EXPORTER).eq(NctigbaEnv::getHostid, node.getHostId())); | 291 | .eq(NctigbaEnv::getType, envType.NODE_EXPORTER).eq(NctigbaEnv::getHostid, node.getHostId())); |
| 291 | var nodeenv = nodeenvList.isEmpty() ? null : nodeenvList.get(0); | 292 | var nodeenv = nodeenvList.isEmpty() ? null : nodeenvList.get(0); |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/MetricsService.java+10-7
| @@ -23,7 +23,6 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
| 23 | import com.gitee.starblues.bootstrap.annotation.AutowiredType; | 23 | import com.gitee.starblues.bootstrap.annotation.AutowiredType; |
| 24 | import com.nctigba.observability.instance.constants.MetricsLine; | 24 | import com.nctigba.observability.instance.constants.MetricsLine; |
| 25 | import com.nctigba.observability.instance.constants.MetricsValue; | 25 | import com.nctigba.observability.instance.constants.MetricsValue; |
| 26 | -import com.nctigba.observability.instance.constants.MonitoringConstants; | ||
| 27 | import com.nctigba.observability.instance.entity.NctigbaEnv; | 26 | import com.nctigba.observability.instance.entity.NctigbaEnv; |
| 28 | import com.nctigba.observability.instance.mapper.NctigbaEnvMapper; | 27 | import com.nctigba.observability.instance.mapper.NctigbaEnvMapper; |
| 29 | import com.nctigba.observability.instance.service.MetricsService.PrometheusResult.PromData.MonitoringMetric; | 28 | import com.nctigba.observability.instance.service.MetricsService.PrometheusResult.PromData.MonitoringMetric; |
| @@ -39,6 +38,11 @@ import lombok.extern.log4j.Log4j2; | |||
| 39 | 38 | ||
| 40 | 39 | ||
| 41 | public class MetricsService { | 40 | public class MetricsService { |
| 41 | + // prometheus query ?query={query} | ||
| 42 | + private static final String PROMETHEUS_QUERY_POINT = "/api/v1/query"; | ||
| 43 | + | ||
| 44 | + // prometheus range query ?query={query}&start={start}&end={end}&step={step} | ||
| 45 | + private static final String PROMETHEUS_QUERY_RANGE = "/api/v1/query_range"; | ||
| 42 | private static final String TIME = "time"; | 46 | private static final String TIME = "time"; |
| 43 | private static final Map<String, String> PROM = new HashMap<>(); | 47 | private static final Map<String, String> PROM = new HashMap<>(); |
| 44 | private static final String DEFAULT = "DEFAULT"; | 48 | private static final String DEFAULT = "DEFAULT"; |
| @@ -85,8 +89,7 @@ public class MetricsService { | |||
| 85 | throw new NullPointerException("query null"); | 89 | throw new NullPointerException("query null"); |
| 86 | } | 90 | } |
| 87 | log.info("promQL:{}, time:{}", query, time); | 91 | log.info("promQL:{}, time:{}", query, time); |
| 88 | - var prometheusResult = query(MonitoringConstants.PROMETHEUS_QUERY_POINT, query, | 92 | + var prometheusResult = query(PROMETHEUS_QUERY_POINT, query, Map.of("query", query, "time", time)); |
| 89 | - Map.of("query", query, "time", time)); | ||
| 90 | return prometheusResult.getData().getResult(); | 93 | return prometheusResult.getData().getResult(); |
| 91 | } | 94 | } |
| 92 | 95 | ||
| @@ -104,12 +107,12 @@ public class MetricsService { | |||
| 104 | return Collections.emptyList(); | 107 | return Collections.emptyList(); |
| 105 | } | 108 | } |
| 106 | log.info("promQL:{}, start:{}, end:{}, step:{}", query, start, end, step); | 109 | log.info("promQL:{}, start:{}, end:{}, step:{}", query, start, end, step); |
| 107 | - var prometheusResult = query(MonitoringConstants.PROMETHEUS_QUERY_RANGE, query, | 110 | + var prometheusResult = query(PROMETHEUS_QUERY_RANGE, query, |
| 108 | Map.of("query", query, "start", start, "end", end, "step", step)); | 111 | Map.of("query", query, "start", start, "end", end, "step", step)); |
| 109 | return prometheusResult.getData().getResult(); | 112 | return prometheusResult.getData().getResult(); |
| 110 | } | 113 | } |
| 111 | 114 | ||
| 112 | - public HashMap<String, Object> listBatch(Enum<?>[] metricsArr, String nodeId, Long start, Long end, Integer step) { | 115 | + public Map<String, Object> listBatch(Enum<?>[] metricsArr, String nodeId, Long start, Long end, Integer step) { |
| 113 | var result = new HashMap<String, Object>(); | 116 | var result = new HashMap<String, Object>(); |
| 114 | var node = clusterManager.getOpsNodeById(nodeId); | 117 | var node = clusterManager.getOpsNodeById(nodeId); |
| 115 | List<Long> timeline = new ArrayList<>(); | 118 | List<Long> timeline = new ArrayList<>(); |
| @@ -164,7 +167,7 @@ public class MetricsService { | |||
| 164 | var map = new HashMap<String, Object>(); | 167 | var map = new HashMap<String, Object>(); |
| 165 | for (var monitoringMetric : metric) { | 168 | for (var monitoringMetric : metric) { |
| 166 | if (template == null) | 169 | if (template == null) |
| 167 | - throw new NullPointerException(promQl); | 170 | + return metric.get(0).getValue().get(1); |
| 168 | String key = StrUtil.format(template, monitoringMetric.getMetric()); | 171 | String key = StrUtil.format(template, monitoringMetric.getMetric()); |
| 169 | map.put(key, monitoringMetric.getValue().get(1)); | 172 | map.put(key, monitoringMetric.getValue().get(1)); |
| 170 | } | 173 | } |
| @@ -181,7 +184,7 @@ public class MetricsService { | |||
| 181 | var map = new HashMap<String, Object>(); | 184 | var map = new HashMap<String, Object>(); |
| 182 | for (var monitoringMetric : metric) { | 185 | for (var monitoringMetric : metric) { |
| 183 | if (template == null) { | 186 | if (template == null) { |
| 184 | - throw new NullPointerException(promQl); | 187 | + return ListUtil.collect(metric.get(0).getValues(), timeline); |
| 185 | } | 188 | } |
| 186 | String key = StrUtil.format(template, monitoringMetric.getMetric()); | 189 | String key = StrUtil.format(template, monitoringMetric.getMetric()); |
| 187 | var lineNumber = ListUtil.collect(monitoringMetric.getValues(), timeline); | 190 | var lineNumber = ListUtil.collect(monitoringMetric.getValues(), timeline); |
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/MonitoringService.java+0-19
| @@ -1,19 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.service; | ||
| 5 | - | ||
| 6 | -import java.util.List; | ||
| 7 | -import java.util.Map; | ||
| 8 | - | ||
| 9 | -import com.nctigba.observability.instance.model.monitoring.MonitoringMetric; | ||
| 10 | -import com.nctigba.observability.instance.model.monitoring.MonitoringParam; | ||
| 11 | - | ||
| 12 | -public interface MonitoringService { | ||
| 13 | - | ||
| 14 | - Map<String, Object> getPointMonitoringData(MonitoringParam monitoringParam); | ||
| 15 | - | ||
| 16 | - List<MonitoringMetric> getCurrentMonitoringData(MonitoringParam monitoringParam); | ||
| 17 | - | ||
| 18 | - List<Object> getRangeMonitoringData(MonitoringParam monitoringParam); | ||
| 19 | -} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/OpsWdrService.java+44-8
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.service; | 5 | package com.nctigba.observability.instance.service; |
| 5 | 6 | ||
| 6 | import java.text.MessageFormat; | 7 | import java.text.MessageFormat; |
| @@ -10,10 +11,10 @@ import java.util.HashMap; | |||
| 10 | import java.util.List; | 11 | import java.util.List; |
| 11 | import java.util.Map; | 12 | import java.util.Map; |
| 12 | import java.util.Objects; | 13 | import java.util.Objects; |
| 14 | +import java.util.stream.Collectors; | ||
| 13 | 15 | ||
| 14 | import javax.servlet.http.HttpServletResponse; | 16 | import javax.servlet.http.HttpServletResponse; |
| 15 | 17 | ||
| 16 | -import com.nctigba.observability.instance.constants.CommonConstants; | ||
| 17 | import org.apache.commons.lang3.StringUtils; | 18 | import org.apache.commons.lang3.StringUtils; |
| 18 | import org.opengauss.admin.common.constant.ops.SshCommandConstants; | 19 | import org.opengauss.admin.common.constant.ops.SshCommandConstants; |
| 19 | import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; | 20 | import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; |
| @@ -39,16 +40,19 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||
| 39 | import com.gitee.starblues.bootstrap.annotation.AutowiredType; | 40 | import com.gitee.starblues.bootstrap.annotation.AutowiredType; |
| 40 | import com.gitee.starblues.bootstrap.annotation.AutowiredType.Type; | 41 | import com.gitee.starblues.bootstrap.annotation.AutowiredType.Type; |
| 41 | import com.jcraft.jsch.Session; | 42 | import com.jcraft.jsch.Session; |
| 43 | +import com.nctigba.observability.instance.constants.CommonConstants; | ||
| 42 | import com.nctigba.observability.instance.entity.OpsWdrEntity; | 44 | import com.nctigba.observability.instance.entity.OpsWdrEntity; |
| 43 | import com.nctigba.observability.instance.entity.OpsWdrEntity.WdrScopeEnum; | 45 | import com.nctigba.observability.instance.entity.OpsWdrEntity.WdrScopeEnum; |
| 44 | import com.nctigba.observability.instance.entity.OpsWdrEntity.WdrTypeEnum; | 46 | import com.nctigba.observability.instance.entity.OpsWdrEntity.WdrTypeEnum; |
| 47 | +import com.nctigba.observability.instance.entity.Snapshot; | ||
| 45 | import com.nctigba.observability.instance.mapper.OpsWdrMapper; | 48 | import com.nctigba.observability.instance.mapper.OpsWdrMapper; |
| 49 | +import com.nctigba.observability.instance.mapper.SnapshotMapper; | ||
| 46 | import com.nctigba.observability.instance.model.WdrGeneratorBody; | 50 | import com.nctigba.observability.instance.model.WdrGeneratorBody; |
| 47 | -import com.nctigba.observability.instance.model.WdrSnapshotVO; | ||
| 48 | import com.nctigba.observability.instance.service.provider.ClusterOpsProviderManager; | 51 | import com.nctigba.observability.instance.service.provider.ClusterOpsProviderManager; |
| 49 | import com.nctigba.observability.instance.util.JschUtil; | 52 | import com.nctigba.observability.instance.util.JschUtil; |
| 50 | 53 | ||
| 51 | import cn.hutool.core.collection.CollUtil; | 54 | import cn.hutool.core.collection.CollUtil; |
| 55 | +import cn.hutool.core.date.DateUtil; | ||
| 52 | import cn.hutool.core.util.StrUtil; | 56 | import cn.hutool.core.util.StrUtil; |
| 53 | import lombok.extern.slf4j.Slf4j; | 57 | import lombok.extern.slf4j.Slf4j; |
| 54 | 58 | ||
| @@ -80,8 +84,13 @@ public class OpsWdrService extends ServiceImpl<OpsWdrMapper, OpsWdrEntity> { | |||
| 80 | 84 | ||
| 81 | 85 | ||
| 82 | protected EncryptionUtils encryptionUtils; | 86 | protected EncryptionUtils encryptionUtils; |
| 87 | + | ||
| 88 | + private SnapshotMapper snapshotMapper; | ||
| 83 | 89 | ||
| 84 | - @SuppressWarnings({ "unchecked", "rawtypes" }) | 90 | + @SuppressWarnings({ |
| 91 | + "unchecked", | ||
| 92 | + "rawtypes" | ||
| 93 | + }) | ||
| 85 | public Page<OpsWdrEntity> listWdr(Page page, String clusterId, WdrScopeEnum wdrScope, WdrTypeEnum wdrType, | 94 | public Page<OpsWdrEntity> listWdr(Page page, String clusterId, WdrScopeEnum wdrScope, WdrTypeEnum wdrType, |
| 86 | String hostId, Date start, Date end) { | 95 | String hostId, Date start, Date end) { |
| 87 | var wrapper = Wrappers.lambdaQuery(OpsWdrEntity.class).eq(OpsWdrEntity::getClusterId, clusterId) | 96 | var wrapper = Wrappers.lambdaQuery(OpsWdrEntity.class).eq(OpsWdrEntity::getClusterId, clusterId) |
| @@ -122,7 +131,34 @@ public class OpsWdrService extends ServiceImpl<OpsWdrMapper, OpsWdrEntity> { | |||
| 122 | } | 131 | } |
| 123 | } | 132 | } |
| 124 | 133 | ||
| 125 | - @SuppressWarnings({ "rawtypes", "unchecked" }) | 134 | + /** |
| 135 | + * findSnapshot | ||
| 136 | + * | ||
| 137 | + * id id | ||
| 138 | + * start start | ||
| 139 | + * end end | ||
| 140 | + * Map | ||
| 141 | + */ | ||
| 142 | + public Map<String, Object> findSnapshot(String id, Date start, Date end) { | ||
| 143 | + Map<String, Object> map = new HashMap<>(); | ||
| 144 | + Long startSnapshot = snapshotMapper.getIdByTime(id, Snapshot::getStartTs, DateUtil.offsetHour(start, -1), | ||
| 145 | + start); | ||
| 146 | + map.put("start", startSnapshot == 0 ? null : startSnapshot); | ||
| 147 | + Long endSnapshot = snapshotMapper.getIdByTime(id, Snapshot::getEndTs, end, DateUtil.offsetHour(end, 1)); | ||
| 148 | + map.put("end", endSnapshot == 0 ? null : endSnapshot); | ||
| 149 | + if (startSnapshot == null || endSnapshot == null) { | ||
| 150 | + return map; | ||
| 151 | + } | ||
| 152 | + var listWdr = getBaseMapper().selectList(Wrappers.<OpsWdrEntity>lambdaQuery() | ||
| 153 | + .eq(OpsWdrEntity::getStartSnapshotId, startSnapshot).eq(OpsWdrEntity::getEndSnapshotId, endSnapshot)); | ||
| 154 | + map.put("wdrId", listWdr.stream().map(OpsWdrEntity::getWdrId).collect(Collectors.toList())); | ||
| 155 | + return map; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + | ||
| 159 | + "rawtypes", | ||
| 160 | + "unchecked" | ||
| 161 | + }) | ||
| 126 | public Page listSnapshot(Page page, String clusterId, String hostId) { | 162 | public Page listSnapshot(Page page, String clusterId, String hostId) { |
| 127 | var connection = clusterManager.getConnectionByClusterHost(clusterId, hostId); | 163 | var connection = clusterManager.getConnectionByClusterHost(clusterId, hostId); |
| 128 | String sqlCount = "select count(*) from snapshot.snapshot"; | 164 | String sqlCount = "select count(*) from snapshot.snapshot"; |
| @@ -140,10 +176,10 @@ public class OpsWdrService extends ServiceImpl<OpsWdrMapper, OpsWdrEntity> { | |||
| 140 | var res = new ArrayList<>(); | 176 | var res = new ArrayList<>(); |
| 141 | try (var statement = connection.createStatement(); var rs = statement.executeQuery(sql);) { | 177 | try (var statement = connection.createStatement(); var rs = statement.executeQuery(sql);) { |
| 142 | while (rs.next()) { | 178 | while (rs.next()) { |
| 143 | - var vo = new WdrSnapshotVO(); | 179 | + var vo = new HashMap<>(); |
| 144 | - vo.setSnapshotId(rs.getInt("snapshot_id")); | 180 | + vo.put("snapshotId", rs.getInt("snapshot_id")); |
| 145 | - vo.setStartTs(rs.getDate("start_ts")); | 181 | + vo.put("startTs", DateUtil.formatDateTime(rs.getDate("start_ts"))); |
| 146 | - vo.setEndTs(rs.getDate("end_ts")); | 182 | + vo.put("endTs", DateUtil.formatDateTime(rs.getDate("end_ts"))); |
| 147 | res.add(vo); | 183 | res.add(vo); |
| 148 | } | 184 | } |
| 149 | } catch (Exception e) { | 185 | } catch (Exception e) { |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ParamInfoService.java+22-21
| @@ -1,24 +1,27 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.service; | 5 | package com.nctigba.observability.instance.service; |
| 5 | 6 | ||
| 6 | import java.util.ArrayList; | 7 | import java.util.ArrayList; |
| 7 | import java.util.List; | 8 | import java.util.List; |
| 9 | +import java.util.Map; | ||
| 8 | 10 | ||
| 9 | import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | 11 | import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; |
| 10 | import org.springframework.beans.factory.annotation.Autowired; | 12 | import org.springframework.beans.factory.annotation.Autowired; |
| 11 | import org.springframework.stereotype.Service; | 13 | import org.springframework.stereotype.Service; |
| 12 | 14 | ||
| 13 | import com.gitee.starblues.bootstrap.annotation.AutowiredType; | 15 | import com.gitee.starblues.bootstrap.annotation.AutowiredType; |
| 14 | -import com.nctigba.common.web.exception.InstanceException; | ||
| 15 | import com.nctigba.observability.instance.constants.CommonConstants; | 16 | import com.nctigba.observability.instance.constants.CommonConstants; |
| 16 | import com.nctigba.observability.instance.dto.param.ParamInfoDTO; | 17 | import com.nctigba.observability.instance.dto.param.ParamInfoDTO; |
| 17 | -import com.nctigba.observability.instance.entity.ParamInfo.type; | 18 | +import com.nctigba.observability.instance.entity.ParamInfo.ParamType; |
| 18 | import com.nctigba.observability.instance.entity.ParamValueInfo; | 19 | import com.nctigba.observability.instance.entity.ParamValueInfo; |
| 20 | +import com.nctigba.observability.instance.exception.InstanceException; | ||
| 21 | +import com.nctigba.observability.instance.mapper.DbConfigMapper; | ||
| 19 | import com.nctigba.observability.instance.mapper.ParamInfoMapper; | 22 | import com.nctigba.observability.instance.mapper.ParamInfoMapper; |
| 20 | import com.nctigba.observability.instance.mapper.ParamValueInfoMapper; | 23 | import com.nctigba.observability.instance.mapper.ParamValueInfoMapper; |
| 21 | -import com.nctigba.observability.instance.model.param.ParamQuery; | 24 | +import com.nctigba.observability.instance.model.ParamQuery; |
| 22 | import com.nctigba.observability.instance.util.MessageSourceUtil; | 25 | import com.nctigba.observability.instance.util.MessageSourceUtil; |
| 23 | import com.nctigba.observability.instance.util.SshSession; | 26 | import com.nctigba.observability.instance.util.SshSession; |
| 24 | 27 | ||
| @@ -29,12 +32,14 @@ import lombok.extern.slf4j.Slf4j; | |||
| 29 | 32 | ||
| 30 | public class ParamInfoService { | 33 | public class ParamInfoService { |
| 31 | 34 | ||
| 32 | - private ClusterManager opsFacade; | 35 | + private ClusterManager clusterManager; |
| 33 | 36 | ||
| 34 | 37 | ||
| 35 | - protected EncryptionUtils encryptionUtils; | 38 | + private EncryptionUtils encryptionUtils; |
| 36 | 39 | ||
| 37 | - protected ParamValueInfoMapper paramValueInfoMapper; | 40 | + private ParamValueInfoMapper paramValueInfoMapper; |
| 41 | + | ||
| 42 | + private DbConfigMapper dbConfigMapper; | ||
| 38 | 43 | ||
| 39 | public List<ParamInfoDTO> getParamInfo(ParamQuery paramQuery) { | 44 | public List<ParamInfoDTO> getParamInfo(ParamQuery paramQuery) { |
| 40 | if ("1".equals(paramQuery.getIsRefresh())) { | 45 | if ("1".equals(paramQuery.getIsRefresh())) { |
| @@ -48,33 +53,29 @@ public class ParamInfoService { | |||
| 48 | return paramValueInfoMapper.query(paramQuery.getNodeId()); | 53 | return paramValueInfoMapper.query(paramQuery.getNodeId()); |
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | - private static final String DBSETTINGS = "select name,setting from pg_settings"; | ||
| 52 | - | ||
| 53 | private void updateDatabaseParamInfo(ParamQuery paramQuery) { | 56 | private void updateDatabaseParamInfo(ParamQuery paramQuery) { |
| 54 | try { | 57 | try { |
| 55 | - var conn = opsFacade.getConnectionByNodeId(paramQuery.getNodeId()); | 58 | + clusterManager.setCurrentDatasource(paramQuery.getNodeId(), null); |
| 56 | - var stmt = conn.createStatement(); | ||
| 57 | - var rs = stmt.executeQuery(DBSETTINGS); | ||
| 58 | var list = new ArrayList<ParamValueInfo>(); | 59 | var list = new ArrayList<ParamValueInfo>(); |
| 59 | - while (rs.next()) { | 60 | + for (Map<String, String> setting : dbConfigMapper.settings()) { |
| 60 | - String name = rs.getString(1); | 61 | + var paramInfo = ParamInfoMapper.getParamInfo(ParamType.DB, setting.get("name")); |
| 61 | - String value = rs.getString(2); | ||
| 62 | - var paramInfo = ParamInfoMapper.getParamInfo(type.DB, name); | ||
| 63 | if (paramInfo == null) | 62 | if (paramInfo == null) |
| 64 | continue; | 63 | continue; |
| 65 | - list.add(new ParamValueInfo(paramInfo.getId(), paramQuery.getNodeId(), value)); | 64 | + list.add(new ParamValueInfo(paramInfo.getId(), paramQuery.getNodeId(), setting.get("setting"))); |
| 66 | } | 65 | } |
| 67 | - update(list, type.DB); | 66 | + update(list, ParamType.DB); |
| 68 | } catch (Exception e) { | 67 | } catch (Exception e) { |
| 69 | log.info(e.getMessage(), e); | 68 | log.info(e.getMessage(), e); |
| 70 | throw new InstanceException(MessageSourceUtil.get("connect.database.tip"), e); | 69 | throw new InstanceException(MessageSourceUtil.get("connect.database.tip"), e); |
| 70 | + } finally { | ||
| 71 | + clusterManager.pool(); | ||
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | private void updateOsParamInfo(ParamQuery paramQuery) { | 76 | private void updateOsParamInfo(ParamQuery paramQuery) { |
| 76 | try { | 77 | try { |
| 77 | - var node = opsFacade.getOpsNodeById(paramQuery.getNodeId()); | 78 | + var node = clusterManager.getOpsNodeById(paramQuery.getNodeId()); |
| 78 | if (node == null) | 79 | if (node == null) |
| 79 | throw new InstanceException(MessageSourceUtil.get("node.tip")); | 80 | throw new InstanceException(MessageSourceUtil.get("node.tip")); |
| 80 | var ssh = SshSession.connect(node.getPublicIp(), node.getHostPort(), "root", | 81 | var ssh = SshSession.connect(node.getPublicIp(), node.getHostPort(), "root", |
| @@ -84,19 +85,19 @@ public class ParamInfoService { | |||
| 84 | for (int n = 0; n < values.length; n++) { | 85 | for (int n = 0; n < values.length; n++) { |
| 85 | String name = values[n].substring(0, values[n].lastIndexOf(CommonConstants.EQUAL_SYMBOL)).trim(); | 86 | String name = values[n].substring(0, values[n].lastIndexOf(CommonConstants.EQUAL_SYMBOL)).trim(); |
| 86 | String paramData = values[n].substring(values[n].indexOf(CommonConstants.EQUAL_SYMBOL) + 1).trim(); | 87 | String paramData = values[n].substring(values[n].indexOf(CommonConstants.EQUAL_SYMBOL) + 1).trim(); |
| 87 | - var paramInfo = ParamInfoMapper.getParamInfo(type.OS, name); | 88 | + var paramInfo = ParamInfoMapper.getParamInfo(ParamType.OS, name); |
| 88 | if (paramInfo == null) | 89 | if (paramInfo == null) |
| 89 | continue; | 90 | continue; |
| 90 | list.add(new ParamValueInfo(paramInfo.getId(), paramQuery.getNodeId(), paramData)); | 91 | list.add(new ParamValueInfo(paramInfo.getId(), paramQuery.getNodeId(), paramData)); |
| 91 | } | 92 | } |
| 92 | - update(list, type.OS); | 93 | + update(list, ParamType.OS); |
| 93 | } catch (Exception e) { | 94 | } catch (Exception e) { |
| 94 | log.info(e.getMessage(), e); | 95 | log.info(e.getMessage(), e); |
| 95 | throw new InstanceException(MessageSourceUtil.get("password.tip"), e); | 96 | throw new InstanceException(MessageSourceUtil.get("password.tip"), e); |
| 96 | } | 97 | } |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | - private void update(ArrayList<ParamValueInfo> list, type t) { | 100 | + private void update(ArrayList<ParamValueInfo> list, ParamType t) { |
| 100 | var ids = ParamInfoMapper.getIds(t); | 101 | var ids = ParamInfoMapper.getIds(t); |
| 101 | ParamValueInfoMapper.delBySids(ids); | 102 | ParamValueInfoMapper.delBySids(ids); |
| 102 | ParamValueInfoMapper.insertBatch(list); | 103 | ParamValueInfoMapper.insertBatch(list); |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/SessionService.java+114-10
| @@ -1,28 +1,132 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.service; | 5 | package com.nctigba.observability.instance.service; |
| 5 | 6 | ||
| 7 | +import java.util.ArrayList; | ||
| 8 | +import java.util.HashMap; | ||
| 6 | import java.util.List; | 9 | import java.util.List; |
| 7 | import java.util.Map; | 10 | import java.util.Map; |
| 11 | +import java.util.Set; | ||
| 12 | +import java.util.stream.Collectors; | ||
| 13 | + | ||
| 14 | +import org.apache.commons.lang3.StringUtils; | ||
| 15 | +import org.springframework.stereotype.Service; | ||
| 8 | 16 | ||
| 9 | import com.alibaba.fastjson.JSONObject; | 17 | import com.alibaba.fastjson.JSONObject; |
| 18 | +import com.nctigba.observability.instance.aop.Ds; | ||
| 10 | import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | 19 | import com.nctigba.observability.instance.dto.session.DetailStatisticDto; |
| 20 | +import com.nctigba.observability.instance.exception.InstanceException; | ||
| 21 | +import com.nctigba.observability.instance.mapper.SessionMapper; | ||
| 11 | 22 | ||
| 12 | -public interface SessionService { | 23 | +import lombok.RequiredArgsConstructor; |
| 13 | - JSONObject detailGeneral(String id, String sessionid); | ||
| 14 | 24 | ||
| 15 | - List<DetailStatisticDto> detailStatistic(String id, String sessionid); | 25 | +@Service |
| 26 | + | ||
| 27 | +public class SessionService { | ||
| 28 | + private final SessionMapper sessionMapper; | ||
| 16 | 29 | ||
| 17 | - List<JSONObject> detailWaiting(String id, String sessionid); | 30 | + @Ds |
| 31 | + public Map<String, Object> detailGeneral(String id, String sessionid) { | ||
| 32 | + Map<String, Object> res = new JSONObject(); | ||
| 33 | + List<Map<String, Object>> generalMesList = sessionMapper.generalMesList(sessionid); | ||
| 34 | + if (generalMesList.size() == 0) { | ||
| 35 | + throw new InstanceException("session.detail.general.message"); | ||
| 36 | + } | ||
| 37 | + res.putAll(generalMesList.get(0)); | ||
| 38 | + if (sessionMapper.sessionIsWaiting(sessionid) != 0) { | ||
| 39 | + return res; | ||
| 40 | + } | ||
| 41 | + List<Map<String, Object>> blockList = sessionMapper.blockList(sessionid); | ||
| 42 | + if (blockList.size() != 0) { | ||
| 43 | + res.putAll(blockList.get(0)); | ||
| 44 | + } | ||
| 45 | + return res; | ||
| 46 | + } | ||
| 18 | 47 | ||
| 19 | - List<JSONObject> detailBlockTree(String id, String sessionid); | 48 | + @Ds |
| 49 | + public List<DetailStatisticDto> detailStatistic(String id, String sessionid) { | ||
| 50 | + ArrayList<DetailStatisticDto> list = new ArrayList<>(); | ||
| 51 | + list.addAll( | ||
| 52 | + sessionMapper.statistic(sessionid).stream() | ||
| 53 | + .map(ob -> new DetailStatisticDto(DetailStatisticDto.Type.STATUS, | ||
| 54 | + ob.get("stat_name").toString(), ob.get("value").toString())) | ||
| 55 | + .collect(Collectors.toList())); | ||
| 56 | + list.addAll( | ||
| 57 | + sessionMapper.runtime(sessionid).stream() | ||
| 58 | + .map(ob -> new DetailStatisticDto(DetailStatisticDto.Type.RUNTIME, | ||
| 59 | + ob.get("statname").toString(), ob.get("value").toString())) | ||
| 60 | + .collect(Collectors.toList())); | ||
| 61 | + return list; | ||
| 62 | + } | ||
| 20 | 63 | ||
| 21 | - JSONObject simpleStatistic(String id); | 64 | + @Ds |
| 65 | + public List<Map<String, Object>> detailWaiting(String id, String sessionid) { | ||
| 66 | + return sessionMapper.detailWaiting(sessionid); | ||
| 67 | + } | ||
| 22 | 68 | ||
| 23 | - List<JSONObject> longTxc(String id); | 69 | + @Ds |
| 70 | + public List<Map<String, Object>> detailBlockTree(String id, String sessionid) { | ||
| 71 | + List<Map<String, Object>> queryList = sessionMapper.blockTree(); | ||
| 72 | + if (StringUtils.isNotEmpty(sessionid)) { | ||
| 73 | + Set<String> treeIdSet = queryList.stream().filter(obj -> obj.get("pathid").toString().contains(sessionid)) | ||
| 74 | + .map(obj -> obj.get("tree_id").toString()).collect(Collectors.toSet()); | ||
| 75 | + queryList = queryList.stream().filter(obj -> treeIdSet.contains(obj.get("tree_id").toString())) | ||
| 76 | + .collect(Collectors.toList()); | ||
| 77 | + } | ||
| 78 | + return toTreeData(queryList); | ||
| 79 | + } | ||
| 24 | 80 | ||
| 25 | - Map<String, List<JSONObject>> blockAndLongTxc(String id); | 81 | + @Ds |
| 82 | + public Map<String, Object> simpleStatistic(String id) { | ||
| 83 | + return sessionMapper.simpleStatistic(); | ||
| 84 | + } | ||
| 26 | 85 | ||
| 27 | - Map<String, Object> detail(String id, String sessionid); | 86 | + @Ds |
| 28 | -} | 87 | + public List<Map<String, Object>> longTxc(String id) { |
| 88 | + return sessionMapper.longTxc(); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + | ||
| 92 | + public HashMap<String, List<Map<String, Object>>> blockAndLongTxc(String id) { | ||
| 93 | + HashMap<String, List<Map<String, Object>>> res = new HashMap<>(); | ||
| 94 | + res.put("blockTree", detailBlockTree(id, null)); | ||
| 95 | + res.put("longTxc", longTxc(id)); | ||
| 96 | + return res; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + | ||
| 100 | + public Map<String, Object> detail(String id, String sessionid) { | ||
| 101 | + Map<String, Object> resMap = new HashMap<>(); | ||
| 102 | + resMap.put("general", detailGeneral(id, sessionid)); | ||
| 103 | + resMap.put("statistic", detailStatistic(id, sessionid)); | ||
| 104 | + resMap.put("blockTree", detailBlockTree(id, sessionid)); | ||
| 105 | + resMap.put("waiting", detailWaiting(id, sessionid)); | ||
| 106 | + return resMap; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + | ||
| 110 | + "unchecked", | ||
| 111 | + "rawtypes" | ||
| 112 | + }) | ||
| 113 | + private List<Map<String, Object>> toTreeData(List<Map<String, Object>> list) { | ||
| 114 | + // Classify by parentid | ||
| 115 | + Map<Long, Map<String, Object>> map = new HashMap<>(); | ||
| 116 | + List<Map<String, Object>> result = new ArrayList<>(); | ||
| 117 | + for (Map<String, Object> object : list) { | ||
| 118 | + object.put("children", new ArrayList<>()); | ||
| 119 | + map.put(Long.valueOf(object.get("id").toString()), object); | ||
| 120 | + Long parentId = Long.valueOf(object.get("parentid").toString()); | ||
| 121 | + if (parentId == 0) { | ||
| 122 | + result.add(object); | ||
| 123 | + continue; | ||
| 124 | + } | ||
| 125 | + Object children = map.get(parentId).get("children"); | ||
| 126 | + if (children instanceof List) { | ||
| 127 | + ((List) children).add(object); | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + return result; | ||
| 131 | + } | ||
| 132 | +} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/TopSQLService.java+185-125
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.service; | 5 | package com.nctigba.observability.instance.service; |
| 5 | 6 | ||
| 6 | import java.time.Duration; | 7 | import java.time.Duration; |
| @@ -8,168 +9,227 @@ import java.time.LocalDateTime; | |||
| 8 | import java.time.format.DateTimeFormatter; | 9 | import java.time.format.DateTimeFormatter; |
| 9 | import java.time.format.DateTimeParseException; | 10 | import java.time.format.DateTimeParseException; |
| 10 | import java.util.ArrayList; | 11 | import java.util.ArrayList; |
| 11 | -import java.util.Collections; | 12 | +import java.util.HashMap; |
| 13 | +import java.util.LinkedList; | ||
| 12 | import java.util.List; | 14 | import java.util.List; |
| 13 | import java.util.Map; | 15 | import java.util.Map; |
| 16 | +import java.util.Set; | ||
| 14 | 17 | ||
| 15 | -import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | 18 | +import org.apache.commons.lang3.StringUtils; |
| 19 | +import org.opengauss.admin.common.exception.CustomException; | ||
| 16 | import org.springframework.stereotype.Service; | 20 | import org.springframework.stereotype.Service; |
| 17 | 21 | ||
| 18 | -import com.alibaba.fastjson.JSONObject; | 22 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| 19 | -import com.nctigba.observability.instance.constants.DatabaseType; | 23 | +import com.nctigba.observability.instance.aop.Ds; |
| 20 | -import com.nctigba.observability.instance.dto.topsql.TopSQLInfoReq; | ||
| 21 | import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; | 24 | import com.nctigba.observability.instance.dto.topsql.TopSQLListReq; |
| 22 | -import com.nctigba.observability.instance.dto.topsql.TopSQLNowReq; | 25 | +import com.nctigba.observability.instance.entity.PgSettings; |
| 23 | -import com.nctigba.observability.instance.factory.TopSQLHandlerFactory; | 26 | +import com.nctigba.observability.instance.mapper.PgSettingMapper; |
| 24 | -import com.nctigba.observability.instance.handler.topsql.TopSQLHandler; | ||
| 25 | import com.nctigba.observability.instance.mapper.TopSqlMapper; | 27 | import com.nctigba.observability.instance.mapper.TopSqlMapper; |
| 26 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | 28 | +import com.nctigba.observability.instance.model.ExecutionPlan; |
| 27 | -import com.nctigba.observability.instance.service.TopSQLService.waitEvent.event; | 29 | +import com.nctigba.observability.instance.model.IndexAdvice; |
| 30 | +import com.nctigba.observability.instance.service.TopSQLService.WaitEvent.Event; | ||
| 28 | 31 | ||
| 32 | +import cn.hutool.core.collection.CollUtil; | ||
| 29 | import cn.hutool.core.util.StrUtil; | 33 | import cn.hutool.core.util.StrUtil; |
| 30 | import lombok.Data; | 34 | import lombok.Data; |
| 31 | import lombok.Generated; | 35 | import lombok.Generated; |
| 32 | import lombok.RequiredArgsConstructor; | 36 | import lombok.RequiredArgsConstructor; |
| 33 | -import lombok.extern.slf4j.Slf4j; | ||
| 34 | 37 | ||
| 35 | /** | 38 | /** |
| 36 | * <p> | 39 | * <p> |
| 37 | * TopSQL services | 40 | * TopSQL services |
| 38 | * </p> | 41 | * </p> |
| 39 | * | 42 | * |
| 40 | - * zhanggr.com.cn | ||
| 41 | * 2022/9/15 15:46 | 43 | * 2022/9/15 15:46 |
| 42 | */ | 44 | */ |
| 43 | 45 | ||
| 44 | 46 | ||
| 45 | - | ||
| 46 | public class TopSQLService { | 47 | public class TopSQLService { |
| 47 | - private final TopSQLHandlerFactory topSQLHandlerFactory; | 48 | + private final PgSettingMapper pgSettingMapper; |
| 48 | - private final ClusterManager clusterManager; | ||
| 49 | private final TopSqlMapper topSqlMapper; | 49 | private final TopSqlMapper topSqlMapper; |
| 50 | 50 | ||
| 51 | - public boolean testConnection(String nodeId) { | 51 | + /** |
| 52 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | 52 | + * fetch TopSQL list from database |
| 53 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(nodeId); | 53 | + * |
| 54 | - try { | 54 | + * @param topSQLListReq instance node id |
| 55 | - return handler.getConnection(instanceNodeInfo) != null; | 55 | + * @return TopSQL list |
| 56 | - } catch (Exception e) { | 56 | + */ |
| 57 | - log.error("test connection exception: {}", e.getMessage()); | 57 | + @Ds("id") |
| 58 | - return false; | 58 | + public List<Map<String, Object>> topSQLList(TopSQLListReq topSQLListReq) { |
| 59 | - } | 59 | + topSqlListPreCheck(); |
| 60 | - } | 60 | + return topSqlMapper.historyTopsqlList(topSQLListReq); |
| 61 | - | ||
| 62 | - public List<JSONObject> getTopSQLList(TopSQLListReq topSQLListReq) { | ||
| 63 | - // get handler | ||
| 64 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 65 | - // query node info | ||
| 66 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLListReq.getId()); | ||
| 67 | - // query TopSQL list | ||
| 68 | - return handler.getTopSQLList(instanceNodeInfo, topSQLListReq); | ||
| 69 | - } | ||
| 70 | - | ||
| 71 | - public List<JSONObject> getTopSQLNow(TopSQLNowReq topSQLNowReq) { | ||
| 72 | - // get handler | ||
| 73 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 74 | - // query node info | ||
| 75 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLNowReq.getId()); | ||
| 76 | - // query TopSQL list | ||
| 77 | - return handler.getTopSQLNow(instanceNodeInfo, topSQLNowReq); | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - public JSONObject getStatisticalInfo(TopSQLInfoReq topSQLDetailReq) { | ||
| 81 | - // get handler | ||
| 82 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 83 | - // query node info | ||
| 84 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLDetailReq.getId()); | ||
| 85 | - // query TopSQL statistical information | ||
| 86 | - return handler.getStatisticalInfo(instanceNodeInfo, topSQLDetailReq.getSqlId()); | ||
| 87 | - } | ||
| 88 | - | ||
| 89 | - public JSONObject getExecutionPlan(TopSQLInfoReq topSQLPlanReq, String type) { | ||
| 90 | - // get handler | ||
| 91 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 92 | - // query node info | ||
| 93 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLPlanReq.getId()); | ||
| 94 | - // query TopSQL statistical information | ||
| 95 | - return handler.getExecutionPlan(instanceNodeInfo, topSQLPlanReq.getSqlId(), type); | ||
| 96 | - } | ||
| 97 | - | ||
| 98 | - public List<JSONObject> getPartitionList(TopSQLInfoReq topSQLPartitionReq) { | ||
| 99 | - // get handler | ||
| 100 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 101 | - // query node info | ||
| 102 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLPartitionReq.getId()); | ||
| 103 | - // query TopSQL statistical information | ||
| 104 | - return handler.getPartitionList(instanceNodeInfo, topSQLPartitionReq.getSqlId()); | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - public List<String> getIndexAdvice(TopSQLInfoReq topSQLIndexReq) { | ||
| 108 | - // get handler | ||
| 109 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 110 | - // query node info | ||
| 111 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLIndexReq.getId()); | ||
| 112 | - // query TopSQL statistical information | ||
| 113 | - return handler.getIndexAdvice(instanceNodeInfo, topSQLIndexReq.getSqlId()); | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - public JSONObject getObjectInfo(TopSQLInfoReq topSQLObjectReq) { | ||
| 117 | - // get handler | ||
| 118 | - TopSQLHandler handler = topSQLHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 119 | - // query node info | ||
| 120 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(topSQLObjectReq.getId()); | ||
| 121 | - // query TopSQL statistical information | ||
| 122 | - return handler.getObjectInfo(instanceNodeInfo, topSQLObjectReq.getSqlId()); | ||
| 123 | } | 61 | } |
| 124 | 62 | ||
| 125 | /** | 63 | /** |
| 126 | - * Query instance node information | 64 | + * fetch TopSQL now list from database |
| 127 | * | 65 | * |
| 128 | - * @param nodeId instance node id | 66 | + * @param id instance node id |
| 129 | - * @return Instance node information | 67 | + * @return TopSQL list |
| 130 | */ | 68 | */ |
| 131 | - public InstanceNodeInfo queryNodeInfo(String nodeId) { | 69 | + @Ds |
| 132 | - OpsClusterNodeVO opsClusterNode = clusterManager.getOpsNodeById(nodeId); | 70 | + public List<Map<String, Object>> topSQLNow(String id) { |
| 133 | - InstanceNodeInfo instanceNodeInfo = new InstanceNodeInfo(); | 71 | + return topSqlMapper.currentTopsqlList(); |
| 134 | - instanceNodeInfo.setId(opsClusterNode.getNodeId()); | ||
| 135 | - instanceNodeInfo.setIp(opsClusterNode.getPublicIp()); | ||
| 136 | - instanceNodeInfo.setPort(opsClusterNode.getDbPort()); | ||
| 137 | - instanceNodeInfo.setDbName(opsClusterNode.getDbName()); | ||
| 138 | - instanceNodeInfo.setDbUser(opsClusterNode.getDbUser()); | ||
| 139 | - instanceNodeInfo.setDbUserPassword(opsClusterNode.getDbUserPassword()); | ||
| 140 | - instanceNodeInfo.setDbType(DatabaseType.DEFAULT.getDbType()); | ||
| 141 | - return instanceNodeInfo; | ||
| 142 | } | 72 | } |
| 143 | 73 | ||
| 74 | + /** | ||
| 75 | + * fetch TopSQL statistical information from database, page index | ||
| 76 | + * | ||
| 77 | + * nodeId instance node id | ||
| 78 | + * sqlId TopSQL debug query id | ||
| 79 | + * TopSQL statistical information | ||
| 80 | + */ | ||
| 81 | + | ||
| 82 | + public Map<String, Object> detail(String nodeId, String sqlId) { | ||
| 83 | + var detail = topSqlMapper.currentDetail(sqlId); | ||
| 84 | + if (CollUtil.isNotEmpty(detail)) { | ||
| 85 | + return detail; | ||
| 86 | + } | ||
| 87 | + return topSqlMapper.historyDetail(sqlId); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * fetch TopSQL execution plan from database | ||
| 92 | + * | ||
| 93 | + * nodeId instance node id | ||
| 94 | + * sqlId TopSQL debug query id | ||
| 95 | + * TopSQL execution plan | ||
| 96 | + */ | ||
| 97 | + | ||
| 98 | + public ExecutionPlan executionPlan(String nodeId, String sqlId) { | ||
| 99 | + String plan = topSqlMapper.currentPlan(sqlId); | ||
| 100 | + if (StrUtil.isNotBlank(plan)) { | ||
| 101 | + return new ExecutionPlan(plan); | ||
| 102 | + } | ||
| 103 | + // pre-check track_stmt_stat_leve full sql level at least L1 | ||
| 104 | + var settings = pgSettingMapper | ||
| 105 | + .selectOne(Wrappers.<PgSettings>lambdaQuery().eq(PgSettings::getName, "track_stmt_stat_level")); | ||
| 106 | + var setting = settings.getSetting(); | ||
| 107 | + if (StringUtils.startsWith(setting, "OFF") || StringUtils.startsWith(setting, "L0")) { | ||
| 108 | + throw new CustomException("failGetExecutionPlan"); | ||
| 109 | + } | ||
| 110 | + // get prepared statement | ||
| 111 | + plan = topSqlMapper.historyPlan(sqlId); | ||
| 112 | + // get base execution plan object | ||
| 113 | + return new ExecutionPlan(plan); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + /** | ||
| 117 | + * fetch TopSQL object information from database | ||
| 118 | + * | ||
| 119 | + * nodeId instance node id | ||
| 120 | + * sqlId TopSQL debug query id | ||
| 121 | + * TopSQL object information | ||
| 122 | + */ | ||
| 123 | + | ||
| 124 | + public Map<String, Object> objectInfo(String nodeId, String sqlId) { | ||
| 125 | + // init objectNameList via get execution plan | ||
| 126 | + var plan = executionPlan(nodeId, sqlId); | ||
| 127 | + Set<String> curObjectNameList = plan.allAlias(); | ||
| 128 | + List<String> modifyObjectNameList = new LinkedList<>(curObjectNameList); | ||
| 129 | + Map<String, Object> tableMetadata = new HashMap<>(); | ||
| 130 | + Map<String, Object> tableStructure = new HashMap<>(); | ||
| 131 | + Map<String, Object> tableIndex = new HashMap<>(); | ||
| 132 | + for (String name : curObjectNameList) { | ||
| 133 | + try { | ||
| 134 | + tableMetadata.put(name, topSqlMapper.tableMetaData(name)); | ||
| 135 | + tableStructure.put(name, topSqlMapper.tableStructure(name)); | ||
| 136 | + tableIndex.put(name, topSqlMapper.indexInfo(name)); | ||
| 137 | + } catch (Exception e) { | ||
| 138 | + modifyObjectNameList.remove(name); | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + return Map.of("object_name_list", modifyObjectNameList, "table_metadata", tableMetadata, "table_structure", | ||
| 142 | + tableStructure, "table_index", tableIndex); | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + /** | ||
| 146 | + * fetch TopSQL index advice from database | ||
| 147 | + * | ||
| 148 | + * nodeId instance node id | ||
| 149 | + * sqlId TopSQL debug query id | ||
| 150 | + * TopSQL index advice | ||
| 151 | + */ | ||
| 152 | + | ||
| 153 | + public List<String> indexAdvice(String nodeId, String sqlId) { | ||
| 154 | + List<String> results = new ArrayList<>(); | ||
| 155 | + var queryText = topSqlMapper.sql(sqlId); | ||
| 156 | + var advises = topSqlMapper.advise(queryText); | ||
| 157 | + String indexTemplate = "建议为%s模式下的%t表的%c列创建索引"; | ||
| 158 | + String multiColumnIndexTemplate = "建议为%s模式下的%t表的%c创建复合索引"; | ||
| 159 | + if (advises.isEmpty()) { | ||
| 160 | + results.add("No index suggestions"); | ||
| 161 | + return results; | ||
| 162 | + } | ||
| 163 | + // process index advice for every returned line | ||
| 164 | + for (IndexAdvice advice : advises) { | ||
| 165 | + String column = advice.getColumn(); | ||
| 166 | + if (StringUtils.isNotEmpty(column)) { | ||
| 167 | + String result = column.contains(",") ? multiColumnIndexTemplate : indexTemplate; | ||
| 168 | + result = result.replace("%s", advice.getSchema()); | ||
| 169 | + result = result.replace("%t", advice.getTable()); | ||
| 170 | + result = result.replace("%c", advice.getColumn()); | ||
| 171 | + results.add(result); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + return results; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + | ||
| 144 | public List<Map<String, Object>> waitEvent(String nodeId, String sqlId) { | 178 | public List<Map<String, Object>> waitEvent(String nodeId, String sqlId) { |
| 145 | List<Map<String, Object>> list = new ArrayList<>(); | 179 | List<Map<String, Object>> list = new ArrayList<>(); |
| 146 | - try { | 180 | + String table = topSqlMapper.waitEvent(sqlId); |
| 147 | - clusterManager.setCurrentDatasource(nodeId, null); | 181 | + if (StrUtil.isBlank(table)) { |
| 148 | - String table = topSqlMapper.waitEvent(sqlId); | 182 | + return topSqlMapper.currentWaitEvent(sqlId); |
| 149 | - if (StrUtil.isBlank(table)) { | 183 | + } |
| 150 | - return Collections.emptyList(); | 184 | + String[] lines = table.split(","); |
| 185 | + WaitEvent pre = null; | ||
| 186 | + for (String string : lines) { | ||
| 187 | + var curr = new WaitEvent(string); | ||
| 188 | + if (pre != null && pre.getE() == Event.LOCK_START && curr.getE() == Event.LOCK_END) { | ||
| 189 | + list.add(Map.of("starttime", pre.getTimeStr(), "lockType", pre.getLockType(), "waittime", | ||
| 190 | + (Duration.between(pre.getTime(), curr.getTime()).toNanos() / 1000))); | ||
| 191 | + pre = null; | ||
| 192 | + continue; | ||
| 151 | } | 193 | } |
| 152 | - String[] lines = table.split(","); | 194 | + pre = curr; |
| 153 | - waitEvent pre = null; | ||
| 154 | - for (String string : lines) { | ||
| 155 | - var curr = new waitEvent(string); | ||
| 156 | - if (pre != null && pre.getE() == event.LOCK_START && curr.getE() == event.LOCK_END) { | ||
| 157 | - list.add(Map.of("starttime", pre.getTimeStr(), "lockType", pre.getLockType(), "waittime", | ||
| 158 | - (Duration.between(pre.getTime(), curr.getTime()).toNanos() / 1000))); | ||
| 159 | - pre = null; | ||
| 160 | - continue; | ||
| 161 | - } | ||
| 162 | - pre = curr; | ||
| 163 | - } | ||
| 164 | - } finally { | ||
| 165 | - clusterManager.pool(); | ||
| 166 | } | 195 | } |
| 167 | return list; | 196 | return list; |
| 168 | } | 197 | } |
| 169 | 198 | ||
| 199 | + /** | ||
| 200 | + * pre-check top sql list job | ||
| 201 | + * | ||
| 202 | + * true when not log; false when can search log | ||
| 203 | + */ | ||
| 204 | + private void topSqlListPreCheck() { | ||
| 205 | + var list = pgSettingMapper.selectList(Wrappers.<PgSettings>lambdaQuery().in(PgSettings::getName, | ||
| 206 | + "enable_stmt_track", "enable_resource_track", "track_stmt_stat_level'")); | ||
| 207 | + for (PgSettings pgSettings : list) { | ||
| 208 | + switch (pgSettings.getName()) { | ||
| 209 | + case "enable_resource_track": | ||
| 210 | + case "enable_stmt_track": | ||
| 211 | + if ("off".equals(pgSettings.getSetting())) { | ||
| 212 | + throw new CustomException("top sql pre check fail", 602); | ||
| 213 | + } | ||
| 214 | + break; | ||
| 215 | + case "track_stmt_stat_level": | ||
| 216 | + var setting = pgSettings.getSetting(); | ||
| 217 | + if (StringUtils.isEmpty(setting) || !setting.contains(",")) { | ||
| 218 | + throw new CustomException("top sql pre check fail", 602); | ||
| 219 | + } | ||
| 220 | + String[] settingArr = setting.split(","); | ||
| 221 | + if ("off".equalsIgnoreCase(settingArr[0])) { | ||
| 222 | + throw new CustomException("top sql pre check fail", 602); | ||
| 223 | + } | ||
| 224 | + break; | ||
| 225 | + default: | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + | ||
| 170 | 230 | ||
| 171 | 231 | ||
| 172 | - public static class waitEvent { | 232 | + public static class WaitEvent { |
| 173 | private static final DateTimeFormatter[] FORMATTERS = { | 233 | private static final DateTimeFormatter[] FORMATTERS = { |
| 174 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSx"), | 234 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSx"), |
| 175 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSx"), | 235 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSx"), |
| @@ -179,16 +239,16 @@ public class TopSQLService { | |||
| 179 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.Sx") | 239 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.Sx") |
| 180 | }; | 240 | }; |
| 181 | private String index; | 241 | private String index; |
| 182 | - private event e; | 242 | + private Event e; |
| 183 | private LocalDateTime time; | 243 | private LocalDateTime time; |
| 184 | private String timeStr; | 244 | private String timeStr; |
| 185 | private String id; | 245 | private String id; |
| 186 | private String lockType; | 246 | private String lockType; |
| 187 | 247 | ||
| 188 | - public waitEvent(String string) { | 248 | + public WaitEvent(String string) { |
| 189 | String[] str = string.split("'\\s+'"); | 249 | String[] str = string.split("'\\s+'"); |
| 190 | this.index = str[0].replaceAll("'", ""); | 250 | this.index = str[0].replaceAll("'", ""); |
| 191 | - this.e = event.valueOf(str[1].replaceAll("'", "")); | 251 | + this.e = Event.valueOf(str[1].replaceAll("'", "")); |
| 192 | for (int i = 0; i < FORMATTERS.length; i++) { | 252 | for (int i = 0; i < FORMATTERS.length; i++) { |
| 193 | try { | 253 | try { |
| 194 | this.time = LocalDateTime.parse(str[2].replaceAll("'", ""), FORMATTERS[i]); | 254 | this.time = LocalDateTime.parse(str[2].replaceAll("'", ""), FORMATTERS[i]); |
| @@ -204,7 +264,7 @@ public class TopSQLService { | |||
| 204 | this.lockType = str[4].replaceAll("'", ""); | 264 | this.lockType = str[4].replaceAll("'", ""); |
| 205 | } | 265 | } |
| 206 | 266 | ||
| 207 | - public enum event { | 267 | + public enum Event { |
| 208 | LOCK_START, | 268 | LOCK_START, |
| 209 | LOCK_END, | 269 | LOCK_END, |
| 210 | LOCK_RELEASE | 270 | LOCK_RELEASE |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/AspServiceImpl.java+53-0
| @@ -0,0 +1,53 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service.impl; | ||
| 6 | + | ||
| 7 | +import java.util.ArrayList; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.List; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | + | ||
| 15 | +import com.nctigba.observability.instance.aop.Ds; | ||
| 16 | +import com.nctigba.observability.instance.dto.asp.AnalysisDto; | ||
| 17 | +import com.nctigba.observability.instance.dto.asp.AspCountReq; | ||
| 18 | +import com.nctigba.observability.instance.mapper.AspMapper; | ||
| 19 | +import com.nctigba.observability.instance.service.AspService; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * AspServiceImpl | ||
| 23 | + * | ||
| 24 | + * liupengfei | ||
| 25 | + * 2023/8/11 | ||
| 26 | + */ | ||
| 27 | + | ||
| 28 | +public class AspServiceImpl implements AspService { | ||
| 29 | + | ||
| 30 | + private AspMapper aspMapper; | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + public Map<String, List<Object>> count(AspCountReq req) { | ||
| 35 | + List<Map<String, Object>> searchRes = aspMapper.count(req); | ||
| 36 | + ArrayList<Object> time = new ArrayList<>(); | ||
| 37 | + ArrayList<Object> count = new ArrayList<>(); | ||
| 38 | + Map<String, List<Object>> res = new HashMap<>(); | ||
| 39 | + for (Map<String, Object> map : searchRes) { | ||
| 40 | + time.add(map.get("sample_time")); | ||
| 41 | + count.add(map.get("session_count")); | ||
| 42 | + } | ||
| 43 | + res.put("sessionCount", count); | ||
| 44 | + res.put("sampleTime", time); | ||
| 45 | + return res; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + public List<AnalysisDto> analysis(AspCountReq req) { | ||
| 51 | + return aspMapper.analysis(req); | ||
| 52 | + } | ||
| 53 | +} | ||
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/ClusterOpsServiceImpl.java+645-0
| @@ -0,0 +1,645 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.cache.CacheUtil; | ||
| 8 | +import cn.hutool.cache.impl.TimedCache; | ||
| 9 | +import cn.hutool.core.bean.BeanUtil; | ||
| 10 | +import cn.hutool.core.lang.Pair; | ||
| 11 | +import cn.hutool.core.map.MapUtil; | ||
| 12 | +import cn.hutool.core.thread.ThreadUtil; | ||
| 13 | +import cn.hutool.core.util.StrUtil; | ||
| 14 | +import com.alibaba.fastjson.JSONObject; | ||
| 15 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 16 | +import com.nctigba.observability.instance.constants.MetricsLine; | ||
| 17 | +import com.nctigba.observability.instance.dto.cluster.ClusterHealthState; | ||
| 18 | +import com.nctigba.observability.instance.dto.cluster.ClusterStateDto; | ||
| 19 | +import com.nctigba.observability.instance.dto.cluster.ClustersDto; | ||
| 20 | +import com.nctigba.observability.instance.dto.cluster.NodeAndCompDto; | ||
| 21 | +import com.nctigba.observability.instance.dto.cluster.NodeRelationDto; | ||
| 22 | +import com.nctigba.observability.instance.dto.cluster.SyncSituation; | ||
| 23 | +import com.nctigba.observability.instance.dto.cluster.SyncSituationDto; | ||
| 24 | +import com.nctigba.observability.instance.exception.InstanceException; | ||
| 25 | +import com.nctigba.observability.instance.mapper.ClustersMapper; | ||
| 26 | +import com.nctigba.observability.instance.service.ClusterManager; | ||
| 27 | +import com.nctigba.observability.instance.service.ClusterOpsService; | ||
| 28 | +import com.nctigba.observability.instance.service.MetricsService; | ||
| 29 | +import com.nctigba.observability.instance.util.SshSession; | ||
| 30 | +import lombok.extern.slf4j.Slf4j; | ||
| 31 | +import org.jetbrains.annotations.NotNull; | ||
| 32 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 33 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostUserEntity; | ||
| 34 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 35 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; | ||
| 36 | +import org.opengauss.admin.common.enums.ops.DeployTypeEnum; | ||
| 37 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 38 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 39 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 40 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 41 | +import org.springframework.stereotype.Service; | ||
| 42 | + | ||
| 43 | +import java.io.IOException; | ||
| 44 | +import java.time.Instant; | ||
| 45 | +import java.time.LocalDateTime; | ||
| 46 | +import java.time.LocalTime; | ||
| 47 | +import java.time.ZoneId; | ||
| 48 | +import java.time.ZoneOffset; | ||
| 49 | +import java.util.ArrayList; | ||
| 50 | +import java.util.Collection; | ||
| 51 | +import java.util.Collections; | ||
| 52 | +import java.util.Date; | ||
| 53 | +import java.util.HashMap; | ||
| 54 | +import java.util.HashSet; | ||
| 55 | +import java.util.List; | ||
| 56 | +import java.util.Map; | ||
| 57 | +import java.util.Optional; | ||
| 58 | +import java.util.Set; | ||
| 59 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 60 | +import java.util.concurrent.CopyOnWriteArrayList; | ||
| 61 | +import java.util.concurrent.CountDownLatch; | ||
| 62 | +import java.util.concurrent.ExecutionException; | ||
| 63 | +import java.util.concurrent.Future; | ||
| 64 | +import java.util.concurrent.TimeUnit; | ||
| 65 | +import java.util.concurrent.TimeoutException; | ||
| 66 | +import java.util.stream.Collectors; | ||
| 67 | + | ||
| 68 | +import static com.nctigba.observability.instance.dto.cluster.NodeRelationDto.getDefaultRelationDto; | ||
| 69 | +import static com.nctigba.observability.instance.dto.cluster.NodeRelationDto.setNodeState; | ||
| 70 | +import static com.nctigba.observability.instance.dto.cluster.SyncSituationDto.getDefaultSituationDto; | ||
| 71 | + | ||
| 72 | +/** | ||
| 73 | + * ClusterOpsServiceImpl | ||
| 74 | + * | ||
| 75 | + * liupengfei | ||
| 76 | + * 2023/8/11 | ||
| 77 | + */ | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +public class ClusterOpsServiceImpl implements ClusterOpsService { | ||
| 81 | + private static final MetricsLine[] CLUSTER_METRICS = { | ||
| 82 | + MetricsLine.CPU, | ||
| 83 | + MetricsLine.MEMORY, | ||
| 84 | + MetricsLine.IOPS_R_TOTAL, | ||
| 85 | + MetricsLine.NETWORK_IN_TOTAL, | ||
| 86 | + MetricsLine.NETWORK_OUT_TOTAL, | ||
| 87 | + MetricsLine.INSTANCE_QPS, | ||
| 88 | + MetricsLine.INSTANCE_DB_RESPONSETIME_P80, | ||
| 89 | + MetricsLine.INSTANCE_DB_RESPONSETIME_P95, | ||
| 90 | + MetricsLine.CLUSTER_PRIMARY_WAL_SEND_PRESSURE, | ||
| 91 | + MetricsLine.CLUSTER_PRIMARY_WAL_WRITE_PER_SEC, | ||
| 92 | + MetricsLine.CLUSTER_WAL_RECEIVED_DELAY, | ||
| 93 | + MetricsLine.CLUSTER_WAL_WRITE_DELAY, | ||
| 94 | + MetricsLine.CLUSTER_WAL_REPLAY_DELAY | ||
| 95 | + }; | ||
| 96 | + private static final long CACHE_TIMEOUT = 15000L; | ||
| 97 | + private static final long CACHE_CLEAN_INTERVAL = 60000L; | ||
| 98 | + private static final TimedCache<String, ClusterHealthState> CLUSTER_STATE_CACHE; | ||
| 99 | + | ||
| 100 | + static { | ||
| 101 | + CLUSTER_STATE_CACHE = CacheUtil.newTimedCache(CACHE_TIMEOUT); | ||
| 102 | + CLUSTER_STATE_CACHE.schedulePrune(CACHE_CLEAN_INTERVAL); | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + | ||
| 106 | + private MetricsService metricsService; | ||
| 107 | + | ||
| 108 | + private ClusterManager clusterManager; | ||
| 109 | + | ||
| 110 | + | ||
| 111 | + private HostFacade hostFacade; | ||
| 112 | + | ||
| 113 | + | ||
| 114 | + private HostUserFacade hostUserFacade; | ||
| 115 | + | ||
| 116 | + | ||
| 117 | + private EncryptionUtils encryptionUtils; | ||
| 118 | + | ||
| 119 | + private ClustersMapper clustersMapper; | ||
| 120 | + | ||
| 121 | + | ||
| 122 | + public List<ClustersDto> listClusters() { | ||
| 123 | + List<ClustersDto> list = new ArrayList<>(); | ||
| 124 | + List<OpsClusterVO> clusters = clusterManager.getAllOpsCluster(); | ||
| 125 | + for (OpsClusterVO cluster : clusters) { | ||
| 126 | + if (!DeployTypeEnum.CLUSTER.equals(cluster.getDeployType())) { | ||
| 127 | + continue; | ||
| 128 | + } | ||
| 129 | + ClustersDto clustersDto = ClustersDto.of(cluster); | ||
| 130 | + list.add(clustersDto); | ||
| 131 | + } | ||
| 132 | + return list; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + | ||
| 136 | + public List<JSONObject> nodes(String clusterId) { | ||
| 137 | + OpsClusterVO cluster = getOpsClusterVOById(clusterId); | ||
| 138 | + ClusterHealthState stateCache = getClusterHealthState(clusterId, cluster); | ||
| 139 | + List<OpsClusterNodeVO> clusterNodes = cluster.getClusterNodes(); | ||
| 140 | + List<SyncSituationDto> nodeSyncSituationDtoList = new CopyOnWriteArrayList<>(); | ||
| 141 | + | ||
| 142 | + // get standby nodes | ||
| 143 | + getClusterStandbyNodes(nodeSyncSituationDtoList, cluster); | ||
| 144 | + | ||
| 145 | + // check | ||
| 146 | + checkPrimaryNode(cluster, stateCache, nodeSyncSituationDtoList); | ||
| 147 | + | ||
| 148 | + // get cm、om state | ||
| 149 | + HashMap<String, Map<String, String>> cmAndOmState = getCmAndOmState(clusterNodes); | ||
| 150 | + return nodeSyncSituationDtoList.stream().map(syn -> { | ||
| 151 | + NodeAndCompDto com = new NodeAndCompDto(); | ||
| 152 | + com.setCmAgentState( | ||
| 153 | + cmAndOmState.get("cmAgent").getOrDefault(syn.getHostIp(), NodeAndCompDto.BinState.STOP.getCode())); | ||
| 154 | + com.setCmServerState( | ||
| 155 | + cmAndOmState.get("cmServer").getOrDefault(syn.getHostIp(), NodeAndCompDto.BinState.STOP.getCode())); | ||
| 156 | + com.setOmMonitorState(cmAndOmState.get("omMonitor").getOrDefault(syn.getHostIp(), | ||
| 157 | + NodeAndCompDto.BinState.STOP.getCode())); | ||
| 158 | + JSONObject jsonObject = new JSONObject(); | ||
| 159 | + jsonObject.putAll(BeanUtil.beanToMap(syn)); | ||
| 160 | + jsonObject.putAll(BeanUtil.beanToMap(com)); | ||
| 161 | + jsonObject.remove("walSyncState"); | ||
| 162 | + return jsonObject; | ||
| 163 | + }).collect(Collectors.toList()); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + private HashMap<String, Map<String, String>> getCmAndOmState(List<OpsClusterNodeVO> clusterNodes) { | ||
| 167 | + ConcurrentHashMap<String, String> cmServer = new ConcurrentHashMap<>(); | ||
| 168 | + ConcurrentHashMap<String, String> cmAgent = new ConcurrentHashMap<>(); | ||
| 169 | + ConcurrentHashMap<String, String> omMonitor = new ConcurrentHashMap<>(); | ||
| 170 | + CountDownLatch countDownLatch = ThreadUtil.newCountDownLatch(clusterNodes.size()); | ||
| 171 | + for (OpsClusterNodeVO clusterNode : clusterNodes) { | ||
| 172 | + ThreadUtil.execute(() -> { | ||
| 173 | + try { | ||
| 174 | + execute(cmServer, cmAgent, omMonitor, clusterNode); | ||
| 175 | + } finally { | ||
| 176 | + countDownLatch.countDown(); | ||
| 177 | + } | ||
| 178 | + }); | ||
| 179 | + } | ||
| 180 | + HashMap<String, Map<String, String>> map = new HashMap<>(); | ||
| 181 | + map.put("cmServer", cmServer); | ||
| 182 | + map.put("cmAgent", cmAgent); | ||
| 183 | + map.put("omMonitor", omMonitor); | ||
| 184 | + return map; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + private void execute(Map<String, String> cmServer, Map<String, String> cmAgent, Map<String, String> omMonitor, | ||
| 188 | + OpsClusterNodeVO clusterNode) { | ||
| 189 | + SshSession sshSession = null; | ||
| 190 | + try { | ||
| 191 | + sshSession = getSshSession(clusterNode); | ||
| 192 | + } catch (IOException e) { | ||
| 193 | + log.error(e.getMessage(), e); | ||
| 194 | + } | ||
| 195 | + if (sshSession == null) { | ||
| 196 | + cmServer.put(clusterNode.getPublicIp(), "Unknown"); | ||
| 197 | + cmAgent.put(clusterNode.getPublicIp(), "Unknown"); | ||
| 198 | + omMonitor.put(clusterNode.getPublicIp(), "Unknown"); | ||
| 199 | + return; | ||
| 200 | + } | ||
| 201 | + String executeRes = null; | ||
| 202 | + try { | ||
| 203 | + executeRes = sshSession.execute("ps -aux | grep \"cm_agent\\|cm_server\\|om_monitor\" | grep -v grep"); | ||
| 204 | + } catch (IOException e) { | ||
| 205 | + log.error(e.getMessage(), e); | ||
| 206 | + } | ||
| 207 | + if (executeRes == null) { | ||
| 208 | + cmServer.put(clusterNode.getPublicIp(), "Unknown"); | ||
| 209 | + cmAgent.put(clusterNode.getPublicIp(), "Unknown"); | ||
| 210 | + omMonitor.put(clusterNode.getPublicIp(), "Unknown"); | ||
| 211 | + return; | ||
| 212 | + } | ||
| 213 | + String[] binMessage = executeRes.split(StrUtil.LF); | ||
| 214 | + for (String bin : binMessage) { | ||
| 215 | + String[] s = bin.replaceAll(" +", " ").split(" "); | ||
| 216 | + if (bin.contains("cm_agent")) { | ||
| 217 | + cmAgent.put(clusterNode.getPublicIp(), s[7]); | ||
| 218 | + continue; | ||
| 219 | + } | ||
| 220 | + if (bin.contains("cm_server")) { | ||
| 221 | + cmServer.put(clusterNode.getPublicIp(), s[7]); | ||
| 222 | + continue; | ||
| 223 | + } | ||
| 224 | + if (bin.contains("om_monitor")) { | ||
| 225 | + omMonitor.put(clusterNode.getPublicIp(), s[7]); | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + private static void checkPrimaryNode(OpsClusterVO cluster, ClusterHealthState stateCache, | ||
| 231 | + List<SyncSituationDto> retList) { | ||
| 232 | + if (retList.size() == cluster.getClusterNodes().size()) { | ||
| 233 | + return; | ||
| 234 | + } | ||
| 235 | + Set<String> standbySet = retList.stream().map(SyncSituationDto::getHostIp).collect(Collectors.toSet()); | ||
| 236 | + for (OpsClusterNodeVO clusterNode : cluster.getClusterNodes()) { | ||
| 237 | + if (!standbySet.contains(clusterNode.getPublicIp())) { | ||
| 238 | + SyncSituationDto dto = new SyncSituationDto(); | ||
| 239 | + dto.setClusterId(cluster.getClusterId()); | ||
| 240 | + dto.setNodeId(clusterNode.getNodeId()); | ||
| 241 | + dto.setHostIp(clusterNode.getPublicIp()); | ||
| 242 | + dto.setNodeName(stateCache.getNodeName().get(clusterNode.getPublicIp())); | ||
| 243 | + dto.setLocalAddr(clusterNode.getPublicIp() + ":" + clusterNode.getDbPort()); | ||
| 244 | + dto.setRole(stateCache.getNodeRole().getOrDefault(clusterNode.getPublicIp(), "Unknown")); | ||
| 245 | + dto.setNodeState(stateCache.getNodeState().getOrDefault(clusterNode.getPublicIp(), "Unknown")); | ||
| 246 | + retList.add(0, dto); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + | ||
| 252 | + private OpsClusterVO getOpsClusterVOById(String clusterId) { | ||
| 253 | + Optional<OpsClusterVO> clusterVOOptional = clusterManager.getAllOpsCluster().stream() | ||
| 254 | + .filter(clusterVO -> clusterVO.getClusterId().equals(clusterId)).findFirst(); | ||
| 255 | + if (clusterVOOptional.isEmpty()) { | ||
| 256 | + throw new InstanceException("The cluster does not exist"); | ||
| 257 | + } | ||
| 258 | + return clusterVOOptional.get(); | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + | ||
| 262 | + public List<NodeRelationDto> relation(String clusterId) { | ||
| 263 | + OpsClusterVO cluster = getOpsClusterVOById(clusterId); | ||
| 264 | + ClusterHealthState stateCache = getClusterHealthState(clusterId, cluster); | ||
| 265 | + List<OpsClusterNodeVO> clusterNodes = cluster.getClusterNodes(); | ||
| 266 | + ArrayList<NodeRelationDto> retList = new ArrayList<>(); | ||
| 267 | + HashSet<String> allAliveNodeIpSet = new HashSet<>(); | ||
| 268 | + for (OpsClusterNodeVO node : clusterNodes) { | ||
| 269 | + if ("Primary".equalsIgnoreCase(stateCache.getNodeRole().get(node.getPublicIp()))) { | ||
| 270 | + List<NodeRelationDto> standbyList = clustersMapper.relation(node.getNodeId()); | ||
| 271 | + standbyList.forEach(standby -> setNodeState(standby, stateCache)); | ||
| 272 | + NodeRelationDto primary = getDefaultRelationDto(stateCache, node, standbyList); | ||
| 273 | + retList.add(primary); | ||
| 274 | + allAliveNodeIpSet | ||
| 275 | + .addAll(standbyList.stream().map(NodeRelationDto::getHostIp).collect(Collectors.toList())); | ||
| 276 | + allAliveNodeIpSet.add(primary.getHostIp()); | ||
| 277 | + } | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + // check | ||
| 281 | + if (allAliveNodeIpSet.size() != clusterNodes.size()) { | ||
| 282 | + for (OpsClusterNodeVO node : clusterNodes) { | ||
| 283 | + if (!allAliveNodeIpSet.contains(node.getPublicIp())) { | ||
| 284 | + retList.add(getDefaultRelationDto(stateCache, node, new ArrayList<>())); | ||
| 285 | + } | ||
| 286 | + } | ||
| 287 | + } | ||
| 288 | + return retList; | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + | ||
| 292 | + public List<ClusterStateDto> allClusterState() { | ||
| 293 | + ArrayList<ClusterStateDto> list = new ArrayList<>(); | ||
| 294 | + List<OpsClusterVO> clusters = clusterManager.getAllOpsCluster().stream() | ||
| 295 | + .filter(cluster -> DeployTypeEnum.CLUSTER.equals(cluster.getDeployType())).collect(Collectors.toList()); | ||
| 296 | + refreshAllClusterState(clusters); | ||
| 297 | + clusters.forEach(cluster -> { | ||
| 298 | + ClusterHealthState stateCache = CLUSTER_STATE_CACHE.get(cluster.getClusterId(), false); | ||
| 299 | + list.add(ClusterStateDto.of(cluster, stateCache)); | ||
| 300 | + }); | ||
| 301 | + return list; | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + private void refreshAllClusterState(List<OpsClusterVO> clusters) { | ||
| 305 | + CountDownLatch countDown = ThreadUtil.newCountDownLatch(clusters.size()); | ||
| 306 | + for (OpsClusterVO cluster : clusters) { | ||
| 307 | + if (!DeployTypeEnum.CLUSTER.equals(cluster.getDeployType())) { | ||
| 308 | + continue; | ||
| 309 | + } | ||
| 310 | + ThreadUtil.execute(() -> { | ||
| 311 | + try { | ||
| 312 | + if (!CLUSTER_STATE_CACHE.containsKey(cluster.getClusterId())) { | ||
| 313 | + refreshHealthStateCache(cluster); | ||
| 314 | + } | ||
| 315 | + } finally { | ||
| 316 | + countDown.countDown(); | ||
| 317 | + } | ||
| 318 | + }); | ||
| 319 | + } | ||
| 320 | + try { | ||
| 321 | + countDown.await(10, TimeUnit.SECONDS); | ||
| 322 | + } catch (InterruptedException e) { | ||
| 323 | + throw new InstanceException(e.getMessage(), e); | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + private ClusterHealthState getClusterHealthState(String clusterId, OpsClusterVO cluster) { | ||
| 328 | + if (!CLUSTER_STATE_CACHE.containsKey(cluster.getClusterId())) { | ||
| 329 | + refreshHealthStateCache(cluster); | ||
| 330 | + } | ||
| 331 | + return CLUSTER_STATE_CACHE.get(clusterId, false); | ||
| 332 | + } | ||
| 333 | + | ||
| 334 | + | ||
| 335 | + public List<SyncSituationDto> allStandbyNodes() { | ||
| 336 | + List<OpsClusterVO> clusters = clusterManager.getAllOpsCluster().stream() | ||
| 337 | + .filter(cluster -> DeployTypeEnum.CLUSTER.equals(cluster.getDeployType())).collect(Collectors.toList()); | ||
| 338 | + refreshAllClusterState(clusters); | ||
| 339 | + CopyOnWriteArrayList<SyncSituationDto> retList = new CopyOnWriteArrayList<>(); | ||
| 340 | + CountDownLatch countDownLatch = ThreadUtil.newCountDownLatch(clusters.size()); | ||
| 341 | + for (OpsClusterVO cluster : clusters) { | ||
| 342 | + ThreadUtil.execute(() -> { | ||
| 343 | + try { | ||
| 344 | + getClusterStandbyNodes(retList, cluster); | ||
| 345 | + } finally { | ||
| 346 | + countDownLatch.countDown(); | ||
| 347 | + } | ||
| 348 | + }); | ||
| 349 | + } | ||
| 350 | + try { | ||
| 351 | + countDownLatch.await(10, TimeUnit.SECONDS); | ||
| 352 | + } catch (InterruptedException e) { | ||
| 353 | + throw new InstanceException(e.getMessage(), e); | ||
| 354 | + } | ||
| 355 | + return retList; | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + | ||
| 359 | + public Map<String, Object> clusterMetrics(String clusterId, Long start, Long end, Integer step) { | ||
| 360 | + HashMap<String, Object> metricsNodes = new HashMap<>(); | ||
| 361 | + OpsClusterVO opsClusterVOById = getOpsClusterVOById(clusterId); | ||
| 362 | + List<OpsClusterNodeVO> clusterNodes = opsClusterVOById.getClusterNodes(); | ||
| 363 | + List<Pair<String, Future<Map<String, Object>>>> futureList = clusterNodes.stream() | ||
| 364 | + .map(node -> new Pair<>(node.getNodeId(), | ||
| 365 | + ThreadUtil.execAsync( | ||
| 366 | + () -> metricsService.listBatch(CLUSTER_METRICS, node.getNodeId(), start, end, step)))) | ||
| 367 | + .collect(Collectors.toList()); | ||
| 368 | + queryPrimaryWalTotalIncrease(end, metricsNodes, clusterNodes); | ||
| 369 | + for (Pair<String, Future<Map<String, Object>>> future : futureList) { | ||
| 370 | + Map<String, Object> nodeRes; | ||
| 371 | + try { | ||
| 372 | + nodeRes = future.getValue().get(5, TimeUnit.SECONDS); | ||
| 373 | + } catch (InterruptedException | ExecutionException | TimeoutException e) { | ||
| 374 | + log.error(e.getMessage(), e); | ||
| 375 | + continue; | ||
| 376 | + } | ||
| 377 | + metricsNodes.put("time", nodeRes.get("time")); | ||
| 378 | + nodeRes.remove("time"); | ||
| 379 | + getMetricsNodes(metricsNodes, future, nodeRes); | ||
| 380 | + } | ||
| 381 | + return metricsNodes; | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + private void queryPrimaryWalTotalIncrease(Long end, HashMap<String, Object> metricsNodes, | ||
| 385 | + List<OpsClusterNodeVO> clusterNodes) { | ||
| 386 | + LocalDateTime currentDate = LocalDateTime.ofInstant(Instant.ofEpochSecond(end), ZoneId.systemDefault()); | ||
| 387 | + Long startOfTheDay = currentDate.toLocalDate().atStartOfDay().minusSeconds(1) | ||
| 388 | + .toEpochSecond(ZoneOffset.of("+8")); | ||
| 389 | + Long fiveDaysAgo = LocalDateTime.of(currentDate.toLocalDate().minusDays(5), LocalTime.of(23, 59, 59)) | ||
| 390 | + .toEpochSecond(ZoneOffset.of("+8")); | ||
| 391 | + List<Pair<String, Future<Map<String, Object>>>> historyPrimaryWalWriteTotalFutureList = clusterNodes.stream() | ||
| 392 | + .map(node -> new Pair<>(node.getNodeId(), | ||
| 393 | + ThreadUtil.execAsync(() -> metricsService.listBatch(new MetricsLine[]{ | ||
| 394 | + MetricsLine.CLUSTER_PRIMARY_WAL_WRITE_TOTAL | ||
| 395 | + }, node.getNodeId(), fiveDaysAgo, startOfTheDay, 60 * 60 * 24)))).collect(Collectors.toList()); | ||
| 396 | + List<Pair<String, Future<Map<String, Object>>>> todayPrimaryWalWriteTotalFutureList = clusterNodes.stream() | ||
| 397 | + .map(node -> new Pair<>(node.getNodeId(), | ||
| 398 | + ThreadUtil.execAsync(() -> metricsService.listBatch(new MetricsLine[]{ | ||
| 399 | + MetricsLine.CLUSTER_PRIMARY_WAL_WRITE_TOTAL | ||
| 400 | + }, node.getNodeId(), startOfTheDay, end, (int) (end - startOfTheDay))))) | ||
| 401 | + .collect(Collectors.toList()); | ||
| 402 | + List<Date> historyTimeLine = new ArrayList<>(); | ||
| 403 | + getHistoryResult(metricsNodes, historyPrimaryWalWriteTotalFutureList, historyTimeLine); | ||
| 404 | + getTodayResult(metricsNodes, todayPrimaryWalWriteTotalFutureList, historyTimeLine); | ||
| 405 | + Collections.sort(historyTimeLine); | ||
| 406 | + metricsNodes.put("CLUSTER_PRIMARY_WAL_WRITE_TOTAL_TIME", historyTimeLine); | ||
| 407 | + } | ||
| 408 | + | ||
| 409 | + | ||
| 410 | + private static void getTodayResult(HashMap<String, Object> metricsNodes, | ||
| 411 | + List<Pair<String, Future<Map<String, Object>>>> futureList, List<Date> time) { | ||
| 412 | + List<Date> todayTimeLine = new ArrayList<>(); | ||
| 413 | + for (Pair<String, Future<Map<String, Object>>> futurePair : futureList) { | ||
| 414 | + Map<String, Object> today = null; | ||
| 415 | + try { | ||
| 416 | + today = futurePair.getValue().get(5, TimeUnit.SECONDS); | ||
| 417 | + } catch (InterruptedException | ExecutionException | TimeoutException e) { | ||
| 418 | + log.error(e.getMessage(), e); | ||
| 419 | + continue; | ||
| 420 | + } | ||
| 421 | + todayTimeLine = (List<Date>) today.get("time"); | ||
| 422 | + for (Date aLong : todayTimeLine) { | ||
| 423 | + if (!time.contains(aLong)) { | ||
| 424 | + time.add(aLong); | ||
| 425 | + } | ||
| 426 | + } | ||
| 427 | + log.info("...........{}", today.entrySet()); | ||
| 428 | + for (Map.Entry<String, Object> nodeMetrics : today.entrySet()) { | ||
| 429 | + if (!metricsNodes.containsKey(nodeMetrics.getKey())) { | ||
| 430 | + metricsNodes.put(nodeMetrics.getKey(), MapUtil.of(futurePair.getKey(), nodeMetrics.getValue())); | ||
| 431 | + continue; | ||
| 432 | + } | ||
| 433 | + Map<String, Object> metricsNodesValue = (Map<String, Object>) metricsNodes.get(nodeMetrics.getKey()); | ||
| 434 | + List<Object> valueList = (List<Object>) metricsNodesValue.get(futurePair.getKey()); | ||
| 435 | + valueList.addAll((Collection<?>) nodeMetrics.getValue()); | ||
| 436 | + } | ||
| 437 | + } | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + | ||
| 441 | + private static void getHistoryResult(HashMap<String, Object> metricsNodes, | ||
| 442 | + List<Pair<String, Future<Map<String, Object>>>> futureList, List<Date> time) { | ||
| 443 | + for (Pair<String, Future<Map<String, Object>>> futurePair : futureList) { | ||
| 444 | + Map<String, Object> history = null; | ||
| 445 | + try { | ||
| 446 | + history = futurePair.getValue().get(5, TimeUnit.SECONDS); | ||
| 447 | + } catch (InterruptedException | ExecutionException | TimeoutException e) { | ||
| 448 | + log.error(e.getMessage(), e); | ||
| 449 | + continue; | ||
| 450 | + } | ||
| 451 | + List<Date> timeLine = (List<Date>) history.get("time"); | ||
| 452 | + for (Date aLong : timeLine) { | ||
| 453 | + if (!time.contains(aLong)) { | ||
| 454 | + time.add(aLong); | ||
| 455 | + } | ||
| 456 | + } | ||
| 457 | + getMetricsNodes(metricsNodes, futurePair, history); | ||
| 458 | + } | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + private static void getMetricsNodes(HashMap<String, Object> metricsNodes, | ||
| 462 | + Pair<String, Future<Map<String, Object>>> future, Map<String, Object> nodeRes) { | ||
| 463 | + for (Map.Entry<String, Object> nodeMetrics : nodeRes.entrySet()) { | ||
| 464 | + if (!metricsNodes.containsKey(nodeMetrics.getKey())) { | ||
| 465 | + metricsNodes.put(nodeMetrics.getKey(), MapUtil.of(future.getKey(), nodeMetrics.getValue())); | ||
| 466 | + continue; | ||
| 467 | + } | ||
| 468 | + Map<String, Object> metricsNodesValue = (Map<String, Object>) metricsNodes.get(nodeMetrics.getKey()); | ||
| 469 | + metricsNodesValue.put(future.getKey(), nodeMetrics.getValue()); | ||
| 470 | + } | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + private void getClusterStandbyNodes(List<SyncSituationDto> retList, OpsClusterVO cluster) { | ||
| 474 | + ClusterHealthState stateCache = CLUSTER_STATE_CACHE.get(cluster.getClusterId(), false); | ||
| 475 | + List<OpsClusterNodeVO> clusterNodes = cluster.getClusterNodes(); | ||
| 476 | + List<SyncSituationDto> standbyList = new ArrayList<>(); | ||
| 477 | + for (OpsClusterNodeVO clusterNode : clusterNodes) { | ||
| 478 | + if ("Primary".equalsIgnoreCase(stateCache.getNodeRole().get(clusterNode.getPublicIp()))) { | ||
| 479 | + List<SyncSituation> syncSituations = clustersMapper.getSyncSituation(clusterNode.getNodeId()); | ||
| 480 | + syncSituations.forEach(s -> { | ||
| 481 | + SyncSituationDto standby = getDefaultSituationDto(s, clusterNodes, cluster.getClusterId()); | ||
| 482 | + standby.setNodeName(stateCache.getNodeName().get(standby.getHostIp())); | ||
| 483 | + standby.setRole(stateCache.getNodeRole().get(standby.getHostIp())); | ||
| 484 | + standby.setNodeState(stateCache.getNodeState().get(standby.getHostIp())); | ||
| 485 | + standby.setPrimaryAddr(clusterNode.getPublicIp() + ":" + clusterNode.getDbPort()); | ||
| 486 | + standby.setLocalAddr(standby.getHostIp() + ":" + clusterNode.getDbPort()); | ||
| 487 | + standbyList.add(standby); | ||
| 488 | + }); | ||
| 489 | + break; | ||
| 490 | + } | ||
| 491 | + } | ||
| 492 | + checkStandbyNode(cluster, stateCache, standbyList); | ||
| 493 | + retList.addAll(standbyList); | ||
| 494 | + } | ||
| 495 | + | ||
| 496 | + private static void checkStandbyNode(OpsClusterVO cluster, ClusterHealthState stateCache, | ||
| 497 | + List<SyncSituationDto> standbyList) { | ||
| 498 | + // check, the cluster might not have a primary node (pending...) or disconnect | ||
| 499 | + ArrayList<String> allNodeIp = new ArrayList<>(); | ||
| 500 | + for (Map.Entry<String, String> entry : stateCache.getNodeRole().entrySet()) { | ||
| 501 | + if (!"Primary".equals(entry.getValue())) { | ||
| 502 | + allNodeIp.add(entry.getKey()); | ||
| 503 | + } | ||
| 504 | + } | ||
| 505 | + if (standbyList.isEmpty()) { | ||
| 506 | + for (OpsClusterNodeVO clusterNode : cluster.getClusterNodes()) { | ||
| 507 | + SyncSituationDto dto = new SyncSituationDto(); | ||
| 508 | + dto.setClusterId(cluster.getClusterId()); | ||
| 509 | + dto.setNodeId(clusterNode.getNodeId()); | ||
| 510 | + dto.setHostIp(clusterNode.getPublicIp()); | ||
| 511 | + dto.setNodeName(clusterNode.getHostname()); | ||
| 512 | + dto.setLocalAddr(clusterNode.getPublicIp() + ":" + clusterNode.getHostPort()); | ||
| 513 | + dto.setRole(stateCache.getNodeRole().getOrDefault(clusterNode.getPublicIp(), "Unknown")); | ||
| 514 | + dto.setNodeState("Unknown"); | ||
| 515 | + standbyList.add(dto); | ||
| 516 | + } | ||
| 517 | + return; | ||
| 518 | + } | ||
| 519 | + if (standbyList.size() != allNodeIp.size()) { | ||
| 520 | + Set<String> standbyIps = standbyList.stream().map(SyncSituationDto::getHostIp).collect(Collectors.toSet()); | ||
| 521 | + for (String ip : allNodeIp) { | ||
| 522 | + if (!standbyIps.contains(ip)) { | ||
| 523 | + SyncSituationDto dto = new SyncSituationDto(); | ||
| 524 | + dto.setClusterId(cluster.getClusterId()); | ||
| 525 | + dto.setNodeId(cluster.getClusterNodes().stream().filter(node -> node.getPublicIp().equals(ip)) | ||
| 526 | + .findFirst().get().getNodeId()); | ||
| 527 | + dto.setNodeName(stateCache.getNodeName().get(ip)); | ||
| 528 | + dto.setLocalAddr(ip + ":" + cluster.getClusterNodes().get(0).getDbPort()); | ||
| 529 | + dto.setRole(stateCache.getNodeRole().get(ip)); | ||
| 530 | + dto.setNodeState(stateCache.getNodeState().get(ip)); | ||
| 531 | + standbyList.add(dto); | ||
| 532 | + } | ||
| 533 | + } | ||
| 534 | + } | ||
| 535 | + } | ||
| 536 | + | ||
| 537 | + private void refreshHealthStateCache(OpsClusterVO cluster) { | ||
| 538 | + List<OpsClusterNodeVO> clusterNodes = cluster.getClusterNodes(); | ||
| 539 | + SshSession sshSession = null; | ||
| 540 | + | ||
| 541 | + // Select a host that you can connect to | ||
| 542 | + for (OpsClusterNodeVO clusterNode : clusterNodes) { | ||
| 543 | + try { | ||
| 544 | + sshSession = getSshSession(clusterNode); | ||
| 545 | + break; | ||
| 546 | + } catch (IOException e) { | ||
| 547 | + log.error(e.getMessage(), e); | ||
| 548 | + } | ||
| 549 | + } | ||
| 550 | + if (sshSession == null) { | ||
| 551 | + log.error("Failed to connect cluster[{}]", cluster.getClusterId()); | ||
| 552 | + CLUSTER_STATE_CACHE.put(cluster.getClusterId(), new ClusterHealthState()); | ||
| 553 | + return; | ||
| 554 | + } | ||
| 555 | + ClusterHealthState healthState = getHealthState(sshSession, cluster.getEnvPath()); | ||
| 556 | + CLUSTER_STATE_CACHE.put(cluster.getClusterId(), healthState); | ||
| 557 | + } | ||
| 558 | + | ||
| 559 | + private SshSession getSshSession(OpsClusterNodeVO clusterNode) throws IOException { | ||
| 560 | + OpsHostEntity hostEntity = hostFacade.getById(clusterNode.getHostId()); | ||
| 561 | + OpsHostUserEntity userEntity = hostUserFacade.listHostUserByHostId(clusterNode.getHostId()).stream() | ||
| 562 | + .filter(p -> p.getUsername().equals(clusterNode.getInstallUserName())).findFirst().orElseThrow( | ||
| 563 | + () -> new InstanceException("The node information corresponding to the host is not found")); | ||
| 564 | + return SshSession.getSession(hostEntity.getPublicIp(), hostEntity.getPort(), userEntity.getUsername(), | ||
| 565 | + encryptionUtils.decrypt(userEntity.getPassword())); | ||
| 566 | + } | ||
| 567 | + | ||
| 568 | + private ClusterHealthState getHealthState(SshSession sshSession, String envPath) { | ||
| 569 | + String command = "source " + envPath + " && gs_om -t status --detail"; | ||
| 570 | + String result = null; | ||
| 571 | + try { | ||
| 572 | + result = sshSession.execute(command); | ||
| 573 | + } catch (IOException e) { | ||
| 574 | + log.error(e.getMessage(), e); | ||
| 575 | + } | ||
| 576 | + if (result == null) { | ||
| 577 | + return new ClusterHealthState(); | ||
| 578 | + } | ||
| 579 | + ClusterHealthState res = new ClusterHealthState(); | ||
| 580 | + Map<String, String> cmState = new HashMap<>(1); | ||
| 581 | + int cmIndex = result.indexOf("CMServer State"); | ||
| 582 | + if (cmIndex > 0) { | ||
| 583 | + cmState(result, cmState, cmIndex); | ||
| 584 | + } | ||
| 585 | + res.setCmState(cmState); | ||
| 586 | + int clusterStateIndex = result.indexOf("cluster_state"); | ||
| 587 | + String clusterState = null; | ||
| 588 | + if (clusterStateIndex > 0) { | ||
| 589 | + int splitIndex = result.indexOf(":", clusterStateIndex); | ||
| 590 | + int lineEndIndex = result.indexOf(StrUtil.LF, clusterStateIndex); | ||
| 591 | + clusterState = result.substring(splitIndex + 1, lineEndIndex).trim(); | ||
| 592 | + } | ||
| 593 | + res.setClusterState(clusterState); | ||
| 594 | + int datanodeStateIndex = result.indexOf("Datanode State"); | ||
| 595 | + if (datanodeStateIndex > 0) { | ||
| 596 | + nodeState(result, datanodeStateIndex, res); | ||
| 597 | + } | ||
| 598 | + return res; | ||
| 599 | + } | ||
| 600 | + | ||
| 601 | + private static void cmState(String result, Map<String, String> cmState, int cmIndex) { | ||
| 602 | + int splitIndex = result.indexOf("------------------", cmIndex); | ||
| 603 | + String dataNodeStateStr = result.substring(splitIndex); | ||
| 604 | + String[] dataNode = dataNodeStateStr.split(StrUtil.LF); | ||
| 605 | + for (String s : dataNode) { | ||
| 606 | + String[] s1 = s.replaceAll(" +", " ").split(" "); | ||
| 607 | + if (s1.length == 6) { | ||
| 608 | + cmState.put(s1[2], s1[5].trim()); | ||
| 609 | + } | ||
| 610 | + } | ||
| 611 | + } | ||
| 612 | + | ||
| 613 | + private static void nodeState(String result, int datanodeStateIndex, ClusterHealthState res) { | ||
| 614 | + Map<String, String> nodeState = new HashMap<>(1); | ||
| 615 | + Map<String, String> nodeRole = new HashMap<>(1); | ||
| 616 | + Map<String, String> nodeName = new HashMap<>(1); | ||
| 617 | + int splitIndex = result.indexOf("------------------", datanodeStateIndex); | ||
| 618 | + String dataNodeStateStr = result.substring(splitIndex); | ||
| 619 | + String[] dataNode = dataNodeStateStr.split(StrUtil.LF); | ||
| 620 | + for (String s : dataNode) { | ||
| 621 | + String[] s1 = s.replaceAll(" +", " ").split(" "); | ||
| 622 | + String state = ""; | ||
| 623 | + String role = ""; | ||
| 624 | + if (s1.length == 1) { | ||
| 625 | + continue; | ||
| 626 | + } | ||
| 627 | + if (s1.length >= 9) { | ||
| 628 | + for (int i = 8; i < s1.length; i++) { | ||
| 629 | + state += (s1[i] + " "); | ||
| 630 | + } | ||
| 631 | + role = s1[7]; | ||
| 632 | + } | ||
| 633 | + if (s1.length == 8) { | ||
| 634 | + state = s1[7]; | ||
| 635 | + role = s1[6]; | ||
| 636 | + } | ||
| 637 | + nodeState.put(s1[2], state.trim()); | ||
| 638 | + nodeRole.put(s1[2], role); | ||
| 639 | + nodeName.put(s1[2], s1[1]); | ||
| 640 | + } | ||
| 641 | + res.setNodeState(nodeState); | ||
| 642 | + res.setNodeRole(nodeRole); | ||
| 643 | + res.setNodeName(nodeName); | ||
| 644 | + } | ||
| 645 | +} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/MonitoringServiceImpl.java+0-65
| @@ -1,65 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.service.impl; | ||
| 5 | - | ||
| 6 | -import java.util.HashMap; | ||
| 7 | -import java.util.List; | ||
| 8 | -import java.util.Map; | ||
| 9 | - | ||
| 10 | -import org.opengauss.admin.common.exception.CustomException; | ||
| 11 | -import org.springframework.beans.factory.annotation.Autowired; | ||
| 12 | -import org.springframework.stereotype.Service; | ||
| 13 | - | ||
| 14 | -import com.alibaba.fastjson.JSONArray; | ||
| 15 | -import com.alibaba.fastjson.JSONObject; | ||
| 16 | -import com.nctigba.observability.instance.constants.MonitoringResultType; | ||
| 17 | -import com.nctigba.observability.instance.factory.MonitoringHandlerFactory; | ||
| 18 | -import com.nctigba.observability.instance.handler.monitoring.MonitoringHandler; | ||
| 19 | -import com.nctigba.observability.instance.model.monitoring.MonitoringMetric; | ||
| 20 | -import com.nctigba.observability.instance.model.monitoring.MonitoringParam; | ||
| 21 | -import com.nctigba.observability.instance.service.MonitoringService; | ||
| 22 | - | ||
| 23 | - | ||
| 24 | -public class MonitoringServiceImpl implements MonitoringService { | ||
| 25 | - | ||
| 26 | - private MonitoringHandlerFactory monitoringHandlerFactory; | ||
| 27 | - | ||
| 28 | - | ||
| 29 | - public Map<String, Object> getPointMonitoringData(MonitoringParam param) { | ||
| 30 | - MonitoringHandler monitoringHandler = monitoringHandlerFactory.getInstance(param.getMonitoringType()); | ||
| 31 | - List<MonitoringMetric> monitoringMetricList = monitoringHandler.pointQuery(param.getQuery(), param.getTime()); | ||
| 32 | - Map<String, Object> map = new HashMap<>(); | ||
| 33 | - for (MonitoringMetric monitoringMetric : monitoringMetricList) { | ||
| 34 | - JSONObject metric = monitoringMetric.getMetric(); | ||
| 35 | - JSONArray value = monitoringMetric.getValue(); | ||
| 36 | - if (metric.containsKey("__name__")) { | ||
| 37 | - metric.put("value", value.size() == 2 ? value.get(1) : null); | ||
| 38 | - map.put(metric.getString("__name__"), metric); | ||
| 39 | - } else { | ||
| 40 | - map.put("value", value.size() == 2 ? value.get(1) : null); | ||
| 41 | - } | ||
| 42 | - } | ||
| 43 | - return map; | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - | ||
| 47 | - public List<MonitoringMetric> getCurrentMonitoringData(MonitoringParam param) { | ||
| 48 | - MonitoringHandler monitoringHandler = monitoringHandlerFactory.getInstance(param.getMonitoringType()); | ||
| 49 | - return monitoringHandler.pointQuery(param.getQuery(), param.getTime()); | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - | ||
| 53 | - public List<Object> getRangeMonitoringData(MonitoringParam param) { | ||
| 54 | - MonitoringHandler monitoringHandler = monitoringHandlerFactory.getInstance(param.getMonitoringType()); | ||
| 55 | - List<MonitoringMetric> monitoringMetricList = monitoringHandler.rangeQuery(param.getQuery(), param.getStart(), | ||
| 56 | - param.getEnd(), param.getStep()); | ||
| 57 | - if (MonitoringResultType.TABLE.name().equalsIgnoreCase(param.getType())) { | ||
| 58 | - return monitoringHandler.metricToTable(monitoringMetricList, param); | ||
| 59 | - } else if (MonitoringResultType.LINE.name().equalsIgnoreCase(param.getType())) { | ||
| 60 | - return monitoringHandler.metricToLine(monitoringMetricList, param); | ||
| 61 | - } else { | ||
| 62 | - throw new CustomException("Unsupported data format:" + param.getType(), 400); | ||
| 63 | - } | ||
| 64 | - } | ||
| 65 | -} | ||
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/SessionServiceImpl.java+0-236
| @@ -1,236 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance.service.impl; | ||
| 5 | - | ||
| 6 | -import java.sql.Connection; | ||
| 7 | -import java.util.HashMap; | ||
| 8 | -import java.util.List; | ||
| 9 | -import java.util.Map; | ||
| 10 | -import java.util.concurrent.Callable; | ||
| 11 | -import java.util.concurrent.ExecutionException; | ||
| 12 | -import java.util.concurrent.Future; | ||
| 13 | - | ||
| 14 | -import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 15 | -import org.opengauss.admin.common.exception.CustomException; | ||
| 16 | -import org.springframework.stereotype.Service; | ||
| 17 | - | ||
| 18 | -import com.alibaba.fastjson.JSONObject; | ||
| 19 | -import com.nctigba.common.web.exception.InstanceException; | ||
| 20 | -import com.nctigba.observability.instance.constants.DatabaseType; | ||
| 21 | -import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | ||
| 22 | -import com.nctigba.observability.instance.factory.SessionHandlerFactory; | ||
| 23 | -import com.nctigba.observability.instance.handler.session.SessionHandler; | ||
| 24 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | ||
| 25 | -import com.nctigba.observability.instance.service.ClusterManager; | ||
| 26 | -import com.nctigba.observability.instance.service.SessionService; | ||
| 27 | - | ||
| 28 | -import cn.hutool.core.thread.ThreadUtil; | ||
| 29 | -import lombok.RequiredArgsConstructor; | ||
| 30 | -import lombok.extern.slf4j.Slf4j; | ||
| 31 | - | ||
| 32 | - | ||
| 33 | - | ||
| 34 | - | ||
| 35 | -public class SessionServiceImpl implements SessionService { | ||
| 36 | - | ||
| 37 | - private final SessionHandlerFactory sessionHandlerFactory; | ||
| 38 | - private final ClusterManager opsFacade; | ||
| 39 | - | ||
| 40 | - | ||
| 41 | - public JSONObject detailGeneral(String id, String sessionid) { | ||
| 42 | - // query node info | ||
| 43 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 44 | - // get handler | ||
| 45 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 46 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 47 | - JSONObject general; | ||
| 48 | - try { | ||
| 49 | - // query TopSQL list | ||
| 50 | - general = handler.detailGeneral(connection, sessionid); | ||
| 51 | - } catch (Exception e) { | ||
| 52 | - throw new CustomException("", e); | ||
| 53 | - } finally { | ||
| 54 | - handler.close(connection); | ||
| 55 | - } | ||
| 56 | - return general; | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - | ||
| 60 | - public List<DetailStatisticDto> detailStatistic(String id, String sessionid) { | ||
| 61 | - // query node info | ||
| 62 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 63 | - // get handler | ||
| 64 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 65 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 66 | - List<DetailStatisticDto> statistic; | ||
| 67 | - try { | ||
| 68 | - // query TopSQL list | ||
| 69 | - statistic = handler.detailStatistic(connection, sessionid); | ||
| 70 | - } catch (Exception e) { | ||
| 71 | - throw new CustomException("", e); | ||
| 72 | - } finally { | ||
| 73 | - handler.close(connection); | ||
| 74 | - } | ||
| 75 | - return statistic; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - | ||
| 79 | - public List<JSONObject> detailWaiting(String id, String sessionid) { | ||
| 80 | - // query node info | ||
| 81 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 82 | - // get handler | ||
| 83 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 84 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 85 | - List<JSONObject> detailWaiting; | ||
| 86 | - try { | ||
| 87 | - // query list | ||
| 88 | - detailWaiting = handler.detailWaiting(connection, sessionid); | ||
| 89 | - } catch (Exception e) { | ||
| 90 | - throw new CustomException("", e); | ||
| 91 | - } finally { | ||
| 92 | - handler.close(connection); | ||
| 93 | - } | ||
| 94 | - return detailWaiting; | ||
| 95 | - } | ||
| 96 | - | ||
| 97 | - | ||
| 98 | - public List<JSONObject> detailBlockTree(String id, String sessionid) { | ||
| 99 | - // query node info | ||
| 100 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 101 | - // get handler | ||
| 102 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 103 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 104 | - List<JSONObject> detailBlockTree; | ||
| 105 | - try { | ||
| 106 | - // query list | ||
| 107 | - detailBlockTree = handler.detailBlockTree(connection, sessionid); | ||
| 108 | - } catch (Exception e) { | ||
| 109 | - throw new CustomException("", e); | ||
| 110 | - } finally { | ||
| 111 | - handler.close(connection); | ||
| 112 | - } | ||
| 113 | - return detailBlockTree; | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - | ||
| 117 | - public JSONObject simpleStatistic(String id) { | ||
| 118 | - // query node info | ||
| 119 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 120 | - // get handler | ||
| 121 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 122 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 123 | - JSONObject simpleStatistic; | ||
| 124 | - try { | ||
| 125 | - // query list | ||
| 126 | - simpleStatistic = handler.simpleStatistic(connection); | ||
| 127 | - } catch (Exception e) { | ||
| 128 | - throw new CustomException("", e); | ||
| 129 | - } finally { | ||
| 130 | - handler.close(connection); | ||
| 131 | - } | ||
| 132 | - return simpleStatistic; | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - | ||
| 136 | - public List<JSONObject> longTxc(String id) { | ||
| 137 | - // query node info | ||
| 138 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 139 | - // get handler | ||
| 140 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 141 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 142 | - List<JSONObject> longTxc; | ||
| 143 | - try { | ||
| 144 | - // query list | ||
| 145 | - longTxc = handler.longTxc(connection); | ||
| 146 | - } catch (Exception e) { | ||
| 147 | - throw new CustomException("", e); | ||
| 148 | - } finally { | ||
| 149 | - handler.close(connection); | ||
| 150 | - } | ||
| 151 | - return longTxc; | ||
| 152 | - } | ||
| 153 | - | ||
| 154 | - | ||
| 155 | - public HashMap<String, List<JSONObject>> blockAndLongTxc(String id) { | ||
| 156 | - // query node info | ||
| 157 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 158 | - // get handler | ||
| 159 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 160 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 161 | - Future<List<JSONObject>> blockFuture = ThreadUtil.execAsync(() -> handler.detailBlockTree(connection, null)); | ||
| 162 | - Future<List<JSONObject>> longTxcFuture = ThreadUtil.execAsync(() -> handler.longTxc(connection)); | ||
| 163 | - List<JSONObject> blockTree; | ||
| 164 | - List<JSONObject> longTxc; | ||
| 165 | - try { | ||
| 166 | - blockTree = blockFuture.get(); | ||
| 167 | - longTxc = longTxcFuture.get(); | ||
| 168 | - } catch (Exception e) { | ||
| 169 | - log.error("", e); | ||
| 170 | - throw new CustomException("", e); | ||
| 171 | - } finally { | ||
| 172 | - handler.close(connection); | ||
| 173 | - } | ||
| 174 | - HashMap<String, List<JSONObject>> res = new HashMap<>(); | ||
| 175 | - res.put("blockTree", blockTree); | ||
| 176 | - res.put("longTxc", longTxc); | ||
| 177 | - return res; | ||
| 178 | - } | ||
| 179 | - | ||
| 180 | - | ||
| 181 | - "rawtypes", | ||
| 182 | - "unchecked" | ||
| 183 | - }) | ||
| 184 | - | ||
| 185 | - public Map<String, Object> detail(String id, String sessionid) { | ||
| 186 | - // query node info | ||
| 187 | - InstanceNodeInfo instanceNodeInfo = queryNodeInfo(id); | ||
| 188 | - // get handler | ||
| 189 | - SessionHandler handler = sessionHandlerFactory.getInstance(instanceNodeInfo.getDbType()); | ||
| 190 | - Connection connection = handler.getConnection(instanceNodeInfo); | ||
| 191 | - Map<String, Callable> callables = new HashMap<>(); | ||
| 192 | - callables.put("general", () -> handler.detailGeneral(connection, sessionid)); | ||
| 193 | - callables.put("statistic", () -> handler.detailStatistic(connection, sessionid)); | ||
| 194 | - callables.put("blockTree", () -> handler.detailBlockTree(connection, sessionid)); | ||
| 195 | - callables.put("waiting", () -> handler.detailWaiting(connection, sessionid)); | ||
| 196 | - Map<String, Future> futures = new HashMap<>(); | ||
| 197 | - for (Map.Entry<String, Callable> callable : callables.entrySet()) { | ||
| 198 | - futures.put(callable.getKey(), ThreadUtil.execAsync(callable.getValue())); | ||
| 199 | - } | ||
| 200 | - HashMap<String, Object> resMap = new HashMap<>(); | ||
| 201 | - try { | ||
| 202 | - for (Map.Entry<String, Future> future : futures.entrySet()) { | ||
| 203 | - resMap.put(future.getKey(), future.getValue().get()); | ||
| 204 | - } | ||
| 205 | - } catch (ExecutionException | InterruptedException e) { | ||
| 206 | - if (e.getCause() instanceof InstanceException) { | ||
| 207 | - InstanceException instanceException = (InstanceException) e.getCause(); | ||
| 208 | - log.error(instanceException.getMessage(), e); | ||
| 209 | - throw instanceException; | ||
| 210 | - } | ||
| 211 | - throw new InstanceException(e.getMessage(), e); | ||
| 212 | - } finally { | ||
| 213 | - handler.close(connection); | ||
| 214 | - } | ||
| 215 | - return resMap; | ||
| 216 | - } | ||
| 217 | - | ||
| 218 | - /** | ||
| 219 | - * Query instance node information | ||
| 220 | - * | ||
| 221 | - * nodeId instance node id | ||
| 222 | - * Instance node information | ||
| 223 | - */ | ||
| 224 | - public InstanceNodeInfo queryNodeInfo(String nodeId) { | ||
| 225 | - OpsClusterNodeVO opsClusterNode = opsFacade.getOpsNodeById(nodeId); | ||
| 226 | - InstanceNodeInfo instanceNodeInfo = new InstanceNodeInfo(); | ||
| 227 | - instanceNodeInfo.setId(opsClusterNode.getNodeId()); | ||
| 228 | - instanceNodeInfo.setIp(opsClusterNode.getPublicIp()); | ||
| 229 | - instanceNodeInfo.setPort(opsClusterNode.getDbPort()); | ||
| 230 | - instanceNodeInfo.setDbName(opsClusterNode.getDbName()); | ||
| 231 | - instanceNodeInfo.setDbUser(opsClusterNode.getDbUser()); | ||
| 232 | - instanceNodeInfo.setDbUserPassword(opsClusterNode.getDbUserPassword()); | ||
| 233 | - instanceNodeInfo.setDbType(DatabaseType.DEFAULT.getDbType()); | ||
| 234 | - return instanceNodeInfo; | ||
| 235 | - } | ||
| 236 | -} | ||
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/MessageSourceUtil.java+1-1
| @@ -69,7 +69,7 @@ public class MessageSourceUtil { | |||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | public static String getMsg(String key) { | 71 | public static String getMsg(String key) { |
| 72 | - return messageSource.getMessage(key, null, key, getRequestLocale()); | 72 | + return messageSource.getMessage(key, null, null, getRequestLocale()); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | public static String getMsg(String key, Object... objs) { | 75 | public static String getMsg(String key, Object... objs) { |
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/SshSession.java+25-0
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | 2 | * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. |
| 3 | */ | 3 | */ |
| 4 | + | ||
| 4 | package com.nctigba.observability.instance.util; | 5 | package com.nctigba.observability.instance.util; |
| 5 | 6 | ||
| 6 | import java.io.ByteArrayInputStream; | 7 | import java.io.ByteArrayInputStream; |
| @@ -156,6 +157,30 @@ public class SshSession implements AutoCloseable { | |||
| 156 | return new SshSession(host, port, username, password); | 157 | return new SshSession(host, port, username, password); |
| 157 | } | 158 | } |
| 158 | 159 | ||
| 160 | + /** | ||
| 161 | + * session is Open | ||
| 162 | + * | ||
| 163 | + * boolean | ||
| 164 | + */ | ||
| 165 | + public boolean isConnected() { | ||
| 166 | + return session.isOpen(); | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + /** | ||
| 170 | + * get session through sessionPool | ||
| 171 | + * | ||
| 172 | + * host host | ||
| 173 | + * port port | ||
| 174 | + * username username | ||
| 175 | + * password password | ||
| 176 | + * SshSession SshSession | ||
| 177 | + * IOException IOException | ||
| 178 | + */ | ||
| 179 | + public static SshSession getSession(String host, Integer port, String username, String password) | ||
| 180 | + throws IOException { | ||
| 181 | + return SshSessionPool.INSTANCE.getSession(host, port, username, password); | ||
| 182 | + } | ||
| 183 | + | ||
| 159 | 184 | ||
| 160 | public void close() throws IOException { | 185 | public void close() throws IOException { |
| 161 | session.close(); | 186 | session.close(); |
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/SshSessionPool.java+111-0
| @@ -0,0 +1,111 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.util; | ||
| 6 | + | ||
| 7 | +import static com.nctigba.observability.instance.util.SshSession.connect; | ||
| 8 | + | ||
| 9 | +import java.io.IOException; | ||
| 10 | +import java.util.Collection; | ||
| 11 | +import java.util.Iterator; | ||
| 12 | +import java.util.Map; | ||
| 13 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 14 | + | ||
| 15 | +import org.opengauss.admin.common.exception.CustomException; | ||
| 16 | + | ||
| 17 | +import cn.hutool.core.util.StrUtil; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * SshSessionPool | ||
| 21 | + * | ||
| 22 | + * liupengfei | ||
| 23 | + * 2023/8/11 | ||
| 24 | + */ | ||
| 25 | +public enum SshSessionPool { | ||
| 26 | + INSTANCE; | ||
| 27 | + | ||
| 28 | + private Map<String, SshSession> sessionPool = new ConcurrentHashMap<>(); | ||
| 29 | + private static final Object LOCK = new Object(); | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * get a session by key | ||
| 33 | + * | ||
| 34 | + * key key | ||
| 35 | + * SshSession | ||
| 36 | + */ | ||
| 37 | + public SshSession get(String key) { | ||
| 38 | + return sessionPool.get(key); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * put a session | ||
| 43 | + * | ||
| 44 | + * key key | ||
| 45 | + * session SshSession | ||
| 46 | + */ | ||
| 47 | + public void put(String key, SshSession session) { | ||
| 48 | + this.sessionPool.put(key, session); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * get an SSH session and reuse a previously used session. | ||
| 53 | + * | ||
| 54 | + * sshHost host | ||
| 55 | + * sshPort port | ||
| 56 | + * sshUser username | ||
| 57 | + * sshPass password | ||
| 58 | + * an SSH session | ||
| 59 | + * IOException IOException | ||
| 60 | + */ | ||
| 61 | + public SshSession getSession(String sshHost, int sshPort, String sshUser, String sshPass) throws IOException { | ||
| 62 | + final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort); | ||
| 63 | + SshSession session = get(key); | ||
| 64 | + if (session == null || !session.isConnected()) { | ||
| 65 | + synchronized (LOCK) { | ||
| 66 | + session = get(key); | ||
| 67 | + if (session == null || !session.isConnected()) { | ||
| 68 | + session = connect(sshHost, sshPort, sshUser, sshPass); | ||
| 69 | + put(key, session); | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + return session; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * remove a session | ||
| 78 | + * | ||
| 79 | + * session session | ||
| 80 | + */ | ||
| 81 | + public void remove(SshSession session) { | ||
| 82 | + if (session != null) { | ||
| 83 | + final Iterator<Map.Entry<String, SshSession>> iterator = this.sessionPool.entrySet().iterator(); | ||
| 84 | + Map.Entry<String, SshSession> entry; | ||
| 85 | + while (iterator.hasNext()) { | ||
| 86 | + entry = iterator.next(); | ||
| 87 | + if (session.equals(entry.getValue())) { | ||
| 88 | + iterator.remove(); | ||
| 89 | + break; | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * close and clear all session | ||
| 97 | + */ | ||
| 98 | + public void closeAll() { | ||
| 99 | + Collection<SshSession> sessions = sessionPool.values(); | ||
| 100 | + for (SshSession session : sessions) { | ||
| 101 | + if (session.isConnected()) { | ||
| 102 | + try { | ||
| 103 | + session.close(); | ||
| 104 | + } catch (IOException e) { | ||
| 105 | + throw new CustomException(null, e); | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | + sessionPool.clear(); | ||
| 110 | + } | ||
| 111 | +} | ||
| @@ -184,3 +184,44 @@ promuninstall.step4 = \u505C\u6B62prometheus | |||
| 184 | promuninstall.step5 = \u5378\u8F7D\u5B8C\u6210 | 184 | promuninstall.step5 = \u5378\u8F7D\u5B8C\u6210 |
| 185 | session.detail.general.message=The session id does not exist, probably the session has finished executing and closed. | 185 | session.detail.general.message=The session id does not exist, probably the session has finished executing and closed. |
| 186 | session.detail.block.message=The number of rows returned by querying block session through sessionid should be equal to 1, but return {0} | 186 | session.detail.block.message=The number of rows returned by querying block session through sessionid should be equal to 1, but return {0} |
| 187 | +cluster.state.value.Normal=\u53EF\u7528(\u6709\u5197\u4F59\u5907\u4EFD) | ||
| 188 | +cluster.state.value.Unavailable=\u4E0D\u53EF\u7528 | ||
| 189 | +cluster.state.value.Degraded=\u53EF\u7528(\u5B58\u5728\u6545\u969C\u8282\u70B9) | ||
| 190 | +cluster.state.value.Unknown=\u72B6\u6001\u672A\u77E5 | ||
| 191 | +cluster.node.role.Primary=\u4E3B\u5B9E\u4F8B | ||
| 192 | +cluster.node.role.Standby=\u5907\u5B9E\u4F8B | ||
| 193 | +cluster.node.role.Cascade=Cascade | ||
| 194 | +cluster.node.role.Pending=\u4EF2\u88C1\u9636\u6BB5 | ||
| 195 | +cluster.node.role.Unknown=\u72B6\u6001\u672A\u77E5 | ||
| 196 | +cluster.node.role.Down=\u5B95\u673A | ||
| 197 | +cluster.node.role.Abnormal=\u5F02\u5E38 | ||
| 198 | +cluster.node.role.Manually\ stopped=\u624B\u52A8\u505C\u6B62 | ||
| 199 | +cluster.node.state.Normal=\u6B63\u5E38 | ||
| 200 | +cluster.node.state.Need\ repair=\u9700\u8981\u4FEE\u590D | ||
| 201 | +cluster.node.state.Starting=\u542F\u52A8\u4E2D | ||
| 202 | +cluster.node.state.Wait\ promoting=\u7B49\u5F85\u5347\u7EA7 | ||
| 203 | +cluster.node.state.Promoting=\u6B63\u5728\u5347\u7EA7 | ||
| 204 | +cluster.node.state.Demoting=\u964D\u7EA7\u4E2D | ||
| 205 | +cluster.node.state.Building=\u91CD\u5EFA | ||
| 206 | +cluster.node.state.Catchup=\u8FFD\u8D76 | ||
| 207 | +cluster.node.state.Coredump=\u5D29\u6E83 | ||
| 208 | +cluster.node.state.Unknown=\u672A\u77E5 | ||
| 209 | +cluster.arch={0}\u4E3B{1}\u5907 | ||
| 210 | +cluster.state.desc.Normal= | ||
| 211 | +cluster.state.desc.Unavailable= | ||
| 212 | +cluster.state.desc.Degraded= | ||
| 213 | +cluster.state.desc.Unknown= | ||
| 214 | +cluster.node.sync.Async=\u5F02\u6B65\u590D\u5236 | ||
| 215 | +cluster.node.sync.Sync=\u540C\u6B65\u590D\u5236 | ||
| 216 | +cluster.node.sync.Potential=\u5F02\u6B65\u590D\u5236\uFF08\u6F5C\u5728\u540C\u6B65\u5E93\uFF09 | ||
| 217 | +cluster.node.syncState.Streaming=\u4E00\u81F4 | ||
| 218 | +cluster.node.syncState.Catchup=\u8FFD\u8D76 | ||
| 219 | +OS.bin.state.TASK_UNINTERRUPTIBLE=\u7761\u7720 | ||
| 220 | +OS.bin.state.TASK_RUNNING=\u6B63\u5E38 | ||
| 221 | +OS.bin.state.TASK_INTERRUPTIBLE=\u7761\u7720 | ||
| 222 | +OS.bin.state.TASK_STOPPED=\u6682\u505C | ||
| 223 | +OS.bin.state.TASK_TRACED=\u88AB\u8DDF\u8E2A | ||
| 224 | +OS.bin.state.EXIT_ZOMBIE=\u50F5\u6B7B | ||
| 225 | +OS.bin.state.EXIT_DEAD=\u9000\u51FA | ||
| 226 | +OS.bin.state.UNKNOWN=\u672A\u77E5 | ||
| 227 | +OS.bin.state.STOP=\u4E2D\u65AD | ||
| @@ -187,3 +187,44 @@ promuninstall.step4 = Stop Prometheus | |||
| 187 | promuninstall.step5 = Uninstall complete | 187 | promuninstall.step5 = Uninstall complete |
| 188 | session.detail.general.message=The session id does not exist, probably the session has finished executing and closed. | 188 | session.detail.general.message=The session id does not exist, probably the session has finished executing and closed. |
| 189 | session.detail.block.message=The number of rows returned by querying block session through sessionid should be equal to 1, but return {0} | 189 | session.detail.block.message=The number of rows returned by querying block session through sessionid should be equal to 1, but return {0} |
| 190 | +cluster.state.value.Normal=Normal | ||
| 191 | +cluster.state.value.Unavailable=Unavailable | ||
| 192 | +cluster.state.value.Degraded=Degraded | ||
| 193 | +cluster.state.value.Unknown=Unknown | ||
| 194 | +cluster.node.role.Primary=Primary | ||
| 195 | +cluster.node.role.Standby=Standby | ||
| 196 | +cluster.node.role.Cascade=Cascade | ||
| 197 | +cluster.node.role.Pending=Pending | ||
| 198 | +cluster.node.role.Unknown=Unknown | ||
| 199 | +cluster.node.role.Down=Down | ||
| 200 | +cluster.node.role.Abnormal=Abnormal | ||
| 201 | +cluster.node.role.Manually\ stopped=Manually stopped | ||
| 202 | +cluster.node.state.Normal=Normal | ||
| 203 | +cluster.node.state.Need\ repair=Need repair | ||
| 204 | +cluster.node.state.Starting=Starting | ||
| 205 | +cluster.node.state.Wait\ promoting=Wait promoting | ||
| 206 | +cluster.node.state.Promoting=Promoting | ||
| 207 | +cluster.node.state.Demoting=Demoting | ||
| 208 | +cluster.node.state.Building=Building | ||
| 209 | +cluster.node.state.Catchup=Catchup | ||
| 210 | +cluster.node.state.Coredump=Coredump | ||
| 211 | +cluster.node.state.Unknown=Unknown | ||
| 212 | +cluster.arch={0} primary {1} standby | ||
| 213 | +cluster.state.desc.Normal=All database nodes in the cluster are healthy | ||
| 214 | +cluster.state.desc.Unavailable=The cluster is unavailable | ||
| 215 | +cluster.state.desc.Degraded=The cluster is available, but there are failed database nodes | ||
| 216 | +cluster.state.desc.Unknown=The cluster cannot be connected and the status is unknown | ||
| 217 | +cluster.node.sync.Async=Async | ||
| 218 | +cluster.node.sync.Sync=Sync | ||
| 219 | +cluster.node.sync.Potential=Potential | ||
| 220 | +cluster.node.syncState.Streaming=Streaming | ||
| 221 | +cluster.node.syncState.Catchup=catchup | ||
| 222 | +OS.bin.state.TASK_UNINTERRUPTIBLE=TASK_UNINTERRUPTIBLE | ||
| 223 | +OS.bin.state.TASK_RUNNING=TASK_RUNNING | ||
| 224 | +OS.bin.state.TASK_INTERRUPTIBLE=TASK_INTERRUPTIBLE | ||
| 225 | +OS.bin.state.TASK_STOPPED=TASK_STOPPED | ||
| 226 | +OS.bin.state.TASK_TRACED=TASK_TRACED | ||
| 227 | +OS.bin.state.EXIT_ZOMBIE=EXIT_ZOMBIE | ||
| 228 | +OS.bin.state.EXIT_DEAD=EXIT_DEAD | ||
| 229 | +OS.bin.state.UNKNOWN=unknown | ||
| 230 | +OS.bin.state.STOP=stop | ||
| @@ -214,3 +214,44 @@ promuninstall.step4 = \u505C\u6B62prometheus | |||
| 214 | promuninstall.step5 = \u5378\u8F7D\u5B8C\u6210 | 214 | promuninstall.step5 = \u5378\u8F7D\u5B8C\u6210 |
| 215 | session.detail.general.message=\u4F1A\u8BDDID\u4E0D\u5B58\u5728\uFF0C\u53EF\u80FD\u4F1A\u8BDD\u5DF2\u6267\u884C\u5B8C\u6BD5\u5E76\u5173\u95ED\u3002 | 215 | session.detail.general.message=\u4F1A\u8BDDID\u4E0D\u5B58\u5728\uFF0C\u53EF\u80FD\u4F1A\u8BDD\u5DF2\u6267\u884C\u5B8C\u6BD5\u5E76\u5173\u95ED\u3002 |
| 216 | session.detail.block.message=\u6839\u636Esessionid\u67E5\u8BE2\u7684\u963B\u585E\u4F1A\u8BDD\u4FE1\u606F\u5E94\u4E3A1\u884C\uFF0C\u4F46\u7ED3\u679C\u4E3A{0}\u884C | 216 | session.detail.block.message=\u6839\u636Esessionid\u67E5\u8BE2\u7684\u963B\u585E\u4F1A\u8BDD\u4FE1\u606F\u5E94\u4E3A1\u884C\uFF0C\u4F46\u7ED3\u679C\u4E3A{0}\u884C |
| 217 | +cluster.state.value.Normal=\u53EF\u7528(\u6709\u5197\u4F59\u5907\u4EFD) | ||
| 218 | +cluster.state.value.Unavailable=\u4E0D\u53EF\u7528 | ||
| 219 | +cluster.state.value.Degraded=\u53EF\u7528(\u5B58\u5728\u6545\u969C\u8282\u70B9) | ||
| 220 | +cluster.state.value.Unknown=\u72B6\u6001\u672A\u77E5 | ||
| 221 | +cluster.node.role.Primary=\u4E3B\u5B9E\u4F8B | ||
| 222 | +cluster.node.role.Standby=\u5907\u5B9E\u4F8B | ||
| 223 | +cluster.node.role.Cascade=\u7EA7\u8054\u5907\u5B9E\u4F8B | ||
| 224 | +cluster.node.role.Pending=\u4EF2\u88C1\u9636\u6BB5 | ||
| 225 | +cluster.node.role.Unknown=\u72B6\u6001\u672A\u77E5 | ||
| 226 | +cluster.node.role.Down=\u5B95\u673A | ||
| 227 | +cluster.node.role.Abnormal=\u5F02\u5E38 | ||
| 228 | +cluster.node.role.Manually\ stopped=\u624B\u52A8\u505C\u6B62 | ||
| 229 | +cluster.node.state.Normal=\u6B63\u5E38 | ||
| 230 | +cluster.node.state.Need\ repair=\u9700\u8981\u4FEE\u590D | ||
| 231 | +cluster.node.state.Starting=\u542F\u52A8\u4E2D | ||
| 232 | +cluster.node.state.Wait\ promoting=\u7B49\u5F85\u5347\u7EA7 | ||
| 233 | +cluster.node.state.Promoting=\u6B63\u5728\u5347\u7EA7 | ||
| 234 | +cluster.node.state.Demoting=\u964D\u7EA7\u4E2D | ||
| 235 | +cluster.node.state.Building=\u91CD\u5EFA | ||
| 236 | +cluster.node.state.Catchup=\u8FFD\u8D76 | ||
| 237 | +cluster.node.state.Coredump=\u5D29\u6E83 | ||
| 238 | +cluster.node.state.Unknown=\u672A\u77E5 | ||
| 239 | +cluster.arch={0}\u4E3B{1}\u5907 | ||
| 240 | +cluster.state.desc.Normal=\u96C6\u7FA4\u4E2D\u6240\u6709\u6570\u636E\u5E93\u8282\u70B9\u8FD0\u884C\u6B63\u5E38 | ||
| 241 | +cluster.state.desc.Unavailable=\u96C6\u7FA4\u4E0D\u53EF\u7528 | ||
| 242 | +cluster.state.desc.Degraded=\u96C6\u7FA4\u53EF\u7528\uFF0C\u4F46\u5B58\u5728\u6545\u969C\u7684\u6570\u636E\u5E93\u8282\u70B9 | ||
| 243 | +cluster.state.desc.Unknown=\u96C6\u7FA4\u65E0\u6CD5\u8FDE\u63A5\uFF0C\u72B6\u6001\u672A\u77E5 | ||
| 244 | +cluster.node.sync.Async=\u5F02\u6B65\u590D\u5236 | ||
| 245 | +cluster.node.sync.Sync=\u540C\u6B65\u590D\u5236 | ||
| 246 | +cluster.node.sync.Potential=\u5F02\u6B65\u590D\u5236\uFF08\u6F5C\u5728\u540C\u6B65\u5E93\uFF09 | ||
| 247 | +cluster.node.syncState.Streaming=\u4E00\u81F4 | ||
| 248 | +cluster.node.syncState.Catchup=\u8FFD\u8D76 | ||
| 249 | +OS.bin.state.TASK_UNINTERRUPTIBLE=\u7761\u7720 | ||
| 250 | +OS.bin.state.TASK_RUNNING=\u6B63\u5E38 | ||
| 251 | +OS.bin.state.TASK_INTERRUPTIBLE=\u7761\u7720 | ||
| 252 | +OS.bin.state.TASK_STOPPED=\u6682\u505C | ||
| 253 | +OS.bin.state.TASK_TRACED=\u88AB\u8DDF\u8E2A | ||
| 254 | +OS.bin.state.EXIT_ZOMBIE=\u50F5\u6B7B | ||
| 255 | +OS.bin.state.EXIT_DEAD=\u9000\u51FA | ||
| 256 | +OS.bin.state.UNKNOWN=\u672A\u77E5 | ||
| 257 | +OS.bin.state.STOP=\u4E2D\u65AD | ||
Dplugins/observability-instance/src/test/java/com/nctigba/observability/instance/ObservabilityPluginApplicationTests.java+0-23
| @@ -1,23 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | -package com.nctigba.observability.instance; | ||
| 5 | - | ||
| 6 | -import org.junit.jupiter.api.Test; | ||
| 7 | -import org.springframework.boot.test.context.SpringBootTest; | ||
| 8 | - | ||
| 9 | -//@SpringBootTest | ||
| 10 | -class ObservabilityPluginApplicationTests { | ||
| 11 | -// @Autowired | ||
| 12 | -// SlowLogMapper slowLogMapper; | ||
| 13 | - // @Test | ||
| 14 | - void contextLoads() { | ||
| 15 | -// List a = slowLogMapper.slowLogtTotalList("postgres","2022-09-19 15:10:12.080 +0800","2022-09-19 15:10:12.080 +0800"); | ||
| 16 | -// System.out.println(slowLogMapper.slowLogtTotalList("postgres", | ||
| 17 | -// "2022-09-19 15:10:12.080 +0800", | ||
| 18 | -// "2022-09-19 15:10:12.080 +0800")); | ||
| 19 | -// System.out.println(slowLogMapper.slowLogtTrendList1()); | ||
| 20 | - | ||
| 21 | - } | ||
| 22 | - | ||
| 23 | -} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/config/ParamInfoInitConfigTest.java+73-0
| @@ -0,0 +1,73 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.config; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 8 | +import static org.mockito.Mockito.mock; | ||
| 9 | +import static org.mockito.Mockito.mockStatic; | ||
| 10 | +import static org.mockito.Mockito.when; | ||
| 11 | + | ||
| 12 | +import java.io.File; | ||
| 13 | +import java.lang.reflect.Field; | ||
| 14 | +import java.sql.Connection; | ||
| 15 | +import java.util.Map; | ||
| 16 | + | ||
| 17 | +import org.junit.jupiter.api.Test; | ||
| 18 | +import org.mockito.MockedStatic; | ||
| 19 | + | ||
| 20 | +import cn.hutool.core.io.FileUtil; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * ParamInfoInitConfigTest | ||
| 24 | + * | ||
| 25 | + * 2023年7月17日 | ||
| 26 | + */ | ||
| 27 | +class ParamInfoInitConfigTest { | ||
| 28 | + | ||
| 29 | + void testGetCon() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { | ||
| 30 | + deleteFile(); | ||
| 31 | + try (MockedStatic<FileUtil> mockedStatic = mockStatic(FileUtil.class)) { | ||
| 32 | + File fileMock = mock(File.class); | ||
| 33 | + when(fileMock.exists()).thenReturn(false); | ||
| 34 | + when(fileMock.getParentFile()).thenReturn(fileMock); | ||
| 35 | + mockedStatic.when(() -> FileUtil.file(anyString())).thenReturn(fileMock); | ||
| 36 | + ParamInfoInitConfig.getCon(ParamInfoInitConfig.PARAMINFO); | ||
| 37 | + | ||
| 38 | + deleteFile(); | ||
| 39 | + clearCache(); | ||
| 40 | + ParamInfoInitConfig.getCon(ParamInfoInitConfig.PARAMINFO); | ||
| 41 | + | ||
| 42 | + when(fileMock.exists()).thenReturn(true); | ||
| 43 | + deleteFile(); | ||
| 44 | + clearCache(); | ||
| 45 | + ParamInfoInitConfig.getCon(ParamInfoInitConfig.PARAMINFO); | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + private static void deleteFile() { | ||
| 50 | + File info = new File("data" + File.separatorChar + "paramInfo.db"); | ||
| 51 | + if (info.exists()) { | ||
| 52 | + info.delete(); | ||
| 53 | + } | ||
| 54 | + File valueInfo = new File("data" + File.separatorChar + "paramValueInfo.db"); | ||
| 55 | + if (valueInfo.exists()) { | ||
| 56 | + valueInfo.delete(); | ||
| 57 | + } | ||
| 58 | + File nul = new File("null"); | ||
| 59 | + if (nul.exists()) { | ||
| 60 | + nul.delete(); | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + private static void clearCache() | ||
| 65 | + throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { | ||
| 66 | + Class<ParamInfoInitConfig> clazz = ParamInfoInitConfig.class; | ||
| 67 | + Field field = clazz.getDeclaredField("map"); | ||
| 68 | + field.setAccessible(true); | ||
| 69 | + | ||
| 70 | + var map = (Map<String, Connection>) field.get(null); | ||
| 71 | + map.clear(); | ||
| 72 | + } | ||
| 73 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/constants/CommonConstantsTest.java+27-0
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.constants; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertThrows; | ||
| 8 | + | ||
| 9 | +import java.lang.reflect.InvocationTargetException; | ||
| 10 | + | ||
| 11 | +import org.junit.jupiter.api.Test; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * CommonConstantsTest | ||
| 15 | + * | ||
| 16 | + * 2023年7月17日 | ||
| 17 | + */ | ||
| 18 | +class CommonConstantsTest { | ||
| 19 | + | ||
| 20 | + void test() { | ||
| 21 | + assertThrows(InvocationTargetException.class, () -> { | ||
| 22 | + var cons = CommonConstants.class.getDeclaredConstructor(); | ||
| 23 | + cons.setAccessible(true); | ||
| 24 | + cons.newInstance(); | ||
| 25 | + }); | ||
| 26 | + } | ||
| 27 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/controller/IndexControllerTest.java+95-0
| @@ -0,0 +1,95 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.controller; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 9 | +import static org.mockito.Mockito.mockStatic; | ||
| 10 | +import static org.mockito.Mockito.when; | ||
| 11 | + | ||
| 12 | +import java.util.List; | ||
| 13 | +import java.util.Map; | ||
| 14 | + | ||
| 15 | +import org.junit.jupiter.api.BeforeEach; | ||
| 16 | +import org.junit.jupiter.api.Test; | ||
| 17 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 18 | +import org.mockito.InjectMocks; | ||
| 19 | +import org.mockito.Mock; | ||
| 20 | +import org.mockito.MockedStatic; | ||
| 21 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 22 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 23 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostUserEntity; | ||
| 24 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 25 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 26 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 27 | + | ||
| 28 | +import com.alibaba.fastjson.JSONObject; | ||
| 29 | +import com.nctigba.observability.instance.mapper.DbConfigMapper; | ||
| 30 | +import com.nctigba.observability.instance.service.ClusterManager; | ||
| 31 | +import com.nctigba.observability.instance.service.ClusterManager.OpsClusterNodeVOSub; | ||
| 32 | +import com.nctigba.observability.instance.service.MetricsService; | ||
| 33 | +import com.nctigba.observability.instance.service.SessionService; | ||
| 34 | +import com.nctigba.observability.instance.service.TopSQLService; | ||
| 35 | +import com.nctigba.observability.instance.util.SshSession; | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * IndexControllerTest.java | ||
| 39 | + * | ||
| 40 | + * 2023年7月17日 | ||
| 41 | + */ | ||
| 42 | + | ||
| 43 | +class IndexControllerTest { | ||
| 44 | + | ||
| 45 | + private IndexController indexController; | ||
| 46 | + | ||
| 47 | + private MetricsService metricsService; | ||
| 48 | + | ||
| 49 | + private TopSQLService topSQLService; | ||
| 50 | + | ||
| 51 | + private SessionService sessionService; | ||
| 52 | + | ||
| 53 | + private SshSession sshSession; | ||
| 54 | + | ||
| 55 | + private DbConfigMapper configMapper; | ||
| 56 | + | ||
| 57 | + private ClusterManager clusterManager; | ||
| 58 | + | ||
| 59 | + private HostFacade hostFacade; | ||
| 60 | + | ||
| 61 | + private HostUserFacade hostUserFacade; | ||
| 62 | + | ||
| 63 | + private EncryptionUtils encryptionUtils; | ||
| 64 | + | ||
| 65 | + | ||
| 66 | + void setup() { | ||
| 67 | + when(sessionService.simpleStatistic(anyString())).thenReturn(new JSONObject()); | ||
| 68 | + OpsClusterNodeVOSub opsClusterNodeVOSub = new OpsClusterNodeVOSub(); | ||
| 69 | + opsClusterNodeVOSub.setHostId("id"); | ||
| 70 | + opsClusterNodeVOSub.setInstallUserName("name"); | ||
| 71 | + when(clusterManager.getOpsNodeById(anyString())).thenReturn(opsClusterNodeVOSub); | ||
| 72 | + when(configMapper.env()).thenReturn(Map.of("datapath", "", "log_directory", "")); | ||
| 73 | + var host = new OpsHostEntity(); | ||
| 74 | + host.setHostId(""); | ||
| 75 | + host.setPublicIp(""); | ||
| 76 | + host.setPort(11); | ||
| 77 | + when(hostFacade.getById(anyString())).thenReturn(host); | ||
| 78 | + OpsHostUserEntity e1 = new OpsHostUserEntity(); | ||
| 79 | + e1.setUsername("name"); | ||
| 80 | + e1.setPassword(""); | ||
| 81 | + when(hostUserFacade.listHostUserByHostId(anyString())).thenReturn(List.of(e1)); | ||
| 82 | + when(encryptionUtils.decrypt(anyString())).thenReturn("pwd"); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + | ||
| 86 | + void test() { | ||
| 87 | + indexController.mainMetrics("id", null, null, null); | ||
| 88 | + indexController.topSQLNow("id"); | ||
| 89 | + try (MockedStatic<SshSession> mockStatic = mockStatic(SshSession.class);) { | ||
| 90 | + mockStatic.when(() -> SshSession.connect(anyString(), anyInt(), anyString(), anyString())) | ||
| 91 | + .thenReturn(sshSession); | ||
| 92 | + indexController.nodeInfo("id"); | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/controller/PageControllerTest.java+73-0
| @@ -0,0 +1,73 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.controller; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.Mockito.when; | ||
| 9 | + | ||
| 10 | +import java.util.HashMap; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +import org.junit.jupiter.api.BeforeEach; | ||
| 15 | +import org.junit.jupiter.api.Test; | ||
| 16 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 17 | +import org.mockito.InjectMocks; | ||
| 18 | +import org.mockito.Mock; | ||
| 19 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 20 | +import org.springframework.context.MessageSource; | ||
| 21 | + | ||
| 22 | +import com.nctigba.observability.instance.constants.MetricsLine; | ||
| 23 | +import com.nctigba.observability.instance.constants.MetricsValue; | ||
| 24 | +import com.nctigba.observability.instance.mapper.DbConfigMapper; | ||
| 25 | +import com.nctigba.observability.instance.service.ClusterManager; | ||
| 26 | +import com.nctigba.observability.instance.service.MetricsService; | ||
| 27 | +import com.nctigba.observability.instance.util.Language; | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * PageControllerTest.java | ||
| 31 | + * | ||
| 32 | + * 2023年7月17日 | ||
| 33 | + */ | ||
| 34 | + | ||
| 35 | +class PageControllerTest { | ||
| 36 | + | ||
| 37 | + private PageController controller; | ||
| 38 | + | ||
| 39 | + private MetricsService metricsService; | ||
| 40 | + | ||
| 41 | + private DbConfigMapper dbConfigMapper; | ||
| 42 | + | ||
| 43 | + private ClusterManager clusterManager; | ||
| 44 | + | ||
| 45 | + private MessageSource messageSource; | ||
| 46 | + | ||
| 47 | + private Language language; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + void setUp() throws Exception { | ||
| 51 | + HashMap<String, Object> result = new HashMap<>(); | ||
| 52 | + result.put("IO_TPS", Map.of("device", "test")); | ||
| 53 | + result.put("NETWORK_TX", Map.of("device", "test")); | ||
| 54 | + result.put(MetricsValue.MEM_TOTAL.name(), "1"); | ||
| 55 | + result.put(MetricsLine.MEMORY_DB_USED.name(), List.of(1, 2, 3)); | ||
| 56 | + when(metricsService.listBatch(any(), any(), any(), any(), any())).thenReturn(result); | ||
| 57 | + when(messageSource.getMessage(any(), any(), any(), any())).thenReturn("any"); | ||
| 58 | + var config = new HashMap<String, Object>(); | ||
| 59 | + config.put("memorytype", "test"); | ||
| 60 | + config.put("name", "test"); | ||
| 61 | + when(dbConfigMapper.memoryConfig()).thenReturn(List.of(config)); | ||
| 62 | + when(dbConfigMapper.memoryNodeDetail()).thenReturn(List.of(config)); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + | ||
| 66 | + void test() { | ||
| 67 | + controller.memory("id", null, null, null); | ||
| 68 | + controller.io("id", null, null, null); | ||
| 69 | + controller.network("id", null, null, null); | ||
| 70 | + controller.instance("id", null, null, null); | ||
| 71 | + controller.waitEvent("id", null, null, null); | ||
| 72 | + } | ||
| 73 | +} | ||
Dplugins/observability-instance/src/test/java/com/nctigba/observability/instance/controller/SessionControllerTest.java+0-63
| @@ -1,63 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.controller; | ||
| 6 | - | ||
| 7 | -import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| 8 | -import static org.mockito.ArgumentMatchers.any; | ||
| 9 | -import static org.mockito.Mockito.times; | ||
| 10 | -import static org.mockito.Mockito.verify; | ||
| 11 | -import static org.mockito.Mockito.when; | ||
| 12 | - | ||
| 13 | -import java.util.HashMap; | ||
| 14 | -import java.util.List; | ||
| 15 | - | ||
| 16 | -import org.junit.jupiter.api.Test; | ||
| 17 | -import org.junit.jupiter.api.extension.ExtendWith; | ||
| 18 | -import org.mockito.InjectMocks; | ||
| 19 | -import org.mockito.Mock; | ||
| 20 | -import org.mockito.junit.jupiter.MockitoExtension; | ||
| 21 | -import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 22 | - | ||
| 23 | -import com.alibaba.fastjson.JSONObject; | ||
| 24 | -import com.nctigba.observability.instance.service.MetricsService; | ||
| 25 | -import com.nctigba.observability.instance.service.impl.MonitoringServiceImpl; | ||
| 26 | -import com.nctigba.observability.instance.service.impl.SessionServiceImpl; | ||
| 27 | - | ||
| 28 | -/** | ||
| 29 | - * SessionServiceImplTest.java | ||
| 30 | - * | ||
| 31 | - * liupengfei | ||
| 32 | - * 2023/6/30 | ||
| 33 | - */ | ||
| 34 | - | ||
| 35 | -class SessionControllerTest { | ||
| 36 | - | ||
| 37 | - SessionController sessionController; | ||
| 38 | - | ||
| 39 | - SessionServiceImpl sessionService; | ||
| 40 | - | ||
| 41 | - MetricsService metricsService; | ||
| 42 | - | ||
| 43 | - MonitoringServiceImpl monitoringService; | ||
| 44 | - | ||
| 45 | - | ||
| 46 | - public void sessionStatistic() { | ||
| 47 | - String id = "123"; | ||
| 48 | - Long start = 111L; | ||
| 49 | - Long end = 222L; | ||
| 50 | - Integer step = 15; | ||
| 51 | - when(monitoringService.getRangeMonitoringData(any())).thenReturn(List.of("waitEven")); | ||
| 52 | - JSONObject jsonObject = new JSONObject(); | ||
| 53 | - jsonObject.put("simple", "val"); | ||
| 54 | - when(sessionService.simpleStatistic(id)).thenReturn(jsonObject); | ||
| 55 | - HashMap<String, Object> metric = new HashMap<>(); | ||
| 56 | - metric.put("metric", "val"); | ||
| 57 | - when(metricsService.listBatch(any(), any(), any(), any(), any())).thenReturn(metric); | ||
| 58 | - | ||
| 59 | - var appResult = sessionController.sessionStatistic(id, start, end, step); | ||
| 60 | - assertNotNull(appResult.getOrDefault(AjaxResult.DATA_TAG, null)); | ||
| 61 | - verify(sessionService, times(1)).simpleStatistic(any()); | ||
| 62 | - } | ||
| 63 | -} | ||
Dplugins/observability-instance/src/test/java/com/nctigba/observability/instance/handler/session/OpenGaussSessionHandlerTest.java+0-183
| @@ -1,183 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.handler.session; | ||
| 6 | - | ||
| 7 | -import com.alibaba.fastjson.JSONObject; | ||
| 8 | -import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | ||
| 9 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | ||
| 10 | -import com.nctigba.observability.instance.service.ClusterManager; | ||
| 11 | -import org.junit.jupiter.api.BeforeEach; | ||
| 12 | -import org.junit.jupiter.api.Test; | ||
| 13 | -import org.junit.jupiter.api.extension.ExtendWith; | ||
| 14 | -import org.mockito.InjectMocks; | ||
| 15 | -import org.mockito.Mock; | ||
| 16 | -import org.mockito.junit.jupiter.MockitoExtension; | ||
| 17 | -import org.mockito.junit.jupiter.MockitoSettings; | ||
| 18 | -import org.mockito.quality.Strictness; | ||
| 19 | - | ||
| 20 | -import java.sql.Connection; | ||
| 21 | -import java.sql.PreparedStatement; | ||
| 22 | -import java.sql.ResultSet; | ||
| 23 | -import java.sql.ResultSetMetaData; | ||
| 24 | -import java.sql.SQLException; | ||
| 25 | -import java.util.List; | ||
| 26 | - | ||
| 27 | -import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 28 | -import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| 29 | -import static org.junit.jupiter.api.Assertions.assertThrows; | ||
| 30 | -import static org.mockito.ArgumentMatchers.anyString; | ||
| 31 | -import static org.mockito.ArgumentMatchers.eq; | ||
| 32 | -import static org.mockito.Mockito.times; | ||
| 33 | -import static org.mockito.Mockito.verify; | ||
| 34 | -import static org.mockito.Mockito.when; | ||
| 35 | - | ||
| 36 | -/** | ||
| 37 | - * OpenGaussSessionHandlerTest.java | ||
| 38 | - * | ||
| 39 | - * 2023年7月17日 | ||
| 40 | - */ | ||
| 41 | - | ||
| 42 | - | ||
| 43 | -class OpenGaussSessionHandlerTest { | ||
| 44 | - | ||
| 45 | - private OpenGaussSessionHandler sessionHandler; | ||
| 46 | - | ||
| 47 | - | ||
| 48 | - private Connection mockConnection; | ||
| 49 | - | ||
| 50 | - | ||
| 51 | - private PreparedStatement mockPreparedStatement; | ||
| 52 | - | ||
| 53 | - | ||
| 54 | - private ResultSet mockResultSet; | ||
| 55 | - | ||
| 56 | - | ||
| 57 | - private ResultSetMetaData mockResultSetMetaData; | ||
| 58 | - | ||
| 59 | - | ||
| 60 | - private ClusterManager clusterManager; | ||
| 61 | - | ||
| 62 | - | ||
| 63 | - public void setUp() throws Exception { | ||
| 64 | - when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement); | ||
| 65 | - when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet); | ||
| 66 | - when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet); | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - | ||
| 70 | - public void testDetailGeneral() throws SQLException { | ||
| 71 | - default1Row3ColumnMockResult(); | ||
| 72 | - when(mockResultSet.next()).thenReturn(true, false, true, false, true, false); | ||
| 73 | - JSONObject detailGeneral = sessionHandler.detailGeneral(mockConnection, "123"); | ||
| 74 | - assertNotNull(detailGeneral); | ||
| 75 | - assertEquals(3, detailGeneral.size()); | ||
| 76 | - verify(mockPreparedStatement, times(3)).executeQuery(); | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - private void default1Row3ColumnMockResult() throws SQLException { | ||
| 80 | - when(mockResultSet.getMetaData()).thenReturn(mockResultSetMetaData); | ||
| 81 | - when(mockResultSetMetaData.getColumnCount()).thenReturn(3); | ||
| 82 | - when(mockResultSetMetaData.getColumnLabel(eq(1))).thenReturn("key1"); | ||
| 83 | - when(mockResultSetMetaData.getColumnLabel(eq(2))).thenReturn("key2"); | ||
| 84 | - when(mockResultSetMetaData.getColumnLabel(eq(3))).thenReturn("count"); | ||
| 85 | - when(mockResultSet.getString(eq(1))).thenReturn("value1"); | ||
| 86 | - when(mockResultSet.getString(eq(2))).thenReturn("value2"); | ||
| 87 | - when(mockResultSet.getString(eq(3))).thenReturn("3"); | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - | ||
| 91 | - public void testDetailGeneralException() throws SQLException { | ||
| 92 | - String sessionId = "123"; | ||
| 93 | - when(mockPreparedStatement.executeQuery()).thenThrow(new SQLException("Query error")); | ||
| 94 | - assertThrows(Exception.class, () -> { | ||
| 95 | - sessionHandler.detailGeneral(mockConnection, sessionId); | ||
| 96 | - }); | ||
| 97 | - } | ||
| 98 | - | ||
| 99 | - | ||
| 100 | - public void testDetailStatistic() throws SQLException { | ||
| 101 | - String sessionId = "123"; | ||
| 102 | - when(mockResultSet.next()).thenReturn(true, false, true, false); | ||
| 103 | - when(mockResultSet.getMetaData()).thenReturn(mockResultSetMetaData); | ||
| 104 | - when(mockResultSetMetaData.getColumnCount()).thenReturn(3); | ||
| 105 | - when(mockResultSetMetaData.getColumnLabel(eq(1))).thenReturn("stat_name"); | ||
| 106 | - when(mockResultSetMetaData.getColumnLabel(eq(2))).thenReturn("statname"); | ||
| 107 | - when(mockResultSetMetaData.getColumnLabel(eq(3))).thenReturn("value"); | ||
| 108 | - when(mockResultSet.getString(eq(1))).thenReturn("stat_name_1"); | ||
| 109 | - when(mockResultSet.getString(eq(2))).thenReturn("statname_2"); | ||
| 110 | - when(mockResultSet.getString(eq(3))).thenReturn("value"); | ||
| 111 | - List<DetailStatisticDto> statistic = sessionHandler.detailStatistic(mockConnection, sessionId); | ||
| 112 | - assertNotNull(statistic); | ||
| 113 | - assertEquals(2, statistic.size()); | ||
| 114 | - verify(mockPreparedStatement, times(2)).executeQuery(); | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - | ||
| 118 | - public void testDetailWaiting() throws SQLException { | ||
| 119 | - String sessionId = "123"; | ||
| 120 | - default1Row3ColumnMockResult(); | ||
| 121 | - when(mockResultSet.next()).thenReturn(true, true, true, false); | ||
| 122 | - List<JSONObject> waiting = sessionHandler.detailWaiting(mockConnection, sessionId); | ||
| 123 | - assertNotNull(waiting); | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - | ||
| 127 | - public void testDetailBlockTree() throws SQLException { | ||
| 128 | - when(mockResultSet.getMetaData()).thenReturn(mockResultSetMetaData); | ||
| 129 | - when(mockResultSetMetaData.getColumnCount()).thenReturn(4); | ||
| 130 | - when(mockResultSetMetaData.getColumnLabel(eq(1))).thenReturn("id"); | ||
| 131 | - when(mockResultSetMetaData.getColumnLabel(eq(2))).thenReturn("pathid"); | ||
| 132 | - when(mockResultSetMetaData.getColumnLabel(eq(3))).thenReturn("parentid"); | ||
| 133 | - when(mockResultSetMetaData.getColumnLabel(eq(4))).thenReturn("tree_id"); | ||
| 134 | - when(mockResultSet.getString(eq(1))).thenReturn("1").thenReturn("2").thenReturn("3"); | ||
| 135 | - when(mockResultSet.getString(eq(2))).thenReturn("/1").thenReturn("/1/2").thenReturn("/1/2/3"); | ||
| 136 | - when(mockResultSet.getString(eq(3))).thenReturn("0").thenReturn("1").thenReturn("2"); | ||
| 137 | - when(mockResultSet.getString(eq(4))).thenReturn("1"); | ||
| 138 | - when(mockResultSet.next()).thenReturn(true, true, true, false); | ||
| 139 | - List<JSONObject> blockTree = sessionHandler.detailBlockTree(mockConnection, "1"); | ||
| 140 | - assertNotNull(blockTree); | ||
| 141 | - assertEquals(1, blockTree.size()); | ||
| 142 | - assertEquals("1", blockTree.get(0).get("id")); | ||
| 143 | - verify(mockPreparedStatement, times(1)).executeQuery(); | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | - | ||
| 147 | - public void testSimpleStatistic() throws SQLException { | ||
| 148 | - default1Row3ColumnMockResult(); | ||
| 149 | - when(mockResultSet.next()).thenReturn(true, true, true, false); | ||
| 150 | - JSONObject statistic = sessionHandler.simpleStatistic(mockConnection); | ||
| 151 | - assertNotNull(statistic); | ||
| 152 | - assertEquals(3, statistic.size()); | ||
| 153 | - verify(mockPreparedStatement, times(1)).executeQuery(); | ||
| 154 | - } | ||
| 155 | - | ||
| 156 | - | ||
| 157 | - public void testLongTxc() throws SQLException { | ||
| 158 | - default1Row3ColumnMockResult(); | ||
| 159 | - when(mockResultSet.next()).thenReturn(true, true, true, false); | ||
| 160 | - List<JSONObject> longTxc = sessionHandler.longTxc(mockConnection); | ||
| 161 | - assertNotNull(longTxc); | ||
| 162 | - assertEquals(3, longTxc.get(0).size()); | ||
| 163 | - verify(mockPreparedStatement, times(1)).executeQuery(); | ||
| 164 | - } | ||
| 165 | - | ||
| 166 | - | ||
| 167 | - public void testGetConnection() { | ||
| 168 | - InstanceNodeInfo nodeInfo = new InstanceNodeInfo(); | ||
| 169 | - nodeInfo.setIp("127.0.0.0"); | ||
| 170 | - nodeInfo.setPort(8080); | ||
| 171 | - nodeInfo.setDbName("dbNameTest"); | ||
| 172 | - when(clusterManager.getConnectionByNodeInfo(nodeInfo)).thenReturn(mockConnection); | ||
| 173 | - Connection connection = sessionHandler.getConnection(nodeInfo); | ||
| 174 | - assertEquals(mockConnection, connection); | ||
| 175 | - } | ||
| 176 | - | ||
| 177 | - | ||
| 178 | - public void testClose() throws SQLException { | ||
| 179 | - sessionHandler.close(mockConnection); | ||
| 180 | - sessionHandler.getDatabaseType(); | ||
| 181 | - verify(mockConnection, times(1)).close(); | ||
| 182 | - } | ||
| 183 | -} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/listener/PluginListenerTest.java+62-0
| @@ -0,0 +1,62 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.listener; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 10 | +import static org.mockito.Mockito.when; | ||
| 11 | + | ||
| 12 | +import org.junit.jupiter.api.Test; | ||
| 13 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 14 | +import org.mockito.InjectMocks; | ||
| 15 | +import org.mockito.Mock; | ||
| 16 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 17 | +import org.opengauss.admin.common.core.vo.MenuVo; | ||
| 18 | +import org.opengauss.admin.system.plugin.facade.MenuFacade; | ||
| 19 | +import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
| 20 | +import org.springframework.context.ConfigurableApplicationContext; | ||
| 21 | +import org.springframework.context.event.ContextClosedEvent; | ||
| 22 | + | ||
| 23 | +import com.gitee.starblues.spring.MainApplicationContext; | ||
| 24 | +import com.gitee.starblues.spring.SpringBeanFactory; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * PluginListenerTest.java | ||
| 28 | + * | ||
| 29 | + * 2023年7月17日 | ||
| 30 | + */ | ||
| 31 | + | ||
| 32 | +class PluginListenerTest { | ||
| 33 | + | ||
| 34 | + private PluginListener pluginListener; | ||
| 35 | + | ||
| 36 | + private ApplicationReadyEvent readyEvent; | ||
| 37 | + | ||
| 38 | + private ConfigurableApplicationContext applicationContext; | ||
| 39 | + | ||
| 40 | + private MainApplicationContext mainApplicationContext; | ||
| 41 | + | ||
| 42 | + private SpringBeanFactory beanFactory; | ||
| 43 | + | ||
| 44 | + private MenuFacade menuFacade; | ||
| 45 | + | ||
| 46 | + private ContextClosedEvent closedEvent; | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + void test() { | ||
| 51 | + when(readyEvent.getApplicationContext()).thenReturn(applicationContext); | ||
| 52 | + when(applicationContext.getBean(any(Class.class))).thenReturn(mainApplicationContext); | ||
| 53 | + when(mainApplicationContext.getSpringBeanFactory()).thenReturn(beanFactory); | ||
| 54 | + when(beanFactory.getBean(MenuFacade.class)).thenReturn(menuFacade); | ||
| 55 | + var vo = new MenuVo(); | ||
| 56 | + vo.setMenuId(1); | ||
| 57 | + when(menuFacade.savePluginMenu(anyString(), anyString(), anyString(), anyInt(), anyString())).thenReturn(vo); | ||
| 58 | + pluginListener.onApplicationEvent(readyEvent); | ||
| 59 | + when(closedEvent.getApplicationContext()).thenReturn(applicationContext); | ||
| 60 | + pluginListener.onApplicationEvent(closedEvent); | ||
| 61 | + } | ||
| 62 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/mapper/ParamInfoMapperTest.java+65-0
| @@ -0,0 +1,65 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.mapper; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertThrows; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 9 | +import static org.mockito.Mockito.mockStatic; | ||
| 10 | +import static org.mockito.Mockito.reset; | ||
| 11 | +import static org.mockito.Mockito.when; | ||
| 12 | + | ||
| 13 | +import java.sql.Connection; | ||
| 14 | +import java.sql.ResultSet; | ||
| 15 | +import java.sql.SQLException; | ||
| 16 | +import java.sql.Statement; | ||
| 17 | + | ||
| 18 | +import org.junit.jupiter.api.Test; | ||
| 19 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 20 | +import org.mockito.InjectMocks; | ||
| 21 | +import org.mockito.Mock; | ||
| 22 | +import org.mockito.MockedStatic; | ||
| 23 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 24 | + | ||
| 25 | +import com.nctigba.observability.instance.config.ParamInfoInitConfig; | ||
| 26 | +import com.nctigba.observability.instance.entity.ParamInfo.ParamType; | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * ParamInfoMapperTest.java | ||
| 30 | + * | ||
| 31 | + * 2023年7月17日 | ||
| 32 | + */ | ||
| 33 | + | ||
| 34 | +class ParamInfoMapperTest { | ||
| 35 | + | ||
| 36 | + private ParamInfoMapper paramInfoMapper; | ||
| 37 | + | ||
| 38 | + private Connection connection; | ||
| 39 | + | ||
| 40 | + private Statement statement; | ||
| 41 | + | ||
| 42 | + private ResultSet resultSet; | ||
| 43 | + | ||
| 44 | + | ||
| 45 | + void test() throws Exception { | ||
| 46 | + try (MockedStatic<ParamInfoInitConfig> mockedStatic = mockStatic(ParamInfoInitConfig.class)) { | ||
| 47 | + when(resultSet.next()).thenReturn(true, true, false); | ||
| 48 | + when(resultSet.getInt(anyString())).thenReturn(1, 2, 3); | ||
| 49 | + when(resultSet.getString(anyString())).thenReturn("OS"); | ||
| 50 | + when(statement.executeQuery(anyString())).thenReturn(resultSet); | ||
| 51 | + when(connection.createStatement()).thenReturn(statement); | ||
| 52 | + mockedStatic.when(() -> { | ||
| 53 | + ParamInfoInitConfig.getCon(anyString()); | ||
| 54 | + }).thenReturn(connection); | ||
| 55 | + paramInfoMapper.afterPropertiesSet(); | ||
| 56 | + ParamInfoMapper.getAll(); | ||
| 57 | + ParamInfoMapper.getById(1); | ||
| 58 | + ParamInfoMapper.getIds(ParamType.OS); | ||
| 59 | + ParamInfoMapper.getParamInfo(ParamType.OS, "OS"); | ||
| 60 | + reset(connection); | ||
| 61 | + when(connection.createStatement()).thenThrow(SQLException.class); | ||
| 62 | + assertThrows(RuntimeException.class, () -> paramInfoMapper.afterPropertiesSet()); | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/mapper/ParamValueInfoMapperTest.java+77-0
| @@ -0,0 +1,77 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.mapper; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertThrows; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 10 | +import static org.mockito.Mockito.mockStatic; | ||
| 11 | +import static org.mockito.Mockito.reset; | ||
| 12 | +import static org.mockito.Mockito.when; | ||
| 13 | + | ||
| 14 | +import java.sql.Connection; | ||
| 15 | +import java.sql.PreparedStatement; | ||
| 16 | +import java.sql.ResultSet; | ||
| 17 | +import java.sql.SQLException; | ||
| 18 | +import java.sql.Statement; | ||
| 19 | +import java.util.List; | ||
| 20 | + | ||
| 21 | +import org.junit.jupiter.api.Test; | ||
| 22 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 23 | +import org.mockito.InjectMocks; | ||
| 24 | +import org.mockito.Mock; | ||
| 25 | +import org.mockito.MockedStatic; | ||
| 26 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 27 | + | ||
| 28 | +import com.nctigba.observability.instance.config.ParamInfoInitConfig; | ||
| 29 | +import com.nctigba.observability.instance.entity.ParamValueInfo; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * ParamValueInfoMapperTest.java | ||
| 33 | + * | ||
| 34 | + * 2023年7月17日 | ||
| 35 | + */ | ||
| 36 | + | ||
| 37 | +class ParamValueInfoMapperTest { | ||
| 38 | + | ||
| 39 | + private ParamValueInfoMapper paramValueInfoMapper; | ||
| 40 | + | ||
| 41 | + private Connection connection; | ||
| 42 | + | ||
| 43 | + private Statement statement; | ||
| 44 | + | ||
| 45 | + private PreparedStatement pstatement; | ||
| 46 | + | ||
| 47 | + private ResultSet resultSet; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + void test() throws SQLException { | ||
| 51 | + try (MockedStatic<ParamInfoInitConfig> mockedStatic = mockStatic(ParamInfoInitConfig.class)) { | ||
| 52 | + when(resultSet.next()).thenReturn(true, true, false); | ||
| 53 | + when(resultSet.getInt(anyInt())).thenReturn(1, 2, 3); | ||
| 54 | + when(resultSet.getString(anyInt())).thenReturn("OS"); | ||
| 55 | + when(pstatement.executeQuery()).thenReturn(resultSet); | ||
| 56 | + when(connection.createStatement()).thenReturn(statement); | ||
| 57 | + when(connection.prepareStatement(anyString())).thenReturn(pstatement); | ||
| 58 | + mockedStatic.when(() -> ParamInfoInitConfig.getCon(anyString())).thenReturn(connection); | ||
| 59 | + | ||
| 60 | + paramValueInfoMapper.query(""); | ||
| 61 | + paramValueInfoMapper.refresh(null); | ||
| 62 | + ParamValueInfoMapper.insert(new ParamValueInfo(1, "", "")); | ||
| 63 | + ParamValueInfoMapper.insertBatch(List.of(new ParamValueInfo(1, "", ""), new ParamValueInfo(1, "", ""))); | ||
| 64 | + ParamValueInfoMapper.delBySids(List.of(1, 2, 3)); | ||
| 65 | + ParamValueInfoMapper.delBySids(List.of()); | ||
| 66 | + ParamValueInfoMapper.selectByInstanceId(""); | ||
| 67 | + reset(connection); | ||
| 68 | + when(connection.createStatement()).thenThrow(SQLException.class); | ||
| 69 | + when(connection.prepareStatement(anyString())).thenThrow(SQLException.class); | ||
| 70 | + assertThrows(RuntimeException.class, () -> ParamValueInfoMapper.selectByInstanceId("")); | ||
| 71 | + assertThrows(RuntimeException.class, () -> ParamValueInfoMapper.insert(new ParamValueInfo(1, "", ""))); | ||
| 72 | + assertThrows(RuntimeException.class, () -> ParamValueInfoMapper | ||
| 73 | + .insertBatch(List.of(new ParamValueInfo(1, "", ""), new ParamValueInfo(1, "", "")))); | ||
| 74 | + assertThrows(RuntimeException.class, () -> ParamValueInfoMapper.delBySids(List.of(1, 2, 3))); | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/ClusterManagerTest.java+79-0
| @@ -0,0 +1,79 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 9 | +import static org.mockito.Mockito.mockStatic; | ||
| 10 | +import static org.mockito.Mockito.when; | ||
| 11 | + | ||
| 12 | +import java.sql.DriverManager; | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +import org.junit.jupiter.api.BeforeEach; | ||
| 16 | +import org.junit.jupiter.api.Test; | ||
| 17 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 18 | +import org.mockito.InjectMocks; | ||
| 19 | +import org.mockito.Mock; | ||
| 20 | +import org.mockito.MockedStatic; | ||
| 21 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 22 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; | ||
| 23 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 24 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 25 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; | ||
| 26 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 27 | +import org.opengauss.admin.system.plugin.facade.OpsFacade; | ||
| 28 | +import org.opengauss.admin.system.service.ops.IOpsClusterService; | ||
| 29 | + | ||
| 30 | +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; | ||
| 31 | +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * ClusterManagerTest.java | ||
| 35 | + * | ||
| 36 | + * 2023年7月17日 | ||
| 37 | + */ | ||
| 38 | + | ||
| 39 | +class ClusterManagerTest { | ||
| 40 | + | ||
| 41 | + private ClusterManager clusterManager; | ||
| 42 | + | ||
| 43 | + private DynamicRoutingDataSource dataSource; | ||
| 44 | + | ||
| 45 | + private DefaultDataSourceCreator dataSourceCreator; | ||
| 46 | + | ||
| 47 | + private OpsFacade opsFacade; | ||
| 48 | + | ||
| 49 | + private HostFacade hostFacade; | ||
| 50 | + | ||
| 51 | + private IOpsClusterService opsClusterService; | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + void setup() { | ||
| 55 | + OpsClusterNodeVO node = new OpsClusterNodeVO(); | ||
| 56 | + node.setNodeId("id"); | ||
| 57 | + OpsClusterVO cluster = new OpsClusterVO(); | ||
| 58 | + cluster.setClusterId("id"); | ||
| 59 | + cluster.setClusterNodes(List.of(node)); | ||
| 60 | + when(opsFacade.listCluster()).thenReturn(List.of(cluster)); | ||
| 61 | + | ||
| 62 | + when(hostFacade.getById(anyString())).thenReturn(new OpsHostEntity()); | ||
| 63 | + OpsClusterEntity opsCluster = new OpsClusterEntity(); | ||
| 64 | + opsCluster.setDatabaseUsername(""); | ||
| 65 | + opsCluster.setDatabasePassword(""); | ||
| 66 | + when(opsClusterService.getById(any())).thenReturn(opsCluster); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + void test() { | ||
| 71 | + clusterManager.setCurrentDatasource("id", null); | ||
| 72 | + clusterManager.pool(); | ||
| 73 | + clusterManager.setCurrentDatasource(null, null); | ||
| 74 | + try (MockedStatic<DriverManager> mockStatic = mockStatic(DriverManager.class)) { | ||
| 75 | + mockStatic.when(() -> DriverManager.getConnection(anyString(), any())).thenReturn(null); | ||
| 76 | + clusterManager.getConnectionByClusterHost("id", "id"); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/ExporterInstallServiceTest.java+117-0
| @@ -0,0 +1,117 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyMap; | ||
| 10 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 11 | +import static org.mockito.Mockito.mockStatic; | ||
| 12 | +import static org.mockito.Mockito.when; | ||
| 13 | + | ||
| 14 | +import java.io.File; | ||
| 15 | +import java.io.IOException; | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +import org.junit.jupiter.api.BeforeEach; | ||
| 19 | +import org.junit.jupiter.api.Test; | ||
| 20 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 21 | +import org.mockito.InjectMocks; | ||
| 22 | +import org.mockito.Mock; | ||
| 23 | +import org.mockito.MockedStatic; | ||
| 24 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 25 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 26 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostUserEntity; | ||
| 27 | +import org.opengauss.admin.common.core.domain.model.ops.WsSession; | ||
| 28 | +import org.opengauss.admin.common.utils.ops.WsUtil; | ||
| 29 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 30 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 31 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 32 | +import org.springframework.core.io.FileSystemResource; | ||
| 33 | +import org.springframework.core.io.ResourceLoader; | ||
| 34 | + | ||
| 35 | +import com.nctigba.observability.instance.entity.NctigbaEnv; | ||
| 36 | +import com.nctigba.observability.instance.mapper.NctigbaEnvMapper; | ||
| 37 | +import com.nctigba.observability.instance.service.ClusterManager.OpsClusterNodeVOSub; | ||
| 38 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 39 | +import com.nctigba.observability.instance.util.SshSession; | ||
| 40 | + | ||
| 41 | +import cn.hutool.http.HttpUtil; | ||
| 42 | + | ||
| 43 | +/** | ||
| 44 | + * ExporterInstallServiceTest.java | ||
| 45 | + * | ||
| 46 | + * 2023年7月17日 | ||
| 47 | + */ | ||
| 48 | + | ||
| 49 | +class ExporterInstallServiceTest { | ||
| 50 | + | ||
| 51 | + private ExporterInstallService exporterInstallService; | ||
| 52 | + | ||
| 53 | + private HostFacade hostFacade; | ||
| 54 | + | ||
| 55 | + private EncryptionUtils encryptionUtils; | ||
| 56 | + | ||
| 57 | + private HostUserFacade hostUserFacade; | ||
| 58 | + | ||
| 59 | + private NctigbaEnvMapper envMapper; | ||
| 60 | + | ||
| 61 | + private WsUtil wsUtil; | ||
| 62 | + | ||
| 63 | + private ClusterManager clusterManager; | ||
| 64 | + | ||
| 65 | + private ResourceLoader loader; | ||
| 66 | + | ||
| 67 | + private SshSession sshSession; | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + void setup() throws IOException { | ||
| 71 | + OpsClusterNodeVOSub node = new OpsClusterNodeVOSub(); | ||
| 72 | + node.setNodeId("id"); | ||
| 73 | + node.setInstallUserName("name"); | ||
| 74 | + node.setDbUser("name"); | ||
| 75 | + node.setDbUserPassword("password"); | ||
| 76 | + node.setDbPort(123); | ||
| 77 | + node.setHostId("id"); | ||
| 78 | + when(clusterManager.getOpsNodeById(anyString())).thenReturn(node); | ||
| 79 | + | ||
| 80 | + OpsHostEntity host = new OpsHostEntity(); | ||
| 81 | + host.setHostId("id"); | ||
| 82 | + host.setPublicIp("123"); | ||
| 83 | + host.setPort(123); | ||
| 84 | + when(hostFacade.getById(any())).thenReturn(host); | ||
| 85 | + when(loader.getResource(anyString())).thenReturn(new FileSystemResource(File.createTempFile("tmp", "tmp"))); | ||
| 86 | + | ||
| 87 | + OpsHostUserEntity user = new OpsHostUserEntity(); | ||
| 88 | + user.setUsername("name"); | ||
| 89 | + user.setPassword(""); | ||
| 90 | + when(hostUserFacade.listHostUserByHostId(anyString())).thenReturn(List.of(user)); | ||
| 91 | + NctigbaEnv nul = null; | ||
| 92 | + when(envMapper.selectOne(any())) | ||
| 93 | + .thenReturn(new NctigbaEnv().setPath("11").setUsername("name").setHostid("host"), nul); | ||
| 94 | + when(encryptionUtils.decrypt(anyString())).thenReturn(""); | ||
| 95 | + when(sshSession.test(anyString())).thenReturn(false); | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + | ||
| 99 | + void test() throws IOException { | ||
| 100 | + try (MockedStatic<SshSession> mockStatic = mockStatic(SshSession.class); | ||
| 101 | + MockedStatic<MessageSourceUtil> msg = mockStatic(MessageSourceUtil.class); | ||
| 102 | + MockedStatic<HttpUtil> util = mockStatic(HttpUtil.class)) { | ||
| 103 | + when(sshSession.execute(anyString())).thenReturn("scrape_configs:" + System.lineSeparator() | ||
| 104 | + + "- scheme: http" + System.lineSeparator() + "" + " job_name: prometheus" + System.lineSeparator() | ||
| 105 | + + " static_configs:" + System.lineSeparator() + " - targets:" + System.lineSeparator() | ||
| 106 | + + " - localhost:9090"); | ||
| 107 | + mockStatic.when(() -> SshSession.connect(anyString(), anyInt(), anyString(), anyString())) | ||
| 108 | + .thenReturn(sshSession); | ||
| 109 | + msg.when(() -> MessageSourceUtil.get(anyString())).thenReturn(""); | ||
| 110 | + util.when(() -> HttpUtil.get(anyString(), anyMap())).thenReturn(null); | ||
| 111 | + util.when(() -> HttpUtil.post(anyString(), anyString())).thenReturn(null); | ||
| 112 | + exporterInstallService.install(new WsSession(null, "id"), "id", "", 9999, 9998); | ||
| 113 | + | ||
| 114 | + exporterInstallService.uninstall(new WsSession(null, "id"), "id"); | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/MetricsServiceTest.java+105-0
| @@ -0,0 +1,105 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyMap; | ||
| 10 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 11 | +import static org.mockito.Mockito.mockStatic; | ||
| 12 | +import static org.mockito.Mockito.when; | ||
| 13 | + | ||
| 14 | +import java.lang.reflect.InvocationTargetException; | ||
| 15 | +import java.util.concurrent.CountDownLatch; | ||
| 16 | + | ||
| 17 | +import org.junit.jupiter.api.BeforeEach; | ||
| 18 | +import org.junit.jupiter.api.Test; | ||
| 19 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 20 | +import org.mockito.InjectMocks; | ||
| 21 | +import org.mockito.Mock; | ||
| 22 | +import org.mockito.MockedStatic; | ||
| 23 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 24 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 25 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 26 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 27 | + | ||
| 28 | +import com.nctigba.observability.instance.constants.MetricsLine; | ||
| 29 | +import com.nctigba.observability.instance.constants.MetricsValue; | ||
| 30 | +import com.nctigba.observability.instance.entity.NctigbaEnv; | ||
| 31 | +import com.nctigba.observability.instance.mapper.NctigbaEnvMapper; | ||
| 32 | +import com.nctigba.observability.instance.service.ClusterManager.OpsClusterNodeVOSub; | ||
| 33 | + | ||
| 34 | +import cn.hutool.core.thread.ThreadUtil; | ||
| 35 | +import cn.hutool.http.HttpUtil; | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * MetricsServiceTest.java | ||
| 39 | + * | ||
| 40 | + * 2023年7月17日 | ||
| 41 | + */ | ||
| 42 | + | ||
| 43 | +class MetricsServiceTest { | ||
| 44 | + private static final Enum<?>[] METRICS = { | ||
| 45 | + MetricsLine.CPU, | ||
| 46 | + MetricsValue.SWAP_FREE | ||
| 47 | + }; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + private MetricsService metricsService; | ||
| 51 | + | ||
| 52 | + private NctigbaEnvMapper envMapper; | ||
| 53 | + | ||
| 54 | + private HostFacade hostFacade; | ||
| 55 | + | ||
| 56 | + private ClusterManager clusterManager; | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + void setup() { | ||
| 60 | + var host = new OpsHostEntity(); | ||
| 61 | + host.setPublicIp(""); | ||
| 62 | + when(hostFacade.getById(anyString())).thenReturn(host); | ||
| 63 | + | ||
| 64 | + OpsClusterNodeVOSub node = new OpsClusterNodeVOSub(); | ||
| 65 | + node.setNodeId("id"); | ||
| 66 | + node.setInstallUserName("name"); | ||
| 67 | + node.setDbUser("name"); | ||
| 68 | + node.setDbUserPassword("password"); | ||
| 69 | + node.setDbPort(123); | ||
| 70 | + node.setHostId("id"); | ||
| 71 | + when(clusterManager.getOpsNodeById(anyString())).thenReturn(node); | ||
| 72 | + when(envMapper.selectOne(any())).thenReturn(new NctigbaEnv().setPort(1).setHostid("host")); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, | ||
| 77 | + InvocationTargetException { | ||
| 78 | + try (MockedStatic<HttpUtil> http = mockStatic(HttpUtil.class); | ||
| 79 | + MockedStatic<ThreadUtil> thread = mockStatic(ThreadUtil.class)) { | ||
| 80 | + http.when(() -> HttpUtil.get(any(), anyMap())).thenAnswer(invocation -> { | ||
| 81 | + var url = invocation.getArgument(0); | ||
| 82 | + if ("http://:1/api/v1/query".equals(url)) { | ||
| 83 | + return "{'status':'success','data':{'resultType':'vector','result':[{'metric':{'__name__':'agent_f" | ||
| 84 | + + "ree_Swap_free_bytes','type':'exporter'},'value':[1689294857.390,'5823524864']}]}}"; | ||
| 85 | + } | ||
| 86 | + return "{'status':'success','data':{'resultType':'matrix','result':[{'metric':{}," | ||
| 87 | + + "'values':[[1689294785.463,'13.90762676073958']]}]}}"; | ||
| 88 | + }); | ||
| 89 | + metricsService.list("1", 1, 1, 1); | ||
| 90 | + metricsService.value("1", 1L); | ||
| 91 | + when(ThreadUtil.newCountDownLatch(anyInt())).thenReturn(new CountDownLatch(0)); | ||
| 92 | + metricsService.listBatch(METRICS, "id", 1L, 1L, 1); | ||
| 93 | + | ||
| 94 | + var extra = metricsService.getClass().getDeclaredMethod("extracted", OpsClusterNodeVO.class, Long.class, | ||
| 95 | + Long.class, Integer.class, Object.class); | ||
| 96 | + extra.setAccessible(true); | ||
| 97 | + OpsClusterNodeVO vo = new OpsClusterNodeVO(); | ||
| 98 | + vo.setNodeId("id"); | ||
| 99 | + vo.setHostId("id"); | ||
| 100 | + for (Enum<?> enum1 : METRICS) { | ||
| 101 | + extra.invoke(metricsService, vo, 1L, 1L, 1, enum1); | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/ParamInfoServiceTest.java+81-0
| @@ -0,0 +1,81 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 10 | +import static org.mockito.Mockito.mockStatic; | ||
| 11 | +import static org.mockito.Mockito.when; | ||
| 12 | + | ||
| 13 | +import java.io.IOException; | ||
| 14 | +import java.sql.SQLException; | ||
| 15 | +import java.util.List; | ||
| 16 | +import java.util.Map; | ||
| 17 | + | ||
| 18 | +import org.junit.jupiter.api.Test; | ||
| 19 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 20 | +import org.mockito.InjectMocks; | ||
| 21 | +import org.mockito.Mock; | ||
| 22 | +import org.mockito.MockedStatic; | ||
| 23 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 24 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 25 | + | ||
| 26 | +import com.nctigba.observability.instance.entity.ParamInfo; | ||
| 27 | +import com.nctigba.observability.instance.mapper.DbConfigMapper; | ||
| 28 | +import com.nctigba.observability.instance.mapper.ParamInfoMapper; | ||
| 29 | +import com.nctigba.observability.instance.mapper.ParamValueInfoMapper; | ||
| 30 | +import com.nctigba.observability.instance.model.ParamQuery; | ||
| 31 | +import com.nctigba.observability.instance.service.ClusterManager.OpsClusterNodeVOSub; | ||
| 32 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 33 | +import com.nctigba.observability.instance.util.SshSession; | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | + * ParamInfoServiceTest.java | ||
| 37 | + * | ||
| 38 | + * 2023年7月17日 | ||
| 39 | + */ | ||
| 40 | + | ||
| 41 | +class ParamInfoServiceTest { | ||
| 42 | + | ||
| 43 | + private ParamInfoService paramInfoService; | ||
| 44 | + | ||
| 45 | + private ClusterManager opsFacade; | ||
| 46 | + | ||
| 47 | + private EncryptionUtils encryptionUtils; | ||
| 48 | + | ||
| 49 | + private ParamValueInfoMapper paramValueInfoMapper; | ||
| 50 | + | ||
| 51 | + private SshSession sshSession; | ||
| 52 | + | ||
| 53 | + private DbConfigMapper dbConfigMapper; | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + void test() throws IOException, SQLException { | ||
| 57 | + when(encryptionUtils.decrypt(anyString())).thenReturn(""); | ||
| 58 | + OpsClusterNodeVOSub node = new OpsClusterNodeVOSub(); | ||
| 59 | + node.setPublicIp("1"); | ||
| 60 | + node.setHostPort(12); | ||
| 61 | + when(opsFacade.getOpsNodeById(anyString())).thenReturn(node); | ||
| 62 | + when(dbConfigMapper.settings()).thenReturn(List.of(Map.of("", ""))); | ||
| 63 | + when(sshSession.execute(anyString())).thenReturn("net.ipv6.mld_max_msf = 64" + System.lineSeparator() | ||
| 64 | + + "net.ipv6.mld_qrv = 2" + System.lineSeparator() | ||
| 65 | + + "net.ipv6.neigh.br-728fbf973182.anycast_delay = 100" + System.lineSeparator() | ||
| 66 | + + "net.ipv6.neigh.br-728fbf973182.app_solicit = 0" + System.lineSeparator() | ||
| 67 | + + "net.ipv6.neigh.br-728fbf973182.base_reachable_time_ms = 30000" + System.lineSeparator() | ||
| 68 | + + "net.ipv6.neigh.br-728fbf973182.delay_first_probe_time = 5" + System.lineSeparator()); | ||
| 69 | + try (MockedStatic<SshSession> mockStatic = mockStatic(SshSession.class); | ||
| 70 | + MockedStatic<ParamInfoMapper> mapper = mockStatic(ParamInfoMapper.class); | ||
| 71 | + MockedStatic<MessageSourceUtil> util = mockStatic(MessageSourceUtil.class)) { | ||
| 72 | + util.when(() -> MessageSourceUtil.get(anyString())).thenReturn("123"); | ||
| 73 | + ParamInfo nul = null; | ||
| 74 | + mapper.when(() -> ParamInfoMapper.getParamInfo(any(), anyString())) | ||
| 75 | + .thenReturn(new ParamInfo().setId(1), nul); | ||
| 76 | + mockStatic.when(() -> SshSession.connect(anyString(), anyInt(), anyString(), anyString())) | ||
| 77 | + .thenReturn(sshSession); | ||
| 78 | + paramInfoService.getParamInfo(new ParamQuery().setIsRefresh("1").setPassword("2").setNodeId("3")); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/PrometheusServiceTest.java+99-0
| @@ -0,0 +1,99 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.mockito.ArgumentMatchers.any; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyInt; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 10 | +import static org.mockito.Mockito.mockStatic; | ||
| 11 | +import static org.mockito.Mockito.when; | ||
| 12 | + | ||
| 13 | +import java.io.File; | ||
| 14 | +import java.io.IOException; | ||
| 15 | +import java.util.List; | ||
| 16 | + | ||
| 17 | +import org.junit.jupiter.api.BeforeEach; | ||
| 18 | +import org.junit.jupiter.api.Test; | ||
| 19 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 20 | +import org.mockito.InjectMocks; | ||
| 21 | +import org.mockito.Mock; | ||
| 22 | +import org.mockito.MockedStatic; | ||
| 23 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 24 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 25 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostUserEntity; | ||
| 26 | +import org.opengauss.admin.common.core.domain.model.ops.WsSession; | ||
| 27 | +import org.opengauss.admin.common.utils.ops.WsUtil; | ||
| 28 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 29 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 30 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 31 | + | ||
| 32 | +import com.nctigba.observability.instance.entity.NctigbaEnv; | ||
| 33 | +import com.nctigba.observability.instance.mapper.NctigbaEnvMapper; | ||
| 34 | +import com.nctigba.observability.instance.util.Download; | ||
| 35 | +import com.nctigba.observability.instance.util.MessageSourceUtil; | ||
| 36 | +import com.nctigba.observability.instance.util.SshSession; | ||
| 37 | + | ||
| 38 | +import cn.hutool.http.HttpUtil; | ||
| 39 | + | ||
| 40 | +/** | ||
| 41 | + * PrometheusServiceTest.java | ||
| 42 | + * | ||
| 43 | + * 2023年7月17日 | ||
| 44 | + */ | ||
| 45 | + | ||
| 46 | +class PrometheusServiceTest { | ||
| 47 | + | ||
| 48 | + private PrometheusService prometheusService; | ||
| 49 | + | ||
| 50 | + private HostFacade hostFacade; | ||
| 51 | + | ||
| 52 | + private EncryptionUtils encryptionUtils; | ||
| 53 | + | ||
| 54 | + private HostUserFacade hostUserFacade; | ||
| 55 | + | ||
| 56 | + private NctigbaEnvMapper envMapper; | ||
| 57 | + | ||
| 58 | + private WsUtil wsUtil; | ||
| 59 | + | ||
| 60 | + private SshSession sshSession; | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + void setup() throws IOException { | ||
| 64 | + OpsHostEntity host = new OpsHostEntity(); | ||
| 65 | + host.setHostId("id"); | ||
| 66 | + host.setPublicIp("123"); | ||
| 67 | + host.setPort(123); | ||
| 68 | + when(hostFacade.getById(any())).thenReturn(host); | ||
| 69 | + when(envMapper.selectById(any())) | ||
| 70 | + .thenReturn(new NctigbaEnv().setHostid("id").setUsername("name").setPort(9999)); | ||
| 71 | + | ||
| 72 | + OpsHostUserEntity user = new OpsHostUserEntity(); | ||
| 73 | + user.setUsername("name"); | ||
| 74 | + user.setPassword(""); | ||
| 75 | + when(hostUserFacade.listHostUserByHostId(anyString())).thenReturn(List.of(user)); | ||
| 76 | + when(encryptionUtils.decrypt(anyString())).thenReturn(""); | ||
| 77 | + when(sshSession.test(anyString())).thenReturn(false); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + void test() throws IOException { | ||
| 82 | + try (MockedStatic<SshSession> mockStatic = mockStatic(SshSession.class); | ||
| 83 | + MockedStatic<MessageSourceUtil> msg = mockStatic(MessageSourceUtil.class); | ||
| 84 | + MockedStatic<HttpUtil> util = mockStatic(HttpUtil.class); | ||
| 85 | + MockedStatic<Download> down = mockStatic(Download.class);) { | ||
| 86 | + when(sshSession.execute(anyString())).thenReturn("scrape_configs:" + System.lineSeparator() | ||
| 87 | + + "- scheme: http" + System.lineSeparator() + " job_name: prometheus" + System.lineSeparator() | ||
| 88 | + + " static_configs:" + System.lineSeparator() + " - targets:" + System.lineSeparator() | ||
| 89 | + + " - localhost:9090"); | ||
| 90 | + mockStatic.when(() -> SshSession.connect(anyString(), anyInt(), anyString(), anyString())) | ||
| 91 | + .thenReturn(sshSession); | ||
| 92 | + msg.when(() -> MessageSourceUtil.get(anyString())).thenReturn(""); | ||
| 93 | + util.when(() -> HttpUtil.get(anyString())).thenReturn("succ"); | ||
| 94 | + down.when(() -> Download.download(anyString(), anyString())).thenReturn(File.createTempFile("test", "tmp")); | ||
| 95 | + prometheusService.install(new WsSession(null, "id"), "id", "", "name", "password", 9998); | ||
| 96 | + prometheusService.uninstall(new WsSession(null, "id"), "id"); | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/SessionServiceTest.java+87-0
| @@ -0,0 +1,87 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| 8 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 9 | +import static org.mockito.Mockito.when; | ||
| 10 | + | ||
| 11 | +import java.util.Collections; | ||
| 12 | +import java.util.List; | ||
| 13 | +import java.util.Map; | ||
| 14 | + | ||
| 15 | +import org.junit.jupiter.api.Test; | ||
| 16 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 17 | +import org.mockito.InjectMocks; | ||
| 18 | +import org.mockito.Mock; | ||
| 19 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 20 | + | ||
| 21 | +import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | ||
| 22 | +import com.nctigba.observability.instance.mapper.SessionMapper; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * SessionServiceImplTest.java | ||
| 26 | + * | ||
| 27 | + * 2023年7月17日 | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | +class SessionServiceTest { | ||
| 31 | + | ||
| 32 | + private SessionService sessionService; | ||
| 33 | + | ||
| 34 | + private SessionMapper sessionMapper; | ||
| 35 | + | ||
| 36 | + private static String getId() { | ||
| 37 | + return "12345"; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + public void testDetailGeneral() { | ||
| 42 | + when(sessionMapper.generalMesList(anyString())).thenReturn(List.of(Map.of("1", 1))); | ||
| 43 | + when(sessionMapper.sessionIsWaiting(anyString())).thenReturn(1); | ||
| 44 | + sessionService.detailGeneral(getId(), getId()); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + public void testDetailStatistic() { | ||
| 49 | + when(sessionMapper.statistic(anyString())).thenReturn(Collections.emptyList()); | ||
| 50 | + // Act | ||
| 51 | + List<DetailStatisticDto> result = sessionService.detailStatistic(getId(), getId()); | ||
| 52 | + // Assert | ||
| 53 | + assertNotNull(result); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + public void testDetailWaiting() { | ||
| 58 | + sessionService.detailWaiting(getId(), getId()); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + | ||
| 62 | + public void testDetailBlockTree() { | ||
| 63 | + sessionService.detailBlockTree(getId(), getId()); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + public void testSimpleStatistic() { | ||
| 68 | + sessionService.simpleStatistic(getId()); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + public void testLongTxc() { | ||
| 73 | + sessionService.longTxc(getId()); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + public void testBlockAndLongTxc() { | ||
| 78 | + sessionService.blockAndLongTxc(getId()); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + | ||
| 82 | + public void testDetail() { | ||
| 83 | + when(sessionMapper.generalMesList(anyString())).thenReturn(List.of(Map.of("1", 1))); | ||
| 84 | + when(sessionMapper.sessionIsWaiting(anyString())).thenReturn(1); | ||
| 85 | + sessionService.detail(getId(), getId()); | ||
| 86 | + } | ||
| 87 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/TopSQLServiceTest.java+95-0
| @@ -0,0 +1,95 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.service; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 8 | +import static org.mockito.ArgumentMatchers.any; | ||
| 9 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 10 | + | ||
| 11 | +import java.util.ArrayList; | ||
| 12 | +import java.util.Arrays; | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +import org.junit.jupiter.api.Test; | ||
| 16 | +import org.junit.jupiter.api.extension.ExtendWith; | ||
| 17 | +import org.mockito.Mock; | ||
| 18 | +import org.mockito.Mockito; | ||
| 19 | +import org.mockito.junit.jupiter.MockitoExtension; | ||
| 20 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterNodeVO; | ||
| 21 | +import org.opengauss.admin.common.core.domain.model.ops.OpsClusterVO; | ||
| 22 | + | ||
| 23 | +import com.alibaba.fastjson.JSONObject; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * TopSQLServiceTest.java | ||
| 27 | + * | ||
| 28 | + * 2023年7月17日 | ||
| 29 | + */ | ||
| 30 | + | ||
| 31 | +class TopSQLServiceTest { | ||
| 32 | + | ||
| 33 | + private ClusterManager clusterManager; | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + private TopSQLService topSQLService; | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + public void testGetCluster() { | ||
| 40 | + Mockito.doReturn(mockClusterList()).when(clusterManager).getAllOpsCluster(); | ||
| 41 | + assertEquals(mockClusterList(), clusterManager.getAllOpsCluster()); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + // @Test | ||
| 45 | + void testGetTopSQLAction() { | ||
| 46 | + Mockito.doReturn(mockTopSQLList()).when(topSQLService).topSQLList(any()); | ||
| 47 | + Mockito.doReturn(mockJsonObject()).when(topSQLService).detail(anyString(), anyString()); | ||
| 48 | + Mockito.doReturn(mockJsonObject()).when(topSQLService).executionPlan(anyString(), anyString()); | ||
| 49 | + Mockito.doReturn(mockStringList()).when(topSQLService).indexAdvice(anyString(), anyString()); | ||
| 50 | + Mockito.doReturn(mockJsonObject()).when(topSQLService).objectInfo(anyString(), anyString()); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + private List<OpsClusterVO> mockClusterList() { | ||
| 54 | + OpsClusterNodeVO opsClusterNode = new OpsClusterNodeVO() { | ||
| 55 | + { | ||
| 56 | + setPublicIp("192.168.0.1"); | ||
| 57 | + setPrivateIp("192.168.0.1"); | ||
| 58 | + setDbPort(15400); | ||
| 59 | + setDbName("postgres"); | ||
| 60 | + setDbUser("root"); | ||
| 61 | + setDbUserPassword("123"); | ||
| 62 | + setAzName("local version"); | ||
| 63 | + setAzAddress("192.168.0.1"); | ||
| 64 | + setClusterRole("local version"); | ||
| 65 | + setNodeId("ffd3dbd2d5a5b920b65441485d949e27"); | ||
| 66 | + } | ||
| 67 | + }; | ||
| 68 | + OpsClusterVO opsClusterVO = new OpsClusterVO(); | ||
| 69 | + opsClusterVO.setClusterId("TestID"); | ||
| 70 | + opsClusterVO.setClusterName("TestMASTER"); | ||
| 71 | + opsClusterVO.setClusterNodes(Arrays.asList(opsClusterNode)); | ||
| 72 | + List<OpsClusterVO> opsClusterVOList = new ArrayList<>(); | ||
| 73 | + opsClusterVOList.add(opsClusterVO); | ||
| 74 | + return opsClusterVOList; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + private List<String> mockStringList() { | ||
| 78 | + List<String> stringList = new ArrayList<>(); | ||
| 79 | + stringList.add("no data"); | ||
| 80 | + return stringList; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private JSONObject mockJsonObject() { | ||
| 84 | + JSONObject jsonObject = new JSONObject(); | ||
| 85 | + jsonObject.put("data", new ArrayList<>()); | ||
| 86 | + return jsonObject; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + private List<JSONObject> mockTopSQLList() { | ||
| 90 | + List<JSONObject> jsonObjectList = new ArrayList<>(); | ||
| 91 | + jsonObjectList.add(new JSONObject()); | ||
| 92 | + jsonObjectList.add(new JSONObject()); | ||
| 93 | + return jsonObjectList; | ||
| 94 | + } | ||
| 95 | +} | ||
Dplugins/observability-instance/src/test/java/com/nctigba/observability/instance/service/impl/SessionServiceImplTest.java+0-198
| @@ -1,198 +0,0 @@ | |||
| 1 | -/* | ||
| 2 | - * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | - */ | ||
| 4 | - | ||
| 5 | -package com.nctigba.observability.instance.service.impl; | ||
| 6 | - | ||
| 7 | -import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 8 | -import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| 9 | -import static org.mockito.ArgumentMatchers.any; | ||
| 10 | -import static org.mockito.Mockito.times; | ||
| 11 | -import static org.mockito.Mockito.verify; | ||
| 12 | -import static org.mockito.Mockito.when; | ||
| 13 | - | ||
| 14 | -import java.sql.Connection; | ||
| 15 | -import java.util.HashMap; | ||
| 16 | -import java.util.List; | ||
| 17 | -import java.util.Map; | ||
| 18 | - | ||
| 19 | -import org.junit.jupiter.api.BeforeEach; | ||
| 20 | -import org.junit.jupiter.api.Test; | ||
| 21 | -import org.junit.jupiter.api.extension.ExtendWith; | ||
| 22 | -import org.mockito.InjectMocks; | ||
| 23 | -import org.mockito.Mock; | ||
| 24 | -import org.mockito.junit.jupiter.MockitoExtension; | ||
| 25 | - | ||
| 26 | -import com.alibaba.fastjson.JSONObject; | ||
| 27 | -import com.nctigba.observability.instance.constants.DatabaseType; | ||
| 28 | -import com.nctigba.observability.instance.dto.session.DetailStatisticDto; | ||
| 29 | -import com.nctigba.observability.instance.factory.SessionHandlerFactory; | ||
| 30 | -import com.nctigba.observability.instance.handler.session.SessionHandler; | ||
| 31 | -import com.nctigba.observability.instance.model.InstanceNodeInfo; | ||
| 32 | -import com.nctigba.observability.instance.service.ClusterManager; | ||
| 33 | - | ||
| 34 | -/** | ||
| 35 | - * SessionServiceImplTest.java | ||
| 36 | - * | ||
| 37 | - * 2023年7月17日 | ||
| 38 | - */ | ||
| 39 | - | ||
| 40 | -class SessionServiceImplTest { | ||
| 41 | - | ||
| 42 | - private SessionServiceImpl sessionService; | ||
| 43 | - | ||
| 44 | - private SessionHandlerFactory sessionHandlerFactory; | ||
| 45 | - | ||
| 46 | - private ClusterManager opsFacade; | ||
| 47 | - | ||
| 48 | - private SessionHandler sessionHandler; | ||
| 49 | - private Connection connection; | ||
| 50 | - private InstanceNodeInfo instanceNodeInfo; | ||
| 51 | - private ClusterManager.OpsClusterNodeVOSub opsClusterNode; | ||
| 52 | - | ||
| 53 | - | ||
| 54 | - public void setUp() { | ||
| 55 | - instanceNodeInfo = new InstanceNodeInfo(); | ||
| 56 | - instanceNodeInfo.setIp("127.0.0.1"); | ||
| 57 | - instanceNodeInfo.setPort(5432); | ||
| 58 | - instanceNodeInfo.setDbName("testDb"); | ||
| 59 | - instanceNodeInfo.setDbUser("testUser"); | ||
| 60 | - instanceNodeInfo.setDbUserPassword("testPassword"); | ||
| 61 | - instanceNodeInfo.setDbType(DatabaseType.DEFAULT.getDbType()); | ||
| 62 | - opsClusterNode = new ClusterManager.OpsClusterNodeVOSub(); | ||
| 63 | - opsClusterNode.setPublicIp("127.0.0.1"); | ||
| 64 | - opsClusterNode.setDbPort(5432); | ||
| 65 | - opsClusterNode.setDbName("testDb"); | ||
| 66 | - opsClusterNode.setDbUser("testUser"); | ||
| 67 | - opsClusterNode.setDbUserPassword("testPassword"); | ||
| 68 | - when(opsFacade.getOpsNodeById(any())).thenReturn(opsClusterNode); | ||
| 69 | - when(sessionHandlerFactory.getInstance(DatabaseType.DEFAULT.getDbType())).thenReturn(sessionHandler); | ||
| 70 | - when(sessionHandler.getConnection(instanceNodeInfo)).thenReturn(connection); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - private static String getId() { | ||
| 74 | - return "12345"; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - | ||
| 78 | - public void testDetailGeneral() { | ||
| 79 | - JSONObject expectedResult = new JSONObject(); | ||
| 80 | - expectedResult.put("key", "value"); | ||
| 81 | - when(sessionHandler.detailGeneral(connection, getId())).thenReturn(expectedResult); | ||
| 82 | - JSONObject result = sessionService.detailGeneral(getId(), getId()); | ||
| 83 | - assertEquals(expectedResult, result); | ||
| 84 | - verify(sessionHandlerFactory, times(1)).getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 85 | - verify(sessionHandler, times(1)).getConnection(instanceNodeInfo); | ||
| 86 | - verify(sessionHandler, times(1)).detailGeneral(connection, getId()); | ||
| 87 | - verify(sessionHandler, times(1)).close(connection); | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - | ||
| 91 | - public void testDetailStatistic() { | ||
| 92 | - // Arrange | ||
| 93 | - List<DetailStatisticDto> expectedResult = List.of(new DetailStatisticDto()); | ||
| 94 | - when(sessionHandler.detailStatistic(connection, getId())).thenReturn(expectedResult); | ||
| 95 | - // Act | ||
| 96 | - List<DetailStatisticDto> result = sessionService.detailStatistic(getId(), getId()); | ||
| 97 | - // Assert | ||
| 98 | - assertNotNull(result); | ||
| 99 | - assertEquals(expectedResult, result); | ||
| 100 | - verify(sessionHandler, times(1)).detailStatistic(connection, getId()); | ||
| 101 | - verify(sessionHandler, times(1)).close(connection); | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - | ||
| 105 | - public void testDetailWaiting() { | ||
| 106 | - JSONObject object = new JSONObject(); | ||
| 107 | - object.put("key", "value"); | ||
| 108 | - List<JSONObject> expectedResult = List.of(object); | ||
| 109 | - when(sessionHandler.detailWaiting(connection, getId())).thenReturn(expectedResult); | ||
| 110 | - List<JSONObject> result = sessionService.detailWaiting(getId(), getId()); | ||
| 111 | - assertEquals(expectedResult, result); | ||
| 112 | - verify(sessionHandlerFactory, times(1)).getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 113 | - verify(sessionHandler, times(1)).getConnection(instanceNodeInfo); | ||
| 114 | - verify(sessionHandler, times(1)).detailWaiting(connection, getId()); | ||
| 115 | - verify(sessionHandler, times(1)).close(connection); | ||
| 116 | - } | ||
| 117 | - | ||
| 118 | - | ||
| 119 | - public void testDetailBlockTree() { | ||
| 120 | - JSONObject object = new JSONObject(); | ||
| 121 | - object.put("key", "value"); | ||
| 122 | - List<JSONObject> expectedResult = List.of(object); | ||
| 123 | - when(sessionHandler.detailBlockTree(connection, getId())).thenReturn(expectedResult); | ||
| 124 | - List<JSONObject> result = sessionService.detailBlockTree(getId(), getId()); | ||
| 125 | - assertEquals(expectedResult, result); | ||
| 126 | - verify(sessionHandlerFactory, times(1)).getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 127 | - verify(sessionHandler, times(1)).getConnection(instanceNodeInfo); | ||
| 128 | - verify(sessionHandler, times(1)).detailBlockTree(connection, getId()); | ||
| 129 | - verify(sessionHandler, times(1)).close(connection); | ||
| 130 | - } | ||
| 131 | - | ||
| 132 | - | ||
| 133 | - public void testSimpleStatistic() { | ||
| 134 | - JSONObject expectedResult = new JSONObject(); | ||
| 135 | - expectedResult.put("key", "value"); | ||
| 136 | - when(sessionHandler.simpleStatistic(connection)).thenReturn(expectedResult); | ||
| 137 | - JSONObject result = sessionService.simpleStatistic(getId()); | ||
| 138 | - assertEquals(expectedResult, result); | ||
| 139 | - | ||
| 140 | - verify(sessionHandlerFactory, times(1)).getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 141 | - verify(sessionHandler, times(1)).getConnection(instanceNodeInfo); | ||
| 142 | - verify(sessionHandler, times(1)).simpleStatistic(connection); | ||
| 143 | - verify(sessionHandler, times(1)).close(connection); | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | - | ||
| 147 | - public void testLongTxc() { | ||
| 148 | - JSONObject object = new JSONObject(); | ||
| 149 | - object.put("key", "value"); | ||
| 150 | - List<JSONObject> expectedResult = List.of(object); | ||
| 151 | - when(sessionHandler.longTxc(connection)).thenReturn(expectedResult); | ||
| 152 | - List<JSONObject> result = sessionService.longTxc(getId()); | ||
| 153 | - assertEquals(expectedResult, result); | ||
| 154 | - verify(sessionHandlerFactory, times(1)).getInstance(DatabaseType.DEFAULT.getDbType()); | ||
| 155 | - verify(sessionHandler, times(1)).getConnection(instanceNodeInfo); | ||
| 156 | - verify(sessionHandler, times(1)).longTxc(connection); | ||
| 157 | - verify(sessionHandler, times(1)).close(connection); | ||
| 158 | - } | ||
| 159 | - | ||
| 160 | - | ||
| 161 | - public void testBlockAndLongTxc() { | ||
| 162 | - JSONObject object = new JSONObject(); | ||
| 163 | - object.put("key", "value"); | ||
| 164 | - List<JSONObject> longTxc = List.of(object); | ||
| 165 | - List<JSONObject> blockTree = List.of(object); | ||
| 166 | - HashMap<String, List<JSONObject>> expectedResult = new HashMap<>(); | ||
| 167 | - expectedResult.put("blockTree", blockTree); | ||
| 168 | - expectedResult.put("longTxc", longTxc); | ||
| 169 | - | ||
| 170 | - when(sessionHandler.detailBlockTree(connection, null)).thenReturn(blockTree); | ||
| 171 | - when(sessionHandler.longTxc(connection)).thenReturn(longTxc); | ||
| 172 | - | ||
| 173 | - HashMap<String, List<JSONObject>> result = sessionService.blockAndLongTxc(getId()); | ||
| 174 | - assertEquals(expectedResult, result); | ||
| 175 | - } | ||
| 176 | - | ||
| 177 | - | ||
| 178 | - public void testDetail() { | ||
| 179 | - JSONObject object = new JSONObject(); | ||
| 180 | - object.put("key", "value"); | ||
| 181 | - List<JSONObject> blockTree = List.of(object); | ||
| 182 | - List<JSONObject> waiting = List.of(object); | ||
| 183 | - List<DetailStatisticDto> statistic = List.of(new DetailStatisticDto()); | ||
| 184 | - HashMap<String, Object> expectedResult = new HashMap<>(); | ||
| 185 | - expectedResult.put("blockTree", blockTree); | ||
| 186 | - expectedResult.put("general", object); | ||
| 187 | - expectedResult.put("statistic", statistic); | ||
| 188 | - expectedResult.put("waiting", waiting); | ||
| 189 | - | ||
| 190 | - when(sessionHandler.detailWaiting(connection, getId())).thenReturn(waiting); | ||
| 191 | - when(sessionHandler.detailStatistic(connection, getId())).thenReturn(statistic); | ||
| 192 | - when(sessionHandler.detailBlockTree(connection, getId())).thenReturn(blockTree); | ||
| 193 | - when(sessionHandler.detailGeneral(connection, getId())).thenReturn(object); | ||
| 194 | - | ||
| 195 | - Map<String, Object> result = sessionService.detail(getId(), getId()); | ||
| 196 | - assertEquals(expectedResult, result); | ||
| 197 | - } | ||
| 198 | -} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/util/DownloadTest.java+37-0
| @@ -0,0 +1,37 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.util; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertThrows; | ||
| 8 | + | ||
| 9 | +import java.io.File; | ||
| 10 | +import java.io.IOException; | ||
| 11 | + | ||
| 12 | +import org.junit.jupiter.api.Test; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * DownloadTest.java | ||
| 16 | + * | ||
| 17 | + * 2023年7月17日 | ||
| 18 | + */ | ||
| 19 | +class DownloadTest { | ||
| 20 | + private static final String HTTP = "http://www.baidu.com"; | ||
| 21 | + private static final String PATH = "1.tmp"; | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + void test() throws IOException { | ||
| 25 | + var file = new File(PATH); | ||
| 26 | + if (file.exists()) { | ||
| 27 | + file.delete(); | ||
| 28 | + } | ||
| 29 | + Download.download(HTTP, file.getCanonicalPath()); | ||
| 30 | + assertThrows(RuntimeException.class, () -> { | ||
| 31 | + Download.download(HTTP, PATH); | ||
| 32 | + }); | ||
| 33 | + if (file.exists()) { | ||
| 34 | + file.delete(); | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | +} | ||
Aplugins/observability-instance/src/test/java/com/nctigba/observability/instance/util/YamlUtilTest.java+28-0
| @@ -0,0 +1,28 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package com.nctigba.observability.instance.util; | ||
| 6 | + | ||
| 7 | +import java.util.HashMap; | ||
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +import org.junit.jupiter.api.Test; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * YamlUtilTest.java | ||
| 14 | + * | ||
| 15 | + * 2023年7月17日 | ||
| 16 | + */ | ||
| 17 | +class YamlUtilTest { | ||
| 18 | + | ||
| 19 | + void test() { | ||
| 20 | + Map<String, String> map = new HashMap<>(); | ||
| 21 | + map.put("a", null); | ||
| 22 | + map.put("b", "c"); | ||
| 23 | + map.put(null, null); | ||
| 24 | + var str = YamlUtil.dump(map); | ||
| 25 | + YamlUtil.loadAs(str, Map.class); | ||
| 26 | + YamlUtil.dump(null); | ||
| 27 | + } | ||
| 28 | +} | ||
| @@ -0,0 +1,40 @@ | |||
| 1 | +import ogRequest from '@/request' | ||
| 2 | +import { useMonitorStore } from '@/store/monitor' | ||
| 3 | +import dayjs from 'dayjs' | ||
| 4 | +import utc from 'dayjs/plugin/utc' | ||
| 5 | +import timezone from 'dayjs/plugin/timezone' | ||
| 6 | + | ||
| 7 | +export type AspCountData = { | ||
| 8 | + sampleTime: string[] | ||
| 9 | + sessionCount: [] | ||
| 10 | +} | ||
| 11 | +export async function getAspCount(tabId: string): Promise<void | AspCountData> { | ||
| 12 | + dayjs.extend(utc) | ||
| 13 | + dayjs.extend(timezone) | ||
| 14 | + const monitorStore = useMonitorStore(tabId) | ||
| 15 | + const { instanceId, culRangeTimeAndStep } = monitorStore | ||
| 16 | + let timeRange = culRangeTimeAndStep() | ||
| 17 | + return ogRequest.get('/instanceMonitoring/api/v1/asp/count', { | ||
| 18 | + id: instanceId, | ||
| 19 | + startTime: dayjs(new Date(timeRange[0] * 1000)) | ||
| 20 | + .utc() | ||
| 21 | + .format(), | ||
| 22 | + finishTime: dayjs(new Date(timeRange[1] * 1000)) | ||
| 23 | + .utc() | ||
| 24 | + .format(), | ||
| 25 | + }) | ||
| 26 | +} | ||
| 27 | +export async function getAspAnalysis(tabId: string): Promise<void | any[]> { | ||
| 28 | + const monitorStore = useMonitorStore(tabId) | ||
| 29 | + const { instanceId, culRangeTimeAndStep } = monitorStore | ||
| 30 | + let timeRange = culRangeTimeAndStep() | ||
| 31 | + return ogRequest.get('/instanceMonitoring/api/v1/asp/analysis', { | ||
| 32 | + id: instanceId, | ||
| 33 | + startTime: dayjs(new Date(timeRange[0] * 1000)) | ||
| 34 | + .utc() | ||
| 35 | + .format(), | ||
| 36 | + finishTime: dayjs(new Date(timeRange[1] * 1000)) | ||
| 37 | + .utc() | ||
| 38 | + .format(), | ||
| 39 | + }) | ||
| 40 | +} | ||
| @@ -0,0 +1,61 @@ | |||
| 1 | +import ogRequest from '@/request' | ||
| 2 | + | ||
| 3 | +export type ClusterListItem = { | ||
| 4 | + clusterId: string | ||
| 5 | + versionNum: string | ||
| 6 | + databaseUsername: string | ||
| 7 | + port: string | ||
| 8 | + clusterState: string | ||
| 9 | + envPath: string | ||
| 10 | + arch: string | ||
| 11 | + desc: string | ||
| 12 | + color: string | ||
| 13 | + nodeId: string | ||
| 14 | +} | ||
| 15 | +export async function getAllClusters(): Promise<void | ClusterListItem[]> { | ||
| 16 | + return ogRequest.get('/instanceMonitoring/api/v1/clusters/list') | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +export type ClusterStateItem = { | ||
| 20 | + clusterId: string | ||
| 21 | + versionNum: string | ||
| 22 | + databaseUsername: string | ||
| 23 | + port: string | ||
| 24 | + clusterState: string | ||
| 25 | + envPath: string | ||
| 26 | + desc: string | ||
| 27 | + primaryNodeId: string | ||
| 28 | +} | ||
| 29 | +export async function getAllClustersStates(): Promise<void | ClusterStateItem[]> { | ||
| 30 | + return ogRequest.get('/instanceMonitoring/api/v1/clusters/allClusterState') | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +export type NodeStateItem = { | ||
| 34 | + clusterId: string | ||
| 35 | + sync: string | ||
| 36 | + nodeName: string | ||
| 37 | + syncState: any | ||
| 38 | +} | ||
| 39 | +export async function getAllNodes(): Promise<void | NodeStateItem[]> { | ||
| 40 | + return ogRequest.get('/instanceMonitoring/api/v1/clusters/nodes') | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +export type ClusterDetail = {} | ||
| 44 | +export async function getClusterDetails(clusterId: string): Promise<void | ClusterDetail[]> { | ||
| 45 | + let start = 0 | ||
| 46 | + let end = 0 | ||
| 47 | + let min = 0 | ||
| 48 | + let now = new Date() | ||
| 49 | + min = 1 * 60 | ||
| 50 | + start = Number.parseInt(`${(now.getTime() - 1000 * min * 60) / 1000}`) | ||
| 51 | + end = Number.parseInt(`${now.getTime() / 1000}`) | ||
| 52 | + let step = Math.max(14, Number.parseInt(`${Math.round((end - start) / 260)}`)) | ||
| 53 | + return ogRequest.get( | ||
| 54 | + '/instanceMonitoring/api/v1/clusters/' + clusterId + '/metrics?start=' + start + '&end=' + end + '&step=' + step | ||
| 55 | + ) | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +export type ClusterNode = {} | ||
| 59 | +export async function getClusterNodes(clusterId: string): Promise<void | ClusterNode[]> { | ||
| 60 | + return ogRequest.get('/instanceMonitoring/api/v1/clusters/' + clusterId + '/nodes') | ||
| 61 | +} | ||
| @@ -7,352 +7,398 @@ import ogRequest from '@/request' | |||
| 7 | import { useMonitorStore } from '@/store/monitor' | 7 | import { useMonitorStore } from '@/store/monitor' |
| 8 | 8 | ||
| 9 | export type OpenGaussNode = { | 9 | export type OpenGaussNode = { |
| 10 | - dbName: string | 10 | + dbName: string |
| 11 | - dbType: string | 11 | + dbType: string |
| 12 | - dbUser: string | 12 | + dbUser: string |
| 13 | - dbUserPassword: string | 13 | + dbUserPassword: string |
| 14 | - id: string | 14 | + id: string |
| 15 | - instanceId: string | 15 | + instanceId: string |
| 16 | - ip: string | 16 | + ip: string |
| 17 | - port: number | 17 | + port: number |
| 18 | - serverId: string | 18 | + serverId: string |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | export type ServerInfo = { | 21 | export type ServerInfo = { |
| 22 | - id: string | 22 | + id: string |
| 23 | - ip: string | 23 | + ip: string |
| 24 | - os: string | 24 | + os: string |
| 25 | - port: number | 25 | + port: number |
| 26 | - userName: string | 26 | + userName: string |
| 27 | - userPassword: string | 27 | + userPassword: string |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | export type OpenGaussInstance = { | 30 | export type OpenGaussInstance = { |
| 31 | - dbVersion: string | 31 | + dbVersion: string |
| 32 | - id: string | 32 | + id: string |
| 33 | - name: string | 33 | + name: string |
| 34 | - nodeInfo: Partial<OpenGaussNode>[] | 34 | + nodeInfo: Partial<OpenGaussNode>[] |
| 35 | - remark: string | 35 | + remark: string |
| 36 | - serverInfoReq: Partial<ServerInfo> | 36 | + serverInfoReq: Partial<ServerInfo> |
| 37 | - serverInfoResp?: Partial<ServerInfo> | 37 | + serverInfoResp?: Partial<ServerInfo> |
| 38 | - type: string | 38 | + type: string |
| 39 | - vip: string | 39 | + vip: string |
| 40 | - port: number | 40 | + port: number |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | export async function getList(keyword?: string, page?: number, limit?: number): Promise<Partial<OpenGaussInstance>[]> { | 43 | export async function getList(keyword?: string, page?: number, limit?: number): Promise<Partial<OpenGaussInstance>[]> { |
| 44 | - let resp = await axios.post('/sql-diagnosis/api/v1/instance/list', { keyword, page, limit }) | 44 | + let resp = await axios.post('/sql-diagnosis/api/v1/instance/list', { keyword, page, limit }) |
| 45 | - return resp.data.data | 45 | + return resp.data.data |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | export async function getDetail(id: string): Promise<Partial<OpenGaussInstance>> { | 48 | export async function getDetail(id: string): Promise<Partial<OpenGaussInstance>> { |
| 49 | - let resp = await axios.get(`/sql-diagnosis/api/v1/instance/detail/${id}`) | 49 | + let resp = await axios.get(`/sql-diagnosis/api/v1/instance/detail/${id}`) |
| 50 | - return resp.data.data | 50 | + return resp.data.data |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | export async function deleteInstance(id: string): Promise<boolean> { | 53 | export async function deleteInstance(id: string): Promise<boolean> { |
| 54 | - let resp = await axios.post('/sql-diagnosis/api/v1/instance/delete', [id]) | 54 | + let resp = await axios.post('/sql-diagnosis/api/v1/instance/delete', [id]) |
| 55 | - return resp.data.data | 55 | + return resp.data.data |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | export async function addInstance(entry: Partial<OpenGaussInstance>): Promise<Partial<OpenGaussInstance>> { | 58 | export async function addInstance(entry: Partial<OpenGaussInstance>): Promise<Partial<OpenGaussInstance>> { |
| 59 | - let resp = await axios.post('/sql-diagnosis/api/v1/instance/add', entry) | 59 | + let resp = await axios.post('/sql-diagnosis/api/v1/instance/add', entry) |
| 60 | - return resp.data.data | 60 | + return resp.data.data |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | export async function updateInstance(entry: Partial<OpenGaussInstance>): Promise<Partial<OpenGaussInstance>> { | 63 | export async function updateInstance(entry: Partial<OpenGaussInstance>): Promise<Partial<OpenGaussInstance>> { |
| 64 | - let resp = await axios.post(`/sql-diagnosis/api/v1/instance/update/${entry.id}`, entry) | 64 | + let resp = await axios.post(`/sql-diagnosis/api/v1/instance/update/${entry.id}`, entry) |
| 65 | - return resp.data.data | 65 | + return resp.data.data |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | export async function testConnection(dbNode: Partial<OpenGaussNode>): Promise<boolean> { | 68 | export async function testConnection(dbNode: Partial<OpenGaussNode>): Promise<boolean> { |
| 69 | - let resp = await axios.post('/sql-diagnosis/api/v1/instance/connect', dbNode) | 69 | + let resp = await axios.post('/sql-diagnosis/api/v1/instance/connect', dbNode) |
| 70 | - return resp.data.code === '200' || resp.data.code === 200 | 70 | + return resp.data.code === '200' || resp.data.code === 200 |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | export async function getIndexMetrics(tabId: string): Promise<void | { | 73 | export async function getIndexMetrics(tabId: string): Promise<void | { |
| 74 | - max_conn: number | 74 | + max_conn: number |
| 75 | - active: number | 75 | + active: number |
| 76 | - waiting: number | 76 | + waiting: number |
| 77 | - max_runtime: number | 77 | + max_runtime: number |
| 78 | - CPU: number[] | 78 | + CPU: number[] |
| 79 | - IO: number[] | 79 | + IO: number[] |
| 80 | - MEMORY: number[] | 80 | + MEMORY: number[] |
| 81 | - NETWORK_IN_TOTAL: number[] | 81 | + NETWORK_IN_TOTAL: number[] |
| 82 | - NETWORK_OUT_TOTAL: number[] | 82 | + NETWORK_OUT_TOTAL: number[] |
| 83 | - SWAP: number[] | 83 | + SWAP: number[] |
| 84 | - DB_THREAD_POOL: number[] | 84 | + DB_THREAD_POOL: number[] |
| 85 | - DB_ACTIVE_SESSION: Record<string, number[]> | 85 | + DB_ACTIVE_SESSION: Record<string, number[]> |
| 86 | - time: string[] | 86 | + time: string[] |
| 87 | }> { | 87 | }> { |
| 88 | - const monitorStore = useMonitorStore(tabId) | 88 | + const monitorStore = useMonitorStore(tabId) |
| 89 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 89 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 90 | - let timeRange = culRangeTimeAndStep() | 90 | + let timeRange = culRangeTimeAndStep() |
| 91 | - return ogRequest.get('/instanceMonitoring/api/v1/mainMetrics', { | 91 | + return ogRequest.get('/instanceMonitoring/api/v1/mainMetrics', { |
| 92 | - id: instanceId, | 92 | + id: instanceId, |
| 93 | - start: timeRange[0], | 93 | + start: timeRange[0], |
| 94 | - end: timeRange[1], | 94 | + end: timeRange[1], |
| 95 | - step: timeRange[2], | 95 | + step: timeRange[2], |
| 96 | - type: 'LINE', | 96 | + type: 'LINE', |
| 97 | - }) | 97 | + }) |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | export async function getCPUMetrics(tabId: string): Promise<void | { | 100 | export async function getCPUMetrics(tabId: string): Promise<void | { |
| 101 | - CPU_IOWAIT: number[] | 101 | + CPU_IOWAIT: number[] |
| 102 | - CPU_SYSTEM: number[] | 102 | + CPU_SYSTEM: number[] |
| 103 | - CPU_TOTAL: number[] | 103 | + CPU_TOTAL: number[] |
| 104 | - CPU_TOTAL_5M_LOAD: number[] | 104 | + CPU_TOTAL_5M_LOAD: number[] |
| 105 | - CPU_TOTAL_AVERAGE_UTILIZATION: number[] | 105 | + CPU_TOTAL_AVERAGE_UTILIZATION: number[] |
| 106 | - CPU_TOTAL_CORE_NUM: number[] | 106 | + CPU_TOTAL_CORE_NUM: number[] |
| 107 | - CPU_USER: number[] | 107 | + CPU_USER: number[] |
| 108 | - CPU_DB: number[] | 108 | + CPU_DB: number[] |
| 109 | - time: string[] | 109 | + CPU_NICE: number[] |
| 110 | - name: string | 110 | + CPU_IRQ: number[] |
| 111 | + CPU_SOFTIRQ: number[] | ||
| 112 | + CPU_STEAL: number[] | ||
| 113 | + CPU_IDLE: number[] | ||
| 114 | + time: string[] | ||
| 115 | + name: string | ||
| 111 | }> { | 116 | }> { |
| 112 | - const monitorStore = useMonitorStore(tabId) | 117 | + const monitorStore = useMonitorStore(tabId) |
| 113 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 118 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 114 | - let timeRange = culRangeTimeAndStep() | 119 | + let timeRange = culRangeTimeAndStep() |
| 115 | - return ogRequest.get('/instanceMonitoring/api/v1/cpu', { | 120 | + return ogRequest.get('/instanceMonitoring/api/v1/cpu', { |
| 116 | - id: instanceId, | 121 | + id: instanceId, |
| 117 | - start: timeRange[0], | 122 | + start: timeRange[0], |
| 118 | - end: timeRange[1], | 123 | + end: timeRange[1], |
| 119 | - step: timeRange[2], | 124 | + step: timeRange[2], |
| 120 | - type: 'LINE', | 125 | + type: 'LINE', |
| 121 | - }) | 126 | + }) |
| 122 | } | 127 | } |
| 123 | 128 | ||
| 124 | export async function getMemoryMetrics(tabId: string): Promise<void | { | 129 | export async function getMemoryMetrics(tabId: string): Promise<void | { |
| 125 | - GLOBAL_CONFIG_SETTINGS: any | 130 | + GLOBAL_CONFIG_SETTINGS: any |
| 126 | - GS_TOTAL_MEMORY_DETAIL: any | 131 | + GS_TOTAL_MEMORY_DETAIL: any |
| 127 | - MEMORY_USED: number[] | 132 | + MEMORY_USED: number[] |
| 128 | - MEMORY_DB_USED: number[] | 133 | + MEMORY_DB_USED: number[] |
| 129 | - MEMORY_SWAP: number[] | 134 | + MEMORY_SWAP: number[] |
| 130 | - MEM_CACHE: number | 135 | + MEM_CACHE: number |
| 131 | - MEM_FREE: number | 136 | + MEM_FREE: number |
| 132 | - MEM_TOTAL: number | 137 | + MEM_TOTAL: number |
| 133 | - MEM_USED: number | 138 | + MEM_USED: number |
| 134 | - SWAP_FREE: number | 139 | + MEMORY_DB_USED_CURR: number |
| 135 | - SWAP_TOTAL: number | 140 | + SWAP_FREE: number |
| 136 | - SWAP_USED: number | 141 | + SWAP_TOTAL: number |
| 137 | - memoryConfig: any[] | 142 | + SWAP_USED: number |
| 138 | - memoryNodeDetail: any[] | 143 | + memoryConfig: any[] |
| 139 | - time: string[] | 144 | + memoryNodeDetail: any[] |
| 145 | + time: string[] | ||
| 140 | }> { | 146 | }> { |
| 141 | - const monitorStore = useMonitorStore(tabId) | 147 | + const monitorStore = useMonitorStore(tabId) |
| 142 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 148 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 143 | - let timeRange = culRangeTimeAndStep() | 149 | + let timeRange = culRangeTimeAndStep() |
| 144 | - return ogRequest.get('/instanceMonitoring/api/v1/memory', { | 150 | + return ogRequest.get('/instanceMonitoring/api/v1/memory', { |
| 145 | - id: instanceId, | 151 | + id: instanceId, |
| 146 | - start: timeRange[0], | 152 | + start: timeRange[0], |
| 147 | - end: timeRange[1], | 153 | + end: timeRange[1], |
| 148 | - step: timeRange[2], | 154 | + step: timeRange[2], |
| 149 | - type: 'LINE', | 155 | + type: 'LINE', |
| 150 | - }) | 156 | + }) |
| 151 | } | 157 | } |
| 152 | 158 | ||
| 153 | export async function getNetworkMetrics(tabId: string): Promise<void | { | 159 | export async function getNetworkMetrics(tabId: string): Promise<void | { |
| 154 | - NETWORK_IN: Record<string, number[]> | 160 | + NETWORK_IN: Record<string, number[]> |
| 155 | - NETWORK_OUT: Record<string, number[]> | 161 | + NETWORK_OUT: Record<string, number[]> |
| 156 | - NETWORK_LOST_PACKAGE: Record<string, number[]> | 162 | + NETWORK_LOST_PACKAGE: Record<string, number[]> |
| 157 | - NETWORK_TCP_ALLOC: number[] | 163 | + NETWORK_TCP_ALLOC: number[] |
| 158 | - NETWORK_CURRESTAB: number[] | 164 | + NETWORK_CURRESTAB: number[] |
| 159 | - NETWORK_TCP_INSEGS: number[] | 165 | + NETWORK_TCP_INSEGS: number[] |
| 160 | - NETWORK_TCP_OUTSEGS: number[] | 166 | + NETWORK_TCP_OUTSEGS: number[] |
| 161 | - NETWORK_TCP_SOCKET: Record<string, number[]> | 167 | + NETWORK_TCP_SOCKET: Record<string, number[]> |
| 162 | - NETWORK_UDP_SOCKET: number[] | 168 | + NETWORK_UDP_SOCKET: number[] |
| 163 | - table: any[] | 169 | + table: any[] |
| 164 | - time: string[] | 170 | + time: string[] |
| 165 | - name: string | 171 | + name: string |
| 166 | }> { | 172 | }> { |
| 167 | - const monitorStore = useMonitorStore(tabId) | 173 | + const monitorStore = useMonitorStore(tabId) |
| 168 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 174 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 169 | - let timeRange = culRangeTimeAndStep() | 175 | + let timeRange = culRangeTimeAndStep() |
| 170 | - return ogRequest.get('/instanceMonitoring/api/v1/network', { | 176 | + return ogRequest.get('/instanceMonitoring/api/v1/network', { |
| 171 | - id: instanceId, | 177 | + id: instanceId, |
| 172 | - start: timeRange[0], | 178 | + start: timeRange[0], |
| 173 | - end: timeRange[1], | 179 | + end: timeRange[1], |
| 174 | - step: timeRange[2], | 180 | + step: timeRange[2], |
| 175 | - type: 'LINE', | 181 | + type: 'LINE', |
| 176 | - }) | 182 | + }) |
| 177 | } | 183 | } |
| 178 | 184 | ||
| 179 | export async function getIOMetrics(tabId: string): Promise<void | { | 185 | export async function getIOMetrics(tabId: string): Promise<void | { |
| 180 | - table: any[] | 186 | + table: any[] |
| 181 | - IOPS_R: Record<string, number[]> | 187 | + IOPS_R: Record<string, number[]> |
| 182 | - IOPS_W: Record<string, number[]> | 188 | + IOPS_W: Record<string, number[]> |
| 183 | - IO_AVG_REPONSE_TIME_READ: Record<string, number[]> | 189 | + IO_AVG_REPONSE_TIME_READ: Record<string, number[]> |
| 184 | - IO_AVG_REPONSE_TIME_RW: Record<string, number[]> | 190 | + IO_AVG_REPONSE_TIME_RW: Record<string, number[]> |
| 185 | - IO_AVG_REPONSE_TIME_WRITE: Record<string, number[]> | 191 | + IO_AVG_REPONSE_TIME_WRITE: Record<string, number[]> |
| 186 | - IO_DISK_READ_BYTES_PER_SECOND: Record<string, number[]> | 192 | + IO_DISK_READ_BYTES_PER_SECOND: Record<string, number[]> |
| 187 | - IO_DISK_WRITE_BYTES_PER_SECOND: Record<string, number[]> | 193 | + IO_DISK_WRITE_BYTES_PER_SECOND: Record<string, number[]> |
| 188 | - IO_QUEUE_LENGTH: Record<string, number[]> | 194 | + IO_QUEUE_LENGTH: Record<string, number[]> |
| 189 | - IO_UTIL: Record<string, number[]> | 195 | + IO_UTIL: Record<string, number[]> |
| 190 | - time: string[] | 196 | + time: string[] |
| 191 | }> { | 197 | }> { |
| 192 | - const monitorStore = useMonitorStore(tabId) | 198 | + const monitorStore = useMonitorStore(tabId) |
| 193 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 199 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 194 | - let timeRange = culRangeTimeAndStep() | 200 | + let timeRange = culRangeTimeAndStep() |
| 195 | - return ogRequest.get('/instanceMonitoring/api/v1/io', { | 201 | + return ogRequest.get('/instanceMonitoring/api/v1/io', { |
| 196 | - id: instanceId, | 202 | + id: instanceId, |
| 197 | - start: timeRange[0], | 203 | + start: timeRange[0], |
| 198 | - end: timeRange[1], | 204 | + end: timeRange[1], |
| 199 | - step: timeRange[2], | 205 | + step: timeRange[2], |
| 200 | - type: 'LINE', | 206 | + type: 'LINE', |
| 201 | - }) | 207 | + }) |
| 202 | } | 208 | } |
| 203 | 209 | ||
| 204 | export type TopSQLNow = { | 210 | export type TopSQLNow = { |
| 205 | - id: string | 211 | + id: string |
| 206 | - ip: string | 212 | + ip: string |
| 207 | - os: string | 213 | + os: string |
| 208 | - port: number | 214 | + port: number |
| 209 | - userName: string | 215 | + userName: string |
| 210 | - userPassword: string | 216 | + userPassword: string |
| 217 | + duration: string | ||
| 211 | } | 218 | } |
| 212 | export type BlockTable = { | 219 | export type BlockTable = { |
| 213 | - depth: string | 220 | + depth: string |
| 214 | - application_name: string | 221 | + application_name: string |
| 215 | - tree_id: string | 222 | + tree_id: string |
| 216 | - backend_start: string | 223 | + backend_start: string |
| 217 | - hasChildren?: boolean | 224 | + hasChildren?: boolean |
| 218 | - children?: undefined | BlockTable[] | 225 | + children?: undefined | BlockTable[] |
| 219 | - client_addr: string | 226 | + client_addr: string |
| 220 | - datname: string | 227 | + datname: string |
| 221 | - pathid: string | 228 | + pathid: string |
| 222 | - id: string | 229 | + id: string |
| 223 | - usename: string | 230 | + usename: string |
| 224 | - state: string | 231 | + state: string |
| 225 | - parentid: string | 232 | + parentid: string |
| 226 | } | 233 | } |
| 227 | export type TransTable = { | 234 | export type TransTable = { |
| 228 | - application_name: string | 235 | + application_name: string |
| 229 | - client_addr: string | 236 | + client_addr: string |
| 230 | - datname: string | 237 | + datname: string |
| 231 | - pid: string | 238 | + pid: string |
| 232 | - query: string | 239 | + query: string |
| 233 | - query_duration: string | 240 | + query_duration: string |
| 234 | - query_start: string | 241 | + query_start: string |
| 235 | - sessionid: string | 242 | + sessionid: string |
| 236 | - state: string | 243 | + state: string |
| 237 | - usename: string | 244 | + usename: string |
| 238 | - xact_duration: string | 245 | + xact_duration: string |
| 239 | - xact_start: string | 246 | + xact_start: string |
| 247 | +} | ||
| 248 | +export type WaitEvent = { | ||
| 249 | + block_sessionid: string | ||
| 250 | + db_name: string | ||
| 251 | + lockmode: string | ||
| 252 | + locktag: string | ||
| 253 | + node_name: string | ||
| 254 | + query_id: string | ||
| 255 | + sessionid: string | ||
| 256 | + tag: string | ||
| 257 | + thread_name: string | ||
| 258 | + tid: string | ||
| 259 | + wait_event: string | ||
| 260 | + wait_status: string | ||
| 240 | } | 261 | } |
| 241 | export type MainNowTable = { | 262 | export type MainNowTable = { |
| 242 | - blockTree: BlockTable[] | 263 | + blockTree: BlockTable[] |
| 243 | - longTxc: TransTable[] | 264 | + longTxc: TransTable[] |
| 244 | - topSQLNow: TopSQLNow[] | 265 | + topSQLNow: TopSQLNow[] |
| 266 | + waitEvents: WaitEvent[] | ||
| 245 | } | 267 | } |
| 246 | export async function getTOPSQLNow(tabId: string): Promise<void | MainNowTable> { | 268 | export async function getTOPSQLNow(tabId: string): Promise<void | MainNowTable> { |
| 247 | - const monitorStore = useMonitorStore(tabId) | 269 | + const monitorStore = useMonitorStore(tabId) |
| 248 | - const { instanceId } = monitorStore | 270 | + const { instanceId } = monitorStore |
| 249 | - return ogRequest.get('/instanceMonitoring/api/v1/topSQLNow', { | 271 | + return ogRequest.get('/instanceMonitoring/api/v1/topSQLNow', { |
| 250 | - id: instanceId, | 272 | + id: instanceId, |
| 251 | - }) | 273 | + }) |
| 252 | } | 274 | } |
| 253 | 275 | ||
| 254 | export type TopCPUProcessNow = { | 276 | export type TopCPUProcessNow = { |
| 255 | - '%CPU': string | 277 | + '%CPU': string |
| 256 | - '%MEM': string | 278 | + '%MEM': string |
| 257 | - COMMAND: string | 279 | + COMMAND: string |
| 258 | - NI: number | 280 | + publicIp: string |
| 259 | - PID: string | 281 | + NI: number |
| 260 | - PR: string | 282 | + PID: string |
| 261 | - RES: string | 283 | + PR: string |
| 262 | - S: string | 284 | + RES: string |
| 263 | - SHR: string | 285 | + S: string |
| 264 | - 'TIME+': string | 286 | + SHR: string |
| 265 | - USER: string | 287 | + 'TIME+': string |
| 266 | - VIRT: string | 288 | + USER: string |
| 289 | + VIRT: string | ||
| 290 | + port: string | ||
| 267 | } | 291 | } |
| 268 | export async function getTOPCPUProcessNow(tabId: string): Promise<void | TopCPUProcessNow[][]> { | 292 | export async function getTOPCPUProcessNow(tabId: string): Promise<void | TopCPUProcessNow[][]> { |
| 269 | - const monitorStore = useMonitorStore(tabId) | 293 | + const monitorStore = useMonitorStore(tabId) |
| 270 | - const { instanceId } = monitorStore | 294 | + const { instanceId } = monitorStore |
| 271 | - return ogRequest.get('/instanceMonitoring/api/v1/topOSProcessAndDBThread', { | 295 | + return ogRequest.get('/instanceMonitoring/api/v1/topOSProcessAndDBThread', { |
| 272 | - id: instanceId, | 296 | + id: instanceId, |
| 273 | - }) | 297 | + }) |
| 274 | } | 298 | } |
| 275 | 299 | ||
| 276 | export type TopMemoryProcessNow = { | 300 | export type TopMemoryProcessNow = { |
| 277 | - '%CPU': string | 301 | + '%CPU': string |
| 278 | - '%MEM': string | 302 | + '%MEM': string |
| 279 | - COMMAND: string | 303 | + COMMAND: string |
| 280 | - NI: number | 304 | + publicIp: string |
| 281 | - PID: string | 305 | + NI: number |
| 282 | - PR: string | 306 | + PID: string |
| 283 | - RES: string | 307 | + PR: string |
| 284 | - S: string | 308 | + RES: string |
| 285 | - SHR: string | 309 | + S: string |
| 286 | - 'TIME+': string | 310 | + SHR: string |
| 287 | - USER: string | 311 | + 'TIME+': string |
| 288 | - VIRT: string | 312 | + USER: string |
| 313 | + VIRT: string | ||
| 314 | + port: string | ||
| 289 | } | 315 | } |
| 290 | -export async function getTOPMemoryProcessNow(tabId: string): Promise<void | TopCPUProcessNow[][]> { | 316 | +export async function getTOPMemoryProcessNow(tabId: string): Promise<void | TopMemoryProcessNow[][]> { |
| 291 | - const monitorStore = useMonitorStore(tabId) | 317 | + const monitorStore = useMonitorStore(tabId) |
| 292 | - const { instanceId } = monitorStore | 318 | + const { instanceId } = monitorStore |
| 293 | - return ogRequest.get('/instanceMonitoring/api/v1/topOSProcessAndDBThread', { | 319 | + return ogRequest.get('/instanceMonitoring/api/v1/topOSProcessAndDBThread', { |
| 294 | - id: instanceId, | 320 | + id: instanceId, |
| 295 | - sort: '%MEM', | 321 | + sort: '%MEM', |
| 296 | - }) | 322 | + }) |
| 297 | } | 323 | } |
| 298 | 324 | ||
| 299 | export async function getInstanceMetrics(tabId: string): Promise<void | { | 325 | export async function getInstanceMetrics(tabId: string): Promise<void | { |
| 300 | - INSTANCE_DB_CONNECTION_ACTIVE: number[] | 326 | + INSTANCE_DB_CONNECTION_ACTIVE: number[] |
| 301 | - INSTANCE_DB_CONNECTION_CURR: number[] | 327 | + INSTANCE_DB_CONNECTION_CURR: number[] |
| 302 | - INSTANCE_DB_CONNECTION_IDLE: number[] | 328 | + INSTANCE_DB_CONNECTION_IDLE: number[] |
| 303 | - INSTANCE_DB_CONNECTION_TOTAL: number[] | 329 | + INSTANCE_DB_CONNECTION_TOTAL: number[] |
| 304 | - INSTANCE_DB_SLOWSQL: number[] | 330 | + INSTANCE_DB_SLOWSQL: number[] |
| 305 | - INSTANCE_QPS: number[] | 331 | + INSTANCE_QPS: number[] |
| 306 | - INSTANCE_TPS_COMMIT: number[] | 332 | + INSTANCE_TPS_COMMIT: number[] |
| 307 | - INSTANCE_TPS_CR: number[] | 333 | + INSTANCE_TPS_CR: number[] |
| 308 | - INSTANCE_TPS_ROLLBACK: number[] | 334 | + INSTANCE_TPS_ROLLBACK: number[] |
| 309 | - time: string[] | 335 | + time: string[] |
| 310 | }> { | 336 | }> { |
| 311 | - const monitorStore = useMonitorStore(tabId) | 337 | + const monitorStore = useMonitorStore(tabId) |
| 312 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 338 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 313 | - let timeRange = culRangeTimeAndStep() | 339 | + let timeRange = culRangeTimeAndStep() |
| 314 | - return ogRequest.get('/instanceMonitoring/api/v1/instance', { | 340 | + return ogRequest.get('/instanceMonitoring/api/v1/instance', { |
| 315 | - id: instanceId, | 341 | + id: instanceId, |
| 316 | - start: timeRange[0], | 342 | + start: timeRange[0], |
| 317 | - end: timeRange[1], | 343 | + end: timeRange[1], |
| 318 | - step: timeRange[2], | 344 | + step: timeRange[2], |
| 319 | - type: 'LINE', | 345 | + type: 'LINE', |
| 320 | - }) | 346 | + }) |
| 321 | } | 347 | } |
| 322 | 348 | ||
| 323 | export async function getSessionMetrics(tabId: string): Promise<void | { | 349 | export async function getSessionMetrics(tabId: string): Promise<void | { |
| 324 | - max_conn: number | 350 | + max_conn: number |
| 325 | - active: number | 351 | + active: number |
| 326 | - waiting: number | 352 | + waiting: number |
| 327 | - max_runtime: number | 353 | + max_runtime: number |
| 328 | - SESSION_ACTIVE_CONNECTION: number[] | 354 | + SESSION_ACTIVE_CONNECTION: number[] |
| 329 | - SESSION_IDLE_CONNECTION: number[] | 355 | + SESSION_IDLE_CONNECTION: number[] |
| 330 | - SESSION_MAX_CONNECTION: number[] | 356 | + SESSION_MAX_CONNECTION: number[] |
| 331 | - SESSION_WAITING_CONNECTION: number[] | 357 | + SESSION_WAITING_CONNECTION: number[] |
| 332 | - gauss_wait_events_value: any[] | 358 | + gauss_wait_events_value: any[] |
| 333 | - time: string[] | 359 | + time: string[] |
| 334 | - name: string | 360 | + name: string |
| 335 | }> { | 361 | }> { |
| 336 | - const monitorStore = useMonitorStore(tabId) | 362 | + const monitorStore = useMonitorStore(tabId) |
| 337 | - const { instanceId, culRangeTimeAndStep } = monitorStore | 363 | + const { instanceId, culRangeTimeAndStep } = monitorStore |
| 338 | - let timeRange = culRangeTimeAndStep() | 364 | + let timeRange = culRangeTimeAndStep() |
| 339 | - return ogRequest.get('/instanceMonitoring/api/v1/session/sessionStatistic', { | 365 | + return ogRequest.get('/instanceMonitoring/api/v1/session/sessionStatistic', { |
| 340 | - id: instanceId, | 366 | + id: instanceId, |
| 341 | - start: timeRange[0], | 367 | + start: timeRange[0], |
| 342 | - end: timeRange[1], | 368 | + end: timeRange[1], |
| 343 | - step: timeRange[2], | 369 | + step: timeRange[2], |
| 344 | - type: 'LINE', | 370 | + type: 'LINE', |
| 345 | - }) | 371 | + }) |
| 346 | } | 372 | } |
| 347 | 373 | ||
| 348 | export type SessionTables = { | 374 | export type SessionTables = { |
| 349 | - blockTree: BlockTable[] | 375 | + blockTree: BlockTable[] |
| 350 | - longTxc: TransTable[] | 376 | + longTxc: TransTable[] |
| 351 | } | 377 | } |
| 352 | export async function getSessionTables(tabId: string): Promise<void | SessionTables> { | 378 | export async function getSessionTables(tabId: string): Promise<void | SessionTables> { |
| 353 | - const monitorStore = useMonitorStore(tabId) | 379 | + const monitorStore = useMonitorStore(tabId) |
| 354 | - const { instanceId } = monitorStore | 380 | + const { instanceId } = monitorStore |
| 355 | - return ogRequest.get('/instanceMonitoring/api/v1/session/blockAndLongTxc', { | 381 | + return ogRequest.get('/instanceMonitoring/api/v1/session/blockAndLongTxc', { |
| 356 | - id: instanceId, | 382 | + id: instanceId, |
| 357 | - }) | 383 | + }) |
| 384 | +} | ||
| 385 | + | ||
| 386 | +export type NodeInfo = { | ||
| 387 | + dbDataPath: string | ||
| 388 | + CPUmodel: string | ||
| 389 | + CPUmanufacturer: string | ||
| 390 | + osVersion: string | ||
| 391 | + dbLogPath: string | ||
| 392 | + CPUcores: string | ||
| 393 | + TotalMemory: string | ||
| 394 | + time: string | ||
| 395 | + version: string | ||
| 396 | + archiveMode: string | ||
| 397 | +} | ||
| 398 | +export async function getNodeInfo(tabId: string): Promise<void | NodeInfo> { | ||
| 399 | + const monitorStore = useMonitorStore(tabId) | ||
| 400 | + const { instanceId } = monitorStore | ||
| 401 | + return ogRequest.get('/instanceMonitoring/api/v1/nodeInfo', { | ||
| 402 | + id: instanceId, | ||
| 403 | + }) | ||
| 358 | } | 404 | } |
| @@ -1,7 +1,3 @@ | |||
| 1 | -/// | ||
| 2 | -/// Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | -/// | ||
| 4 | - | ||
| 5 | import { useRequest } from 'vue-request' | 1 | import { useRequest } from 'vue-request' |
| 6 | import ogRequest from '@/request' | 2 | import ogRequest from '@/request' |
| 7 | import { useMonitorStore } from '@/store/monitor' | 3 | import { useMonitorStore } from '@/store/monitor' |
| @@ -11,70 +7,70 @@ import { tabKeys } from '@/pages/dashboardV2/common' | |||
| 11 | let tabIdTemp: string = '' | 7 | let tabIdTemp: string = '' |
| 12 | 8 | ||
| 13 | const { data, run: getDatabaseMetrics } = useRequest<Record< | 9 | const { data, run: getDatabaseMetrics } = useRequest<Record< |
| 14 | - string, | 10 | + string, |
| 15 | - { data: string[]; time: string[]; name: string }[] | 11 | + { data: string[]; time: string[]; name: string }[] |
| 16 | > | void>( | 12 | > | void>( |
| 17 | - (tabId: string) => { | 13 | + (tabId: string, dbId?: string) => { |
| 18 | - tabIdTemp = tabId | 14 | + tabIdTemp = tabId |
| 19 | - const monitorStore = useMonitorStore(tabIdTemp) | 15 | + const monitorStore = useMonitorStore(tabIdTemp) |
| 20 | - const { rangeTime, time, instanceId, fixedRangeTime, tab } = monitorStore | 16 | + const { rangeTime, time, instanceId, fixedRangeTime, tab } = monitorStore |
| 21 | - let start = 0 | 17 | + let start = 0 |
| 22 | - let end = 0 | 18 | + let end = 0 |
| 23 | - let step = 60 | 19 | + let step = 60 |
| 24 | - if (tab === 1 && Array.isArray(fixedRangeTime) && fixedRangeTime.length === 2) { | 20 | + if (tab === 1 && Array.isArray(fixedRangeTime) && fixedRangeTime.length === 2) { |
| 25 | - end = Math.floor(moment(fixedRangeTime[1]).valueOf() / 1000) | 21 | + end = Math.floor(moment(fixedRangeTime[1]).valueOf() / 1000) |
| 26 | - start = Math.floor(moment(fixedRangeTime[0]).valueOf() / 1000) | 22 | + start = Math.floor(moment(fixedRangeTime[0]).valueOf() / 1000) |
| 27 | - if (end - start < 2 * 60) { | 23 | + if (end - start < 2 * 60) { |
| 28 | - const mid = start + Math.floor((end - start) / 2) | 24 | + const mid = start + Math.floor((end - start) / 2) |
| 29 | - end = mid + 60 | 25 | + end = mid + 60 |
| 30 | - start = mid - 60 | 26 | + start = mid - 60 |
| 31 | - } | 27 | + } |
| 32 | - console.log('sql detail - system source', start, end) | 28 | + console.log('sql detail - system source', start, end) |
| 33 | - } else { | 29 | + } else { |
| 34 | - if (rangeTime > 0) { | 30 | + if (rangeTime > 0) { |
| 35 | - const _time = moment() | 31 | + const _time = moment() |
| 36 | - end = Number.parseInt( | 32 | + end = Number.parseInt( |
| 37 | - `${ | 33 | + `${ |
| 38 | - _time | 34 | + _time |
| 39 | - .subtract(60 * rangeTime, 'second') | 35 | + .subtract(60 * rangeTime, 'second') |
| 40 | - .toDate() | 36 | + .toDate() |
| 41 | - .getTime() / 1000 | 37 | + .getTime() / 1000 |
| 42 | - }` | 38 | + }` |
| 43 | - ) | 39 | + ) |
| 44 | - start = Number.parseInt(`${_time.subtract(rangeTime, 'hour').toDate().getTime() / 1000}`) | 40 | + start = Number.parseInt(`${_time.subtract(rangeTime, 'hour').toDate().getTime() / 1000}`) |
| 45 | - step = 60 * rangeTime | 41 | + step = 60 * rangeTime |
| 46 | - } else { | 42 | + } else { |
| 47 | - start = Number.parseInt(`${time![0].getTime() / 1000}`) | 43 | + start = Number.parseInt(`${time![0].getTime() / 1000}`) |
| 48 | - end = Number.parseInt(`${time![1].getTime() / 1000}`) | 44 | + end = Number.parseInt(`${time![1].getTime() / 1000}`) |
| 49 | - step = Number.parseInt(`${(end - start) / 120}`) | 45 | + step = Number.parseInt(`${(end - start) / 120}`) |
| 50 | - } | 46 | + } |
| 51 | - } | 47 | + } |
| 52 | - monitorStore.promethuesStart = start | 48 | + monitorStore.promethuesStart = start |
| 53 | - monitorStore.promethuesEnd = end | 49 | + monitorStore.promethuesEnd = end |
| 54 | - monitorStore.promethuesStep = Math.max(60, step) | 50 | + monitorStore.promethuesStep = Math.max(60, step) |
| 55 | - return ogRequest.get('/observability/v1/monitoring/database-metrics', { | 51 | + return ogRequest.get('/observability/v1/monitoring/database-metrics', { |
| 56 | - id: instanceId, | 52 | + id: dbId !== undefined ? dbId : instanceId, |
| 57 | - start, | 53 | + start, |
| 58 | - end, | 54 | + end, |
| 59 | - step: Math.max(60, step), | 55 | + step: Math.max(60, step), |
| 60 | - type: 'LINE', | 56 | + type: 'LINE', |
| 61 | - }) | 57 | + }) |
| 62 | - }, | 58 | + }, |
| 63 | - { manual: true } | 59 | + { manual: true } |
| 64 | ) | 60 | ) |
| 65 | 61 | ||
| 66 | watch( | 62 | watch( |
| 67 | - data, | 63 | + data, |
| 68 | - () => { | 64 | + () => { |
| 69 | - console.log('prometheus:tabIdTemp2', tabIdTemp) | 65 | + console.log('prometheus:tabIdTemp2', tabIdTemp) |
| 70 | - const monitorStore = useMonitorStore(tabIdTemp) | 66 | + const monitorStore = useMonitorStore(tabIdTemp) |
| 71 | - if (monitorStore.tabNow === tabKeys.Home) { | 67 | + if (monitorStore.tabNow === tabKeys.Home) { |
| 72 | - monitorStore.databaseData = data.value || {} | 68 | + monitorStore.databaseData = data.value || {} |
| 73 | - console.log('prometheus:databaseData', monitorStore.databaseData) | 69 | + console.log('prometheus:databaseData', monitorStore.databaseData) |
| 74 | - } else { | 70 | + } else { |
| 75 | - monitorStore.serverData = data.value || {} | 71 | + monitorStore.serverData = data.value || {} |
| 76 | - } | 72 | + } |
| 77 | - }, | 73 | + }, |
| 78 | - { deep: true } | 74 | + { deep: true } |
| 79 | ) | 75 | ) |
| 80 | export { getDatabaseMetrics } | 76 | export { getDatabaseMetrics } |
| @@ -1,20 +1,47 @@ | |||
| 1 | -/// | ||
| 2 | -/// Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | -/// | ||
| 4 | - | ||
| 5 | import ogRequest from '@/request' | 1 | import ogRequest from '@/request' |
| 6 | 2 | ||
| 7 | export type SQLEvent = { | 3 | export type SQLEvent = { |
| 8 | - event: string | 4 | + event: string |
| 9 | - id: string | 5 | + id: string |
| 10 | - lockType: string | 6 | + lockType: string |
| 11 | - time: string | 7 | + time: string |
| 12 | - unknown: string | 8 | + unknown: string |
| 13 | } | 9 | } |
| 14 | 10 | ||
| 15 | export async function getSQLEvent(instanceId: string, sqlId: string): Promise<void | SQLEvent[]> { | 11 | export async function getSQLEvent(instanceId: string, sqlId: string): Promise<void | SQLEvent[]> { |
| 16 | - return ogRequest.get('/observability/v1/topsql/waitevent', { | 12 | + return ogRequest.get('/observability/v1/topsql/waitevent', { |
| 17 | - id: instanceId, | 13 | + id: instanceId, |
| 18 | - sqlId, | 14 | + sqlId, |
| 19 | - }) | 15 | + }) |
| 16 | +} | ||
| 17 | + | ||
| 18 | +export async function getSQLMetrics( | ||
| 19 | + instanceId: String, | ||
| 20 | + startTime: String, | ||
| 21 | + endTime: String, | ||
| 22 | + step: String | ||
| 23 | +): Promise<void | { | ||
| 24 | + CPU_DB: number[] | ||
| 25 | + CPU_IDLE: number[] | ||
| 26 | + CPU_IOWAIT: number[] | ||
| 27 | + CPU_IRQ: number[] | ||
| 28 | + CPU_NICE: number[] | ||
| 29 | + CPU_SOFTIRQ: number[] | ||
| 30 | + CPU_STEAL: number[] | ||
| 31 | + CPU_SYSTEM: number[] | ||
| 32 | + CPU_TOTAL: number[] | ||
| 33 | + CPU_USER: number[] | ||
| 34 | + IO_UTIL: number[][] | ||
| 35 | + MEMORY_DB_USED: number[] | ||
| 36 | + MEMORY_USED: number[] | ||
| 37 | + NETWORK_IN_TOTAL: number[] | ||
| 38 | + NETWORK_OUT_TOTAL: number[] | ||
| 39 | + time: string[] | ||
| 40 | +}> { | ||
| 41 | + return ogRequest.get('/observability/v1/topsql/sysResource', { | ||
| 42 | + id: instanceId, | ||
| 43 | + start: startTime, | ||
| 44 | + end: endTime, | ||
| 45 | + step, | ||
| 46 | + }) | ||
| 20 | } | 47 | } |
| @@ -0,0 +1,17 @@ | |||
| 1 | +import ogRequest from '@/request' | ||
| 2 | +import { useMonitorStore } from '@/store/monitor' | ||
| 3 | + | ||
| 4 | +export type WDRSnapshots = { | ||
| 5 | + start: string | ||
| 6 | + end: string | ||
| 7 | + wdrId: string[] | ||
| 8 | +} | ||
| 9 | +export async function getWDRSnapshot(tabId: string): Promise<void | WDRSnapshots> { | ||
| 10 | + const monitorStore = useMonitorStore(tabId) | ||
| 11 | + const { instanceId, timeRange } = monitorStore | ||
| 12 | + return ogRequest.get('/wdr/findSnapshot', { | ||
| 13 | + id: instanceId, | ||
| 14 | + start: timeRange == null ? '' : new Date(timeRange[0]).toISOString().replace(/\.\d+/, ''), | ||
| 15 | + end: timeRange == null ? '' : new Date(timeRange[1]).toISOString().replace(/\.\d+/, ''), | ||
| 16 | + }) | ||
| 17 | +} | ||
| @@ -7,260 +7,306 @@ | |||
| 7 | 7 | ||
| 8 | // page-header | 8 | // page-header |
| 9 | .page-header { | 9 | .page-header { |
| 10 | - display: flex; | 10 | + display: flex; |
| 11 | - flex-direction: row; | 11 | + flex-direction: row; |
| 12 | - align-items: center; | 12 | + align-items: center; |
| 13 | - padding-bottom: 7px; | 13 | + padding-bottom: 7px; |
| 14 | - border-bottom: 1px solid var(--border-1); | 14 | + border-bottom: 1px solid var(--border-1); |
| 15 | 15 | ||
| 16 | - .icon { | 16 | + .icon { |
| 17 | - width: 4px; | 17 | + width: 4px; |
| 18 | - height: 14px; | 18 | + height: 14px; |
| 19 | - background: var(--primary-6); | 19 | + background: var(--primary-6); |
| 20 | - border-radius: 1px; | 20 | + border-radius: 1px; |
| 21 | - margin-right: 4px; | 21 | + margin-right: 4px; |
| 22 | - } | 22 | + } |
| 23 | - .title { | 23 | + .title { |
| 24 | - font-family: 'Source Han Sans CN'; | 24 | + font-family: 'Source Han Sans CN'; |
| 25 | - font-style: normal; | 25 | + font-style: normal; |
| 26 | - font-weight: 700; | 26 | + font-weight: 700; |
| 27 | - font-size: 16px; | 27 | + font-size: 16px; |
| 28 | - line-height: 22px; | 28 | + line-height: 22px; |
| 29 | - height: 22px; | 29 | + height: 22px; |
| 30 | - /* identical to box height, or 138% */ | 30 | + /* identical to box height, or 138% */ |
| 31 | - letter-spacing: -0.01px; | 31 | + letter-spacing: -0.01px; |
| 32 | - color: var(--text-1); | 32 | + color: var(--text-1); |
| 33 | - } | 33 | + } |
| 34 | - .seperator { | 34 | + .seperator { |
| 35 | - margin: 0px 16px; | 35 | + margin: 0px 16px; |
| 36 | - width: 18px; | 36 | + width: 18px; |
| 37 | - height: 0px; | 37 | + height: 0px; |
| 38 | - border: 1px solid var(--border-1); | 38 | + border: 1px solid var(--border-1); |
| 39 | - transform: rotate(90deg); | 39 | + transform: rotate(90deg); |
| 40 | - } | 40 | + } |
| 41 | - .cluster-title { | 41 | + .cluster-title { |
| 42 | - height: 22px; | 42 | + height: 22px; |
| 43 | - font-family: 'Source Han Sans CN'; | 43 | + font-family: 'Source Han Sans CN'; |
| 44 | - font-style: normal; | 44 | + font-style: normal; |
| 45 | - font-weight: 400; | 45 | + font-weight: 400; |
| 46 | - font-size: 14px; | 46 | + font-size: 14px; |
| 47 | - line-height: 22px; | 47 | + line-height: 22px; |
| 48 | - color: var(--text-1); | 48 | + color: var(--text-1); |
| 49 | - } | 49 | + } |
| 50 | - .instance-info { | 50 | + .instance-info { |
| 51 | - margin-left: 4px; | 51 | + margin-left: 4px; |
| 52 | - } | 52 | + } |
| 53 | +} | ||
| 54 | + | ||
| 55 | +.main-container { | ||
| 56 | + margin-top: 16px; | ||
| 53 | } | 57 | } |
| 54 | 58 | ||
| 55 | // card margin bottom | 59 | // card margin bottom |
| 56 | .card-margin-bottom { | 60 | .card-margin-bottom { |
| 57 | - margin-bottom: 16px; | 61 | + margin-bottom: 16px; |
| 58 | } | 62 | } |
| 59 | .card-links { | 63 | .card-links { |
| 60 | - .el-link { | 64 | + .el-link { |
| 61 | - margin-right: 10px; | 65 | + margin-right: 10px; |
| 62 | - } | 66 | + } |
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | // tabs in card | 69 | // tabs in card |
| 66 | .card-tabs { | 70 | .card-tabs { |
| 67 | - &.el-tabs { | 71 | + &.el-tabs { |
| 68 | - --el-tabs-header-height: 32px; | 72 | + --el-tabs-header-height: 32px; |
| 69 | - > .el-tabs__header { | 73 | + > .el-tabs__header { |
| 70 | - .el-tabs__item { | 74 | + .el-tabs__item { |
| 71 | - padding: 0px 16px !important; | 75 | + padding: 0px 16px !important; |
| 72 | - } | 76 | + } |
| 73 | - } | ||
| 74 | } | 77 | } |
| 78 | + } | ||
| 75 | } | 79 | } |
| 76 | 80 | ||
| 77 | // table in card | 81 | // table in card |
| 78 | .table-in-card { | 82 | .table-in-card { |
| 79 | - padding: 0px 16px; | 83 | + padding: 0px 16px; |
| 80 | - .el-table--border { | 84 | + .el-table--border { |
| 81 | - border: 1px solid rgba(22, 93, 255, 0.4); | 85 | + border: 1px solid rgba(22, 93, 255, 0.4); |
| 82 | - } | 86 | + } |
| 83 | } | 87 | } |
| 84 | 88 | ||
| 85 | // text in card | 89 | // text in card |
| 86 | .text-in-card { | 90 | .text-in-card { |
| 87 | - padding: 8px 16px; | 91 | + padding: 8px 16px; |
| 88 | - .text-row { | 92 | + .text-row { |
| 89 | - display: flex; | 93 | + display: flex; |
| 90 | - flex-direction: row; | 94 | + flex-direction: row; |
| 91 | - .label { | 95 | + .label { |
| 92 | - width: 115px; | 96 | + width: 115px; |
| 93 | - text-align: right; | 97 | + text-align: right; |
| 94 | - } | ||
| 95 | } | 98 | } |
| 99 | + } | ||
| 96 | } | 100 | } |
| 97 | 101 | ||
| 98 | // normal grid header | 102 | // normal grid header |
| 99 | .grid-header { | 103 | .grid-header { |
| 100 | - background: var(--background-color-2) !important; | 104 | + background: var(--background-color-2) !important; |
| 101 | - .cell { | 105 | + .cell { |
| 102 | - line-height: 22px !important; | 106 | + line-height: 22px !important; |
| 103 | - } | 107 | + } |
| 108 | +} | ||
| 109 | +.highlight-row { | ||
| 110 | + background: #fff8df ; | ||
| 104 | } | 111 | } |
| 105 | - | ||
| 106 | 112 | ||
| 107 | // grid header when grid is in card | 113 | // grid header when grid is in card |
| 108 | .grid-header-in-card { | 114 | .grid-header-in-card { |
| 109 | - background: var(--background-color-3) !important; | 115 | + background: var(--background-color-3) !important; |
| 110 | - .cell { | 116 | + .cell { |
| 111 | - line-height: 22px !important; | 117 | + line-height: 22px !important; |
| 112 | - } | 118 | + } |
| 113 | } | 119 | } |
| 114 | 120 | ||
| 115 | .table-link { | 121 | .table-link { |
| 116 | - color: var(--link-6); | 122 | + color: var(--link-6); |
| 117 | - cursor: pointer; | 123 | + cursor: pointer; |
| 118 | } | 124 | } |
| 119 | 125 | ||
| 120 | .el-tabs__item.is-disabled { | 126 | .el-tabs__item.is-disabled { |
| 121 | - cursor: auto !important; | 127 | + cursor: auto !important; |
| 122 | } | 128 | } |
| 123 | 129 | ||
| 124 | // table | 130 | // table |
| 131 | +.filter-bar { | ||
| 132 | + display: flex; | ||
| 133 | + flex-direction: row; | ||
| 134 | + align-items: center; | ||
| 135 | + justify-content: flex-end; | ||
| 136 | + width: 100%; | ||
| 137 | + margin-bottom: 8px; | ||
| 138 | + .item:not(:last-child) { | ||
| 139 | + display: flex; | ||
| 140 | + align-items: center; | ||
| 141 | + margin-right: 16px; | ||
| 142 | + } | ||
| 143 | +} | ||
| 125 | .normal-table { | 144 | .normal-table { |
| 126 | - .operate-btns { | 145 | + .operate-btns { |
| 127 | - display: flex; | 146 | + display: flex; |
| 128 | - justify-content: space-around; | 147 | + justify-content: space-around; |
| 129 | - } | 148 | + } |
| 130 | } | 149 | } |
| 131 | .search-form { | 150 | .search-form { |
| 151 | + display: flex; | ||
| 152 | + justify-content: flex-end; | ||
| 153 | + align-items: center; | ||
| 154 | + margin-bottom: 20px; | ||
| 155 | + .search-time-range { | ||
| 156 | + width: 300px; | ||
| 157 | + } | ||
| 158 | + .filter { | ||
| 159 | + display: flex; | ||
| 160 | + align-items: center; | ||
| 161 | + } | ||
| 162 | + .filter:not(:last-child) { | ||
| 163 | + margin-right: 15px; | ||
| 164 | + } | ||
| 165 | + .seperator { | ||
| 166 | + margin: auto; | ||
| 167 | + } | ||
| 168 | +} | ||
| 169 | +.search-form-multirow { | ||
| 170 | + .row { | ||
| 132 | display: flex; | 171 | display: flex; |
| 133 | justify-content: flex-end; | 172 | justify-content: flex-end; |
| 134 | align-items: center; | 173 | align-items: center; |
| 135 | - margin-bottom: 20px; | ||
| 136 | .search-time-range { | 174 | .search-time-range { |
| 137 | - width: 300px; | 175 | + width: 300px; |
| 138 | } | 176 | } |
| 139 | .filter { | 177 | .filter { |
| 140 | - display: flex; | 178 | + display: flex; |
| 141 | - align-items: center; | 179 | + align-items: center; |
| 142 | } | 180 | } |
| 143 | .filter:not(:last-child) { | 181 | .filter:not(:last-child) { |
| 144 | - margin-right: 15px; | 182 | + margin-right: 15px; |
| 145 | } | 183 | } |
| 146 | .seperator { | 184 | .seperator { |
| 147 | - margin: auto; | 185 | + margin: auto; |
| 148 | - } | ||
| 149 | -} | ||
| 150 | -.search-form-multirow { | ||
| 151 | - .row { | ||
| 152 | - display: flex; | ||
| 153 | - justify-content: flex-end; | ||
| 154 | - align-items: center; | ||
| 155 | - .search-time-range { | ||
| 156 | - width: 300px; | ||
| 157 | - } | ||
| 158 | - .filter { | ||
| 159 | - display: flex; | ||
| 160 | - align-items: center; | ||
| 161 | - } | ||
| 162 | - .filter:not(:last-child) { | ||
| 163 | - margin-right: 15px; | ||
| 164 | - } | ||
| 165 | - .seperator { | ||
| 166 | - margin: auto; | ||
| 167 | - } | ||
| 168 | - margin-bottom: 10px; | ||
| 169 | } | 186 | } |
| 170 | margin-bottom: 10px; | 187 | margin-bottom: 10px; |
| 188 | + } | ||
| 189 | + margin-bottom: 10px; | ||
| 190 | +} | ||
| 191 | +.state-row { | ||
| 192 | + display: flex; | ||
| 193 | + flex-direction: row; | ||
| 194 | + align-items: center; | ||
| 195 | + .state { | ||
| 196 | + width: 6px; | ||
| 197 | + height: 6px; | ||
| 198 | + margin-right: 4px; | ||
| 199 | + border-radius: 100px; | ||
| 200 | + &.green { | ||
| 201 | + background: var(--green, #52c41a); | ||
| 202 | + box-shadow: 0px 1px 3px 0px #52c41a; | ||
| 203 | + } | ||
| 204 | + &.yellow { | ||
| 205 | + background: var(--green, #ffa53c); | ||
| 206 | + box-shadow: 0px 1px 3px 0px #ffa53c; | ||
| 207 | + } | ||
| 208 | + &.red { | ||
| 209 | + background: var(--green, #f6605a); | ||
| 210 | + box-shadow: 0px 1px 3px 0px #f6605a; | ||
| 211 | + } | ||
| 212 | + &.grey { | ||
| 213 | + background: var(--green, #b8b8b8); | ||
| 214 | + box-shadow: 0px 1px 3px 0px #b8b8b8; | ||
| 215 | + } | ||
| 216 | + } | ||
| 171 | } | 217 | } |
| 172 | 218 | ||
| 173 | .refresh-bar { | 219 | .refresh-bar { |
| 174 | - &-container { | 220 | + &-container { |
| 175 | - height: 500px; | 221 | + height: 500px; |
| 176 | - position: absolute; | 222 | + position: absolute; |
| 177 | - right: -14px; | 223 | + right: -14px; |
| 178 | - top: 0px; | 224 | + top: 0px; |
| 179 | - padding-top: 1px; | 225 | + padding-top: 1px; |
| 180 | - display: flex; | 226 | + display: flex; |
| 181 | - margin-bottom: 10px; | 227 | + margin-bottom: 10px; |
| 182 | - justify-content: end; | 228 | + justify-content: end; |
| 183 | - overflow: hidden; | 229 | + overflow: hidden; |
| 184 | - font-size: 12px; | 230 | + font-size: 12px; |
| 231 | + } | ||
| 232 | + | ||
| 233 | + &-filter { | ||
| 234 | + font-size: 12px; | ||
| 235 | + width: 800px; | ||
| 236 | + z-index: 10; | ||
| 237 | + padding-right: 16px; | ||
| 238 | + display: flex; | ||
| 239 | + align-items: center; | ||
| 240 | + padding: 0 10px; | ||
| 241 | + height: 30px; | ||
| 242 | + > div:not(:last-of-type), | ||
| 243 | + > span, | ||
| 244 | + > button { | ||
| 245 | + margin-right: 4px; | ||
| 185 | } | 246 | } |
| 186 | 247 | ||
| 187 | - &-filter { | 248 | + :deep(.el-button .el-icon svg) { |
| 188 | - font-size: 12px; | 249 | + color: var(--el-color-icon-refresh-color); |
| 189 | - width: 800px; | ||
| 190 | - z-index: 10; | ||
| 191 | - padding-right: 16px; | ||
| 192 | - display: flex; | ||
| 193 | - align-items: center; | ||
| 194 | - padding: 0 10px; | ||
| 195 | - height: 30px; | ||
| 196 | - > div:not(:last-of-type), | ||
| 197 | - > span, | ||
| 198 | - > button { | ||
| 199 | - margin-right: 4px; | ||
| 200 | - } | ||
| 201 | - | ||
| 202 | - :deep(.el-button .el-icon svg) { | ||
| 203 | - color: var(--el-color-icon-refresh-color); | ||
| 204 | - } | ||
| 205 | - | ||
| 206 | - :deep(.el-select .el-input.is-focus .el-input__wrapper) { | ||
| 207 | - box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset ; | ||
| 208 | - } | ||
| 209 | - :deep(.el-select-dropdown__item.selected) { | ||
| 210 | - color: var(--el-color-tabbar-active) ; | ||
| 211 | - } | ||
| 212 | - :deep(.el-range-editor.is-active) { | ||
| 213 | - box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset ; | ||
| 214 | - } | ||
| 215 | } | 250 | } |
| 216 | 251 | ||
| 217 | - :deep(.el-range-input) { | 252 | + :deep(.el-select .el-input.is-focus .el-input__wrapper) { |
| 218 | - background-color: var(--el-bg-color); | 253 | + box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset !important; |
| 219 | } | 254 | } |
| 255 | + :deep(.el-select-dropdown__item.selected) { | ||
| 256 | + color: var(--el-color-tabbar-active) ; | ||
| 257 | + } | ||
| 258 | + :deep(.el-range-editor.is-active) { | ||
| 259 | + box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset ; | ||
| 260 | + } | ||
| 261 | + } | ||
| 220 | 262 | ||
| 221 | - :deep(.el-date-editor--datetimerange) { | 263 | + :deep(.el-range-input) { |
| 222 | - width: 100px; | 264 | + background-color: var(--el-bg-color); |
| 223 | - background-color: var(--el-bg-color); | 265 | + } |
| 224 | - } | 266 | + |
| 267 | + :deep(.el-date-editor--datetimerange) { | ||
| 268 | + width: 100px; | ||
| 269 | + background-color: var(--el-bg-color); | ||
| 270 | + } | ||
| 225 | } | 271 | } |
| 226 | 272 | ||
| 227 | .refresh-button.el-button.el-button--primary { | 273 | .refresh-button.el-button.el-button--primary { |
| 228 | - background-color: var(--button-1-background) !important; | 274 | + background-color: var(--button-1-background) !important; |
| 229 | - border: 1px solid var(--button-1-border) !important; | 275 | + border: 1px solid var(--button-1-border) !important; |
| 230 | - color: var(--button-1-color) !important; | 276 | + color: var(--button-1-color) !important; |
| 231 | - padding: 8px !important; | 277 | + padding: 8px !important; |
| 232 | } | 278 | } |
| 233 | 279 | ||
| 234 | .divider { | 280 | .divider { |
| 235 | - height: 24px; | 281 | + height: 24px; |
| 236 | - width: 1px; | 282 | + width: 1px; |
| 237 | - margin: 0 8px !important; | 283 | + margin: 0 8px !important; |
| 238 | - background-color: var(--el-color-divider-border-color); | 284 | + background-color: var(--el-color-divider-border-color); |
| 239 | } | 285 | } |
| 240 | 286 | ||
| 241 | .gap-row { | 287 | .gap-row { |
| 242 | - margin-bottom: 16px; | 288 | + margin-bottom: 16px; |
| 243 | } | 289 | } |
| 244 | 290 | ||
| 245 | .line-tips { | 291 | .line-tips { |
| 246 | - position: absolute; | 292 | + position: absolute; |
| 247 | - top: 8px; | 293 | + top: 8px; |
| 248 | - left: 13px; | 294 | + left: 13px; |
| 295 | + display: flex; | ||
| 296 | + > div { | ||
| 297 | + font-size: 12px; | ||
| 249 | display: flex; | 298 | display: flex; |
| 250 | - > div { | 299 | + flex-direction: row; |
| 251 | - font-size: 12px; | 300 | + align-items: center; |
| 252 | - display: flex; | 301 | + padding: 4px 12px; |
| 253 | - flex-direction: row; | 302 | + gap: 4px; |
| 254 | - align-items: center; | 303 | + border: 1px solid var(--border-2); |
| 255 | - padding: 4px 12px; | 304 | + border-radius: 2px; |
| 256 | - gap: 4px; | 305 | + } |
| 257 | - border: 1px solid var(--border-2); | ||
| 258 | - border-radius: 2px; | ||
| 259 | - } | ||
| 260 | 306 | ||
| 261 | - &.center { | 307 | + &.center { |
| 262 | - position: unset; | 308 | + position: unset; |
| 263 | - justify-content: center; | 309 | + justify-content: center; |
| 264 | - flex-direction: row; | 310 | + flex-direction: row; |
| 265 | - } | 311 | + } |
| 266 | } | 312 | } |
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path fill-rule="evenodd" clip-rule="evenodd" d="M7.05709 7.9999L2.81445 3.75726L3.75726 2.81445L7.9999 7.05709L12.2425 2.81445L13.1854 3.75726L8.94271 7.9999L13.1854 12.2425L12.2425 13.1854L7.9999 8.94271L3.75726 13.1854L2.81445 12.2425L7.05709 7.9999Z" fill="#4E5969"/> | ||
| 3 | +</svg> | ||
| @@ -9,6 +9,8 @@ declare module '@vue/runtime-core' { | |||
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | ClusterCascader: typeof import('./components/ClusterCascader.vue')['default'] | 10 | ClusterCascader: typeof import('./components/ClusterCascader.vue')['default'] |
| 11 | ElAside: typeof import('element-plus/es')['ElAside'] | 11 | ElAside: typeof import('element-plus/es')['ElAside'] |
| 12 | + ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] | ||
| 13 | + ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ||
| 12 | ElButton: typeof import('element-plus/es')['ElButton'] | 14 | ElButton: typeof import('element-plus/es')['ElButton'] |
| 13 | ElCascader: typeof import('element-plus/es')['ElCascader'] | 15 | ElCascader: typeof import('element-plus/es')['ElCascader'] |
| 14 | ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | 16 | ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] |
| @@ -3,7 +3,8 @@ | |||
| 3 | <div class="refresh-bar-filter" > | 3 | <div class="refresh-bar-filter" > |
| 4 | <div style="width: 200px;"></div> | 4 | <div style="width: 200px;"></div> |
| 5 | <div style="white-space: nowrap">{{ $t('app.autoRefresh') }}:</div> | 5 | <div style="white-space: nowrap">{{ $t('app.autoRefresh') }}:</div> |
| 6 | - <el-select v-model="autoRefreshTime" style="width: 80px; margin: 0 4px"> | 6 | + <el-select v-model="autoRefreshTime" style="width: 130px; margin: 0 4px"> |
| 7 | + <el-option :value="99999999" label="NO-AUTO" /> | ||
| 7 | <el-option :value="1" label="1s" /> | 8 | <el-option :value="1" label="1s" /> |
| 8 | <el-option :value="15" label="15s" /> | 9 | <el-option :value="15" label="15s" /> |
| 9 | <el-option :value="30" label="30s" /> | 10 | <el-option :value="30" label="30s" /> |
| @@ -89,11 +89,14 @@ const props = withDefaults( | |||
| 89 | interval?: number // yAxis interval | 89 | interval?: number // yAxis interval |
| 90 | tabId: string | 90 | tabId: string |
| 91 | rangeSelect: boolean | 91 | rangeSelect: boolean |
| 92 | + legendShown: boolean | ||
| 92 | isTooltipsFormatDate: boolean // x value is date,and format to YYYY-MM-DD HH:mm:ss | 93 | isTooltipsFormatDate: boolean // x value is date,and format to YYYY-MM-DD HH:mm:ss |
| 93 | 94 | ||
| 94 | unit?: string | 95 | unit?: string |
| 95 | scatterUnit?: string | 96 | scatterUnit?: string |
| 96 | tips?: string | 97 | tips?: string |
| 98 | + toolTipsSort?: string // desc asc | ||
| 99 | + toolTipsExcludeZero?: boolean | ||
| 97 | // yAxis Scatter Data | 100 | // yAxis Scatter Data |
| 98 | scatterData?: LineData | 101 | scatterData?: LineData |
| 99 | // LineChart use areaStyle | 102 | // LineChart use areaStyle |
| @@ -116,6 +119,7 @@ const props = withDefaults( | |||
| 116 | enterable?: boolean | 119 | enterable?: boolean |
| 117 | translate?: boolean | 120 | translate?: boolean |
| 118 | countByDataTimePicker: boolean | 121 | countByDataTimePicker: boolean |
| 122 | + xFormater?: string | ||
| 119 | }>(), | 123 | }>(), |
| 120 | { | 124 | { |
| 121 | xData: () => [], | 125 | xData: () => [], |
| @@ -124,6 +128,7 @@ const props = withDefaults( | |||
| 124 | scatterUnit: '', | 128 | scatterUnit: '', |
| 125 | areaStyle: false, | 129 | areaStyle: false, |
| 126 | rangeSelect: false, | 130 | rangeSelect: false, |
| 131 | + legendShown: true, | ||
| 127 | translate: true, | 132 | translate: true, |
| 128 | isTooltipsFormatDate: true, | 133 | isTooltipsFormatDate: true, |
| 129 | enterable: true, | 134 | enterable: true, |
| @@ -168,10 +173,12 @@ const renderChart = () => { | |||
| 168 | areaStyle: props.areaStyle ? {} : undefined, | 173 | areaStyle: props.areaStyle ? {} : undefined, |
| 169 | ...d, | 174 | ...d, |
| 170 | } | 175 | } |
| 171 | - if (props.bar) { | 176 | + if (props.bar && d.type === undefined) { |
| 172 | o.type = 'bar' | 177 | o.type = 'bar' |
| 178 | + o['barGap'] = '0%' | ||
| 179 | + o['barCategoryGap'] = '0%' | ||
| 180 | + o['barWidth'] = '100%' | ||
| 173 | o['stack'] = 'total' | 181 | o['stack'] = 'total' |
| 174 | - o['barMaxWidth'] = 12 | ||
| 175 | } | 182 | } |
| 176 | if (props.stack) { | 183 | if (props.stack) { |
| 177 | o['stack'] = 'total' | 184 | o['stack'] = 'total' |
| @@ -210,7 +217,7 @@ const renderChart = () => { | |||
| 210 | }, | 217 | }, |
| 211 | color: props.color ? props.color : colorArray, | 218 | color: props.color ? props.color : colorArray, |
| 212 | legend: { | 219 | legend: { |
| 213 | - show: true, | 220 | + show: props.legendShown, |
| 214 | type: 'scroll', | 221 | type: 'scroll', |
| 215 | left: 10, | 222 | left: 10, |
| 216 | bottom: 0, | 223 | bottom: 0, |
| @@ -227,7 +234,7 @@ const renderChart = () => { | |||
| 227 | left: 15, | 234 | left: 15, |
| 228 | right: 15, | 235 | right: 15, |
| 229 | top: props.tips ? 50 : 25, | 236 | top: props.tips ? 50 : 25, |
| 230 | - bottom: 28, | 237 | + bottom: props.legendShown ? 28 : 15, |
| 231 | containLabel: true, | 238 | containLabel: true, |
| 232 | }, | 239 | }, |
| 233 | tooltip: { | 240 | tooltip: { |
| @@ -247,19 +254,30 @@ const renderChart = () => { | |||
| 247 | } else { | 254 | } else { |
| 248 | htmlStr += '<div style="font-size:14px">' + params[0].axisValue + '</div>' | 255 | htmlStr += '<div style="font-size:14px">' + params[0].axisValue + '</div>' |
| 249 | } | 256 | } |
| 250 | - | 257 | + let tempParams = params.filter((item: any) => { |
| 251 | - for (let i = 0; i < params.length; i++) { | 258 | + if ( |
| 259 | + props.toolTipsExcludeZero && | ||
| 260 | + (Number.isNaN(item.value) || item.value === 'NaN' || Number(item.value) === 0) | ||
| 261 | + ) { | ||
| 262 | + return false | ||
| 263 | + } else { | ||
| 264 | + return true | ||
| 265 | + } | ||
| 266 | + }) | ||
| 267 | + if (props.toolTipsSort === 'desc') tempParams.sort((a: any, b: any) => b.value - a.value) | ||
| 268 | + if (props.toolTipsSort === 'asc') tempParams.sort((a: any, b: any) => a.value - b.value) | ||
| 269 | + for (let i = 0; i < tempParams.length; i++) { | ||
| 252 | // htmlStr += '<div ">' + params[i].marker + params[i].seriesName + ':' + params[i].value + '</div>' | 270 | // htmlStr += '<div ">' + params[i].marker + params[i].seriesName + ':' + params[i].value + '</div>' |
| 253 | htmlStr += | 271 | htmlStr += |
| 254 | '<div style="display: flex;flex-direction: row;align-items:center;font-size:12px">' + | 272 | '<div style="display: flex;flex-direction: row;align-items:center;font-size:12px">' + |
| 255 | '<div style="display: inline-block; width: 14px; height: 4px;border-radius: 1px;margin-right:8px;background-color: ' + | 273 | '<div style="display: inline-block; width: 14px; height: 4px;border-radius: 1px;margin-right:8px;background-color: ' + |
| 256 | - params[i].color + | 274 | + tempParams[i].color + |
| 257 | ';"></div>' + | 275 | ';"></div>' + |
| 258 | '<div style="flex-grow:1;padding-right:12px">' + | 276 | '<div style="flex-grow:1;padding-right:12px">' + |
| 259 | - params[i].seriesName + | 277 | + tempParams[i].seriesName + |
| 260 | '</div>' + | 278 | '</div>' + |
| 261 | '<div style="">' + | 279 | '<div style="">' + |
| 262 | - params[i].value + | 280 | + tempParams[i].value + |
| 263 | (props.unit ? props.unit : '') + | 281 | (props.unit ? props.unit : '') + |
| 264 | '</div>' + | 282 | '</div>' + |
| 265 | '</div>' | 283 | '</div>' |
| @@ -304,7 +322,10 @@ const renderChart = () => { | |||
| 304 | axisLabel: { | 322 | axisLabel: { |
| 305 | color: theme.value === 'dark' ? '#FFFFFF' : '#4E5969', | 323 | color: theme.value === 'dark' ? '#FFFFFF' : '#4E5969', |
| 306 | fontSize: 10, | 324 | fontSize: 10, |
| 307 | - formatter: (v) => moment(new Date(v)).format('HH:mm'), | 325 | + formatter: (v) => { |
| 326 | + if (props.xFormater) return moment(new Date(v)).format(props.xFormater) | ||
| 327 | + else return moment(new Date(v)).format('HH:mm') | ||
| 328 | + }, | ||
| 308 | }, | 329 | }, |
| 309 | data: props.xData, | 330 | data: props.xData, |
| 310 | }, | 331 | }, |
| @@ -347,6 +368,13 @@ const renderChart = () => { | |||
| 347 | }, | 368 | }, |
| 348 | series: data.length > 0 ? data : [], | 369 | series: data.length > 0 ? data : [], |
| 349 | } | 370 | } |
| 371 | + | ||
| 372 | + myChart.on('legendselectchanged', function (params: any) { | ||
| 373 | + let selectedLegend = params.name | ||
| 374 | + | ||
| 375 | + myEmit('legendSelected', selectedLegend) | ||
| 376 | + }) | ||
| 377 | + | ||
| 350 | myChart.setOption(option, true) | 378 | myChart.setOption(option, true) |
| 351 | if ( | 379 | if ( |
| 352 | !props.countByDataTimePicker && | 380 | !props.countByDataTimePicker && |
| @@ -387,9 +415,7 @@ const renderChart = () => { | |||
| 387 | } | 415 | } |
| 388 | } | 416 | } |
| 389 | // lazy load | 417 | // lazy load |
| 390 | -const myEmit = defineEmits<{ | 418 | +const myEmit = defineEmits(['load', 'legendSelected']) |
| 391 | - (event: 'load'): void | ||
| 392 | -}>() | ||
| 393 | const loadRef = ref<HTMLDivElement>() | 419 | const loadRef = ref<HTMLDivElement>() |
| 394 | const { stop } = useIntersectionObserver(loadRef, ([{ isIntersecting }]) => { | 420 | const { stop } = useIntersectionObserver(loadRef, ([{ isIntersecting }]) => { |
| 395 | if (isIntersecting) { | 421 | if (isIntersecting) { |
| @@ -20,7 +20,8 @@ export default { | |||
| 20 | cancel: 'cancel', | 20 | cancel: 'cancel', |
| 21 | confirm: 'confirm', | 21 | confirm: 'confirm', |
| 22 | edit: 'edit', | 22 | edit: 'edit', |
| 23 | - operate: 'operate', | 23 | + operate: 'Operate', |
| 24 | + detail: 'Detail', | ||
| 24 | view: 'view', | 25 | view: 'view', |
| 25 | download: 'download', | 26 | download: 'download', |
| 26 | reset: 'Reset', | 27 | reset: 'Reset', |
| @@ -34,12 +35,39 @@ export default { | |||
| 34 | autoRefreshFor: 'Auto Refresh:', | 35 | autoRefreshFor: 'Auto Refresh:', |
| 35 | needSQLDiagnosis: 'Please install the smart diagnosis plug-in first', | 36 | needSQLDiagnosis: 'Please install the smart diagnosis plug-in first', |
| 36 | diagnosis: 'Diagnosis', | 37 | diagnosis: 'Diagnosis', |
| 38 | + all: 'All', | ||
| 37 | }, | 39 | }, |
| 38 | instanceMonitor: { | 40 | instanceMonitor: { |
| 39 | instanceMonitor: 'Instance Monitor', | 41 | instanceMonitor: 'Instance Monitor', |
| 40 | clusterTitle: 'Cluster/Instances:', | 42 | clusterTitle: 'Cluster/Instances:', |
| 41 | index: 'Home', | 43 | index: 'Home', |
| 42 | resourceMonitor: 'Resource Monitor', | 44 | resourceMonitor: 'Resource Monitor', |
| 45 | + thisInstance: ',Current Instance', | ||
| 46 | + asp: { | ||
| 47 | + sampleActiveSessionCount: 'Sample Active Session Count', | ||
| 48 | + aspAnalysis: 'ASP Analysis', | ||
| 49 | + analysisMetrics: 'Analysis Metrics', | ||
| 50 | + filterConditions: 'Filter Conditions', | ||
| 51 | + clickLegendToAddFilter: 'Click Legend to Add Filter', | ||
| 52 | + sampleCount: 'Sample Count', | ||
| 53 | + activeSessionCount: 'Active Session Count', | ||
| 54 | + }, | ||
| 55 | + nodeInfo: { | ||
| 56 | + instanceInfo: 'Instance information', | ||
| 57 | + databaseVersion: 'Database version:', | ||
| 58 | + databaseStartTime: 'Database start time:', | ||
| 59 | + databaseDataDirectory: 'Database data directory:', | ||
| 60 | + databaseLogDirectory: 'Database log directory:', | ||
| 61 | + enableArchiving: 'Enable archiving:', | ||
| 62 | + yes: 'Yes', | ||
| 63 | + no: 'No', | ||
| 64 | + operatingSystemVersion: 'Operating system version:', | ||
| 65 | + serverCPUManufacturer: 'Server CPU manufacturer:', | ||
| 66 | + serverCPUModel: 'Server CPU model:', | ||
| 67 | + serverCPUCoreCount: 'Server CPU core count:', | ||
| 68 | + cores: 'cores', | ||
| 69 | + totalMemorySize: 'Total memory size:', | ||
| 70 | + }, | ||
| 43 | instance: { | 71 | instance: { |
| 44 | connectionQty: 'Connections', | 72 | connectionQty: 'Connections', |
| 45 | slowSQL3s: 'Number Of Slow Sqls(>3s)', | 73 | slowSQL3s: 'Number Of Slow Sqls(>3s)', |
| @@ -54,6 +82,73 @@ export default { | |||
| 54 | slowSQLQty: 'Slow SQL Number', | 82 | slowSQLQty: 'Slow SQL Number', |
| 55 | }, | 83 | }, |
| 56 | }, | 84 | }, |
| 85 | + clusterMonitor: { | ||
| 86 | + clusterMonitor: 'Cluster Monitor', | ||
| 87 | + instanceMonitor: 'Instance Monitor', | ||
| 88 | + clusterList: 'Clusters', | ||
| 89 | + delayList: 'Primary-Backup Delay', | ||
| 90 | + detail: { | ||
| 91 | + title: 'Cluster Details (Cluster Name = temp)', | ||
| 92 | + info: 'Cluster Information', | ||
| 93 | + instance: { | ||
| 94 | + legend: 'Legend', | ||
| 95 | + nodeName: 'Node Name', | ||
| 96 | + ipPort: 'IP Port', | ||
| 97 | + role: 'Role', | ||
| 98 | + nodeStatus: 'Node Status', | ||
| 99 | + syncMode: 'Sync Mode', | ||
| 100 | + syncPriority: 'Sync Priority', | ||
| 101 | + syncStatus: 'Sync Status', | ||
| 102 | + receiveDelay: 'Receive Delay', | ||
| 103 | + diskDelay: 'Disk Delay', | ||
| 104 | + replayDelay: 'Replay Delay', | ||
| 105 | + performanceMonitoring: 'Performance Monitoring', | ||
| 106 | + memory: 'Memory', | ||
| 107 | + networkReceive: 'Network (Receive)', | ||
| 108 | + networkSend: 'Network (Send)', | ||
| 109 | + diskRead: 'Disk Read', | ||
| 110 | + sqlResponseTime80: '80% SQL Response Time', | ||
| 111 | + sqlResponseTime95: '95% SQL Response Time', | ||
| 112 | + primaryWalAccumulation: 'Primary WAL Accumulation (Daily) (KB)', | ||
| 113 | + primaryWalSendPressure: 'Primary WAL Send Pressure (KB)', | ||
| 114 | + primaryWalWriteRate: 'Primary WAL Write Rate (KB/S)', | ||
| 115 | + standbyReceiveDelay: 'Standby Receive Delay (KB)', | ||
| 116 | + standbyDiskDelay: 'Standby Disk Delay (KB)', | ||
| 117 | + standbyReplayDelay: 'Standby Replay Delay (KB)', | ||
| 118 | + }, | ||
| 119 | + }, | ||
| 120 | + list: { | ||
| 121 | + name: 'Cluster Name', | ||
| 122 | + state: 'Cluster Status', | ||
| 123 | + stateDesc: 'Status Description', | ||
| 124 | + pointCount: 'Number of Nodes', | ||
| 125 | + user: 'Database User', | ||
| 126 | + posrt: 'Database Port', | ||
| 127 | + deploymentMethod: 'Architecture', | ||
| 128 | + deploymentMethodN: 'Architecture:', | ||
| 129 | + faildNodesNum: 'Number of Failure Nodes:', | ||
| 130 | + searchInstanceName: 'Search instance name', | ||
| 131 | + version: 'Database Version', | ||
| 132 | + versionNum: 'Version Num', | ||
| 133 | + path: 'ENV File Path', | ||
| 134 | + noNodeId: 'Failed to retrieve master node information!', | ||
| 135 | + }, | ||
| 136 | + delay: { | ||
| 137 | + nodeName: 'Node Name', | ||
| 138 | + nodeStatus: 'Node Status', | ||
| 139 | + primaryIpPort: 'Primary IP Port', | ||
| 140 | + secondaryIpPort: 'Secondary IP Port', | ||
| 141 | + syncMode: 'Sync Mode', | ||
| 142 | + syncStatus: 'Sync Status', | ||
| 143 | + syncModeN: 'Sync Mode:', | ||
| 144 | + syncStatusN: 'Sync Status:', | ||
| 145 | + syncPriority: 'Sync Priority', | ||
| 146 | + receiveDelay: 'Receive Delay', | ||
| 147 | + diskDelay: 'Disk Delay', | ||
| 148 | + replayDelay: 'Replay Delay', | ||
| 149 | + searchNodeName: 'Search Node Name', | ||
| 150 | + }, | ||
| 151 | + }, | ||
| 57 | resourceMonitor: { | 152 | resourceMonitor: { |
| 58 | memoryTab: 'Memory', | 153 | memoryTab: 'Memory', |
| 59 | ioTab: 'IO', | 154 | ioTab: 'IO', |
| @@ -74,6 +169,7 @@ export default { | |||
| 74 | usedMemory: 'Used Memory', | 169 | usedMemory: 'Used Memory', |
| 75 | freeMemory: 'Free Memory', | 170 | freeMemory: 'Free Memory', |
| 76 | cachedMemory: 'Cached Memory', | 171 | cachedMemory: 'Cached Memory', |
| 172 | + dbMemory: 'Database Memory Usage', | ||
| 77 | interactiveAreaUsage: 'Interactive Area Usage', | 173 | interactiveAreaUsage: 'Interactive Area Usage', |
| 78 | totalExchangeArea: 'Total Exchange Area', | 174 | totalExchangeArea: 'Total Exchange Area', |
| 79 | ysedSwapArea: 'Used Swap Area', | 175 | ysedSwapArea: 'Used Swap Area', |
| @@ -119,6 +215,7 @@ export default { | |||
| 119 | costTime: 'Cost Time(s)', | 215 | costTime: 'Cost Time(s)', |
| 120 | sessionId: 'Session ID', | 216 | sessionId: 'Session ID', |
| 121 | detail: 'detail', | 217 | detail: 'detail', |
| 218 | + wdrAnalysis: 'WDR analysis', | ||
| 122 | }, | 219 | }, |
| 123 | trans: { | 220 | trans: { |
| 124 | longTransaction: 'LongTransaction', | 221 | longTransaction: 'LongTransaction', |
| @@ -153,6 +250,20 @@ export default { | |||
| 153 | clientIP: 'Client IP', | 250 | clientIP: 'Client IP', |
| 154 | appName: 'Application Name', | 251 | appName: 'Application Name', |
| 155 | }, | 252 | }, |
| 253 | + waitEventTab: { | ||
| 254 | + title: 'Wait Events', | ||
| 255 | + blockSessionid: 'Blocked Session ID', | ||
| 256 | + dbName: 'Database Name', | ||
| 257 | + lockmode: 'Lock Mode', | ||
| 258 | + locktag: 'Lock Information', | ||
| 259 | + nodeName: 'Node Name', | ||
| 260 | + queryId: 'Query ID', | ||
| 261 | + sessionid: 'Session ID', | ||
| 262 | + threadName: 'Thread Name', | ||
| 263 | + tid: 'Thread ID', | ||
| 264 | + waitEvent: 'Wait Event', | ||
| 265 | + waitStatus: 'Wait Status', | ||
| 266 | + }, | ||
| 156 | trans: { | 267 | trans: { |
| 157 | tabTitle: 'Long Transactions', | 268 | tabTitle: 'Long Transactions', |
| 158 | longTransaction: 'Long Transaction', | 269 | longTransaction: 'Long Transaction', |
| @@ -318,6 +429,7 @@ export default { | |||
| 318 | 'Number Of Database Avtivity Session', | 429 | 'Number Of Database Avtivity Session', |
| 319 | 'Number Of Database Block Session', | 430 | 'Number Of Database Block Session', |
| 320 | ], | 431 | ], |
| 432 | + clusters: 'Cluster Monitoring', | ||
| 321 | instance: 'Instance Monitoring', | 433 | instance: 'Instance Monitoring', |
| 322 | load: 'Performance Load', | 434 | load: 'Performance Load', |
| 323 | systemConfig: { | 435 | systemConfig: { |
| @@ -346,6 +458,8 @@ export default { | |||
| 346 | createSnapshot: 'Create Snapshot', | 458 | createSnapshot: 'Create Snapshot', |
| 347 | snapshotID: 'Snapshot ID', | 459 | snapshotID: 'Snapshot ID', |
| 348 | captureTime: 'Capture Time', | 460 | captureTime: 'Capture Time', |
| 461 | + startTime: 'Snapshot Start Time', | ||
| 462 | + endTime: 'Snapshot End Time', | ||
| 349 | buildSuccess: | 463 | buildSuccess: |
| 350 | 'Created successfully! There may be a lag in the asynchronous writing of the snapshot list, please refresh the list manually!', | 464 | 'Created successfully! There may be a lag in the asynchronous writing of the snapshot list, please refresh the list manually!', |
| 351 | }, | 465 | }, |
| @@ -355,7 +469,10 @@ export default { | |||
| 355 | build: 'Generate', | 469 | build: 'Generate', |
| 356 | buildSuccess: 'Generate suceed', | 470 | buildSuccess: 'Generate suceed', |
| 357 | buildFail: 'Generate fail', | 471 | buildFail: 'Generate fail', |
| 472 | + startTime: 'Start Time', | ||
| 473 | + endTime: 'End Time', | ||
| 358 | }, | 474 | }, |
| 475 | + wdrErrtip: 'No matching WDR report and corresponding snapshot available for generating WDR report', | ||
| 359 | }, | 476 | }, |
| 360 | session: 'Session Management', | 477 | session: 'Session Management', |
| 361 | slow: 'Slow SQL', | 478 | slow: 'Slow SQL', |
| @@ -21,6 +21,7 @@ export default { | |||
| 21 | confirm: '确定', | 21 | confirm: '确定', |
| 22 | edit: '编辑', | 22 | edit: '编辑', |
| 23 | operate: '操作', | 23 | operate: '操作', |
| 24 | + detail: '详情', | ||
| 24 | view: '查看', | 25 | view: '查看', |
| 25 | download: '下载', | 26 | download: '下载', |
| 26 | reset: '重置', | 27 | reset: '重置', |
| @@ -34,12 +35,106 @@ export default { | |||
| 34 | autoRefreshFor: '自动刷新:', | 35 | autoRefreshFor: '自动刷新:', |
| 35 | needSQLDiagnosis: '请先安装智能诊断插件', | 36 | needSQLDiagnosis: '请先安装智能诊断插件', |
| 36 | diagnosis: '智能诊断', | 37 | diagnosis: '智能诊断', |
| 38 | + all: '全部', | ||
| 39 | + }, | ||
| 40 | + clusterMonitor: { | ||
| 41 | + clusterMonitor: '集群监控', | ||
| 42 | + instanceMonitor: '实例监控', | ||
| 43 | + clusterList: '集群列表', | ||
| 44 | + delayList: '主备延迟列表', | ||
| 45 | + detail: { | ||
| 46 | + title: '集群详情(集群名称=temp)', | ||
| 47 | + info: '集群信息', | ||
| 48 | + instance: { | ||
| 49 | + legend: '图例', | ||
| 50 | + nodeName: '节点名称', | ||
| 51 | + ipPort: 'IP 端口', | ||
| 52 | + role: '角色', | ||
| 53 | + nodeStatus: '节点状态', | ||
| 54 | + syncMode: '同步方式', | ||
| 55 | + syncPriority: '同步优先级', | ||
| 56 | + syncStatus: '同步状态', | ||
| 57 | + receiveDelay: '接收延迟', | ||
| 58 | + diskDelay: '落盘延迟', | ||
| 59 | + replayDelay: '回放延迟', | ||
| 60 | + performanceMonitoring: '性能监控', | ||
| 61 | + memory: '内存', | ||
| 62 | + networkReceive: '网络(接收)', | ||
| 63 | + networkSend: '网络(发送)', | ||
| 64 | + diskRead: '磁盘读', | ||
| 65 | + sqlResponseTime80: '80%的SQL响应时间', | ||
| 66 | + sqlResponseTime95: '95%的SQL响应时间', | ||
| 67 | + primaryWalAccumulation: '主库wal累积量(日)(KB)', | ||
| 68 | + primaryWalSendPressure: '主库wal发送压力(KB)', | ||
| 69 | + primaryWalWriteRate: '主库wal写频率(KB/S)', | ||
| 70 | + standbyReceiveDelay: '备库接收延迟(KB)', | ||
| 71 | + standbyDiskDelay: '备库落盘延迟(KB)', | ||
| 72 | + standbyReplayDelay: '备库回放延迟(KB)', | ||
| 73 | + }, | ||
| 74 | + }, | ||
| 75 | + list: { | ||
| 76 | + name: '集群名称', | ||
| 77 | + state: '集群状态', | ||
| 78 | + stateDesc: '状态说明', | ||
| 79 | + pointCount: '节点数量', | ||
| 80 | + user: '数据库用户', | ||
| 81 | + posrt: '数据库端口', | ||
| 82 | + deploymentMethod: '架构', | ||
| 83 | + deploymentMethodN: '架构:', | ||
| 84 | + faildNodesNum: '故障节点数:', | ||
| 85 | + searchInstanceName: '搜索实例名称', | ||
| 86 | + version: '数据库版本', | ||
| 87 | + versionNum: '版本号', | ||
| 88 | + path: '环境分离文件路径', | ||
| 89 | + noNodeId: '未获取到主节点信息!', | ||
| 90 | + }, | ||
| 91 | + delay: { | ||
| 92 | + nodeName: '节点名称', | ||
| 93 | + nodeStatus: '节点状态', | ||
| 94 | + primaryIpPort: '主库IP 端口', | ||
| 95 | + secondaryIpPort: '备库IP 端口', | ||
| 96 | + syncMode: '同步方式', | ||
| 97 | + syncStatus: '同步状态', | ||
| 98 | + syncModeN: '同步方式:', | ||
| 99 | + syncStatusN: '同步状态:', | ||
| 100 | + syncPriority: '同步优先级', | ||
| 101 | + receiveDelay: '接收延迟', | ||
| 102 | + diskDelay: '落盘延迟', | ||
| 103 | + replayDelay: '回放延迟', | ||
| 104 | + searchNodeName: '搜索节点名称', | ||
| 105 | + }, | ||
| 37 | }, | 106 | }, |
| 38 | instanceMonitor: { | 107 | instanceMonitor: { |
| 39 | instanceMonitor: '实例监控', | 108 | instanceMonitor: '实例监控', |
| 40 | clusterTitle: '集群/实例:', | 109 | clusterTitle: '集群/实例:', |
| 41 | index: '首页', | 110 | index: '首页', |
| 42 | resourceMonitor: '资源监控', | 111 | resourceMonitor: '资源监控', |
| 112 | + thisInstance: ',当前实例', | ||
| 113 | + asp: { | ||
| 114 | + sampleActiveSessionCount: '采样活跃会话数量', | ||
| 115 | + aspAnalysis: 'ASP分析', | ||
| 116 | + analysisMetrics: '分析指标', | ||
| 117 | + filterConditions: '过滤条件', | ||
| 118 | + clickLegendToAddFilter: '单击图例可以增加对应过滤条件', | ||
| 119 | + sampleCount: '采样数量', | ||
| 120 | + activeSessionCount: '活跃会话数量', | ||
| 121 | + }, | ||
| 122 | + nodeInfo: { | ||
| 123 | + instanceInfo: '实例信息', | ||
| 124 | + databaseVersion: '数据库版本:', | ||
| 125 | + databaseStartTime: '数据库开始运行时间:', | ||
| 126 | + databaseDataDirectory: '数据库数据目录:', | ||
| 127 | + databaseLogDirectory: '数据库日志目录:', | ||
| 128 | + enableArchiving: '是否开启归档:', | ||
| 129 | + yes: '是', | ||
| 130 | + no: '否', | ||
| 131 | + operatingSystemVersion: '操作系统版本:', | ||
| 132 | + serverCPUManufacturer: '服务器CPU厂商:', | ||
| 133 | + serverCPUModel: '服务器CPU型号:', | ||
| 134 | + serverCPUCoreCount: '服务器CPU核数:', | ||
| 135 | + cores: '核', | ||
| 136 | + totalMemorySize: '内存总大小:', | ||
| 137 | + }, | ||
| 43 | instance: { | 138 | instance: { |
| 44 | connectionQty: '连接数', | 139 | connectionQty: '连接数', |
| 45 | slowSQL3s: '慢SQL数(大于3秒)', | 140 | slowSQL3s: '慢SQL数(大于3秒)', |
| @@ -74,6 +169,7 @@ export default { | |||
| 74 | usedMemory: '已用内存', | 169 | usedMemory: '已用内存', |
| 75 | freeMemory: '空闲内存', | 170 | freeMemory: '空闲内存', |
| 76 | cachedMemory: '缓存的内存', | 171 | cachedMemory: '缓存的内存', |
| 172 | + dbMemory: '数据库占用内存', | ||
| 77 | interactiveAreaUsage: '交互区使用情况', | 173 | interactiveAreaUsage: '交互区使用情况', |
| 78 | totalExchangeArea: '交换区总量', | 174 | totalExchangeArea: '交换区总量', |
| 79 | ysedSwapArea: '已用交换区', | 175 | ysedSwapArea: '已用交换区', |
| @@ -119,6 +215,7 @@ export default { | |||
| 119 | costTime: '耗时(s)', | 215 | costTime: '耗时(s)', |
| 120 | sessionId: '会话ID', | 216 | sessionId: '会话ID', |
| 121 | detail: '详情', | 217 | detail: '详情', |
| 218 | + wdrAnalysis: 'WDR分析', | ||
| 122 | }, | 219 | }, |
| 123 | trans: { | 220 | trans: { |
| 124 | longTransaction: '长事务', | 221 | longTransaction: '长事务', |
| @@ -153,6 +250,20 @@ export default { | |||
| 153 | clientIP: '客户端IP', | 250 | clientIP: '客户端IP', |
| 154 | appName: '应用名称', | 251 | appName: '应用名称', |
| 155 | }, | 252 | }, |
| 253 | + waitEventTab: { | ||
| 254 | + title: '等待事件', | ||
| 255 | + blockSessionid: '阻塞会话ID', | ||
| 256 | + dbName: '数据库名称', | ||
| 257 | + lockmode: '锁模式', | ||
| 258 | + locktag: '锁信息', | ||
| 259 | + nodeName: '节点名称', | ||
| 260 | + queryId: '查询ID', | ||
| 261 | + sessionid: '会话ID', | ||
| 262 | + threadName: '线程名称', | ||
| 263 | + tid: '线程号', | ||
| 264 | + waitEvent: '等待事件', | ||
| 265 | + waitStatus: '等待状态', | ||
| 266 | + }, | ||
| 156 | trans: { | 267 | trans: { |
| 157 | longTransaction: '长事务', | 268 | longTransaction: '长事务', |
| 158 | sessionID: '会话ID', | 269 | sessionID: '会话ID', |
| @@ -308,6 +419,7 @@ export default { | |||
| 308 | '数据库活动会话数', | 419 | '数据库活动会话数', |
| 309 | '数据库阻塞会话数', | 420 | '数据库阻塞会话数', |
| 310 | ], | 421 | ], |
| 422 | + clusters: '集群监控', | ||
| 311 | instance: '实例监控', | 423 | instance: '实例监控', |
| 312 | load: '系统负载', | 424 | load: '系统负载', |
| 313 | systemConfig: { | 425 | systemConfig: { |
| @@ -336,6 +448,8 @@ export default { | |||
| 336 | createSnapshot: '创建快照', | 448 | createSnapshot: '创建快照', |
| 337 | snapshotID: '快照ID', | 449 | snapshotID: '快照ID', |
| 338 | captureTime: '捕获时间', | 450 | captureTime: '捕获时间', |
| 451 | + startTime: '快照开始时间', | ||
| 452 | + endTime: '快照结束时间', | ||
| 339 | buildSuccess: '创建成功!快照列表异步写入可能存在滞后,请手动刷新列表!', | 453 | buildSuccess: '创建成功!快照列表异步写入可能存在滞后,请手动刷新列表!', |
| 340 | }, | 454 | }, |
| 341 | buildWDRDialog: { | 455 | buildWDRDialog: { |
| @@ -344,7 +458,10 @@ export default { | |||
| 344 | build: '生成', | 458 | build: '生成', |
| 345 | buildSuccess: 'WDR生成成功', | 459 | buildSuccess: 'WDR生成成功', |
| 346 | buildFail: 'WDR生成失败', | 460 | buildFail: 'WDR生成失败', |
| 461 | + startTime: '开始时间', | ||
| 462 | + endTime: '结束时间', | ||
| 347 | }, | 463 | }, |
| 464 | + wdrErrtip: '没有匹配的WDR报告和可生成WDR报告的相应快照', | ||
| 348 | }, | 465 | }, |
| 349 | session: '会话管理', | 466 | session: '会话管理', |
| 350 | slow: '慢SQL', | 467 | slow: '慢SQL', |
| @@ -0,0 +1,335 @@ | |||
| 1 | +<template> | ||
| 2 | + <cluster ref="clusterRef" v-if="indexs.showingComponent == 'cluster'" @goback="backToHome"></cluster> | ||
| 3 | + <div class="tab-wrapper" v-show="indexs.showingComponent == 'list'"> | ||
| 4 | + <el-container> | ||
| 5 | + <el-main style="position: relative; padding-top: 0px" class="padding-fix"> | ||
| 6 | + <div class="page-header" style="padding-left: 20px"> | ||
| 7 | + <div class="icon"></div> | ||
| 8 | + <div class="title">{{ $t('clusterMonitor.clusterMonitor') }}</div> | ||
| 9 | + <div class="seperator"></div> | ||
| 10 | + <el-breadcrumb separator="/" style="flex-grow: 1"> | ||
| 11 | + <el-breadcrumb-item :to="{ path: '/vem/dashboard/clusters' }">{{ | ||
| 12 | + $t('clusterMonitor.clusterMonitor') | ||
| 13 | + }}</el-breadcrumb-item> | ||
| 14 | + </el-breadcrumb> | ||
| 15 | + | ||
| 16 | + <el-button | ||
| 17 | + class="refresh-button" | ||
| 18 | + type="primary" | ||
| 19 | + :icon="Refresh" | ||
| 20 | + style="padding: 8px" | ||
| 21 | + @click="autoRefreshFn" | ||
| 22 | + /> | ||
| 23 | + </div> | ||
| 24 | + | ||
| 25 | + <div class="main-container"> | ||
| 26 | + <el-tabs v-model="dashboardTabKey" class="index-tabs" @tab-change="tabChange"> | ||
| 27 | + <el-tab-pane class="min-height" :label="$t('clusterMonitor.clusterList')" name="clusterList"> | ||
| 28 | + <div class="filter-bar"> | ||
| 29 | + <div class="item"> | ||
| 30 | + <div style="white-space: nowrap">{{ $t('clusterMonitor.list.deploymentMethodN') }}</div> | ||
| 31 | + <el-select v-model="selectedArch" style="width: 130px; margin: 0 4px"> | ||
| 32 | + <el-option :value="''" :label="$t('app.all')" /> | ||
| 33 | + <el-option v-for="item in archSelections" :key="item" :value="item" :label="item" /> | ||
| 34 | + </el-select> | ||
| 35 | + </div> | ||
| 36 | + <div class="item"> | ||
| 37 | + <el-input | ||
| 38 | + v-model="searchText" | ||
| 39 | + :placeholder="$t('clusterMonitor.list.searchInstanceName')" | ||
| 40 | + :suffix-icon="Search" | ||
| 41 | + style="width: 268px" | ||
| 42 | + /> | ||
| 43 | + </div> | ||
| 44 | + </div> | ||
| 45 | + <el-table | ||
| 46 | + :table-layout="'auto'" | ||
| 47 | + :data="filterClusters" | ||
| 48 | + style="width: 100%" | ||
| 49 | + border | ||
| 50 | + :header-cell-class-name=" | ||
| 51 | + () => { | ||
| 52 | + return 'grid-header' | ||
| 53 | + } | ||
| 54 | + " | ||
| 55 | + v-loading="loading" | ||
| 56 | + > | ||
| 57 | + <el-table-column :label="$t('clusterMonitor.list.name')" width="200"> | ||
| 58 | + <template #default="scope"> | ||
| 59 | + <el-link size="small" type="primary" @click="gotoCluster(scope.row)">{{ | ||
| 60 | + scope.row.clusterId | ||
| 61 | + }}</el-link> | ||
| 62 | + </template> | ||
| 63 | + </el-table-column> | ||
| 64 | + <el-table-column prop="clusterState.value" :label="$t('clusterMonitor.list.state')" width="130"> | ||
| 65 | + <template #default="scope"> | ||
| 66 | + <div class="state-row"> | ||
| 67 | + <div class="state" :class="[scope.row.clusterState?.color?.toLowerCase()]"></div> | ||
| 68 | + {{ scope.row.clusterState?.value }} | ||
| 69 | + </div> | ||
| 70 | + </template> | ||
| 71 | + </el-table-column> | ||
| 72 | + <el-table-column prop="nodeCount" :label="$t('clusterMonitor.list.pointCount')" width="100" /> | ||
| 73 | + <el-table-column prop="arch" :label="$t('clusterMonitor.list.deploymentMethod')" width="100" /> | ||
| 74 | + <el-table-column prop="version" :label="$t('clusterMonitor.list.version')" width="130"> | ||
| 75 | + <template #default="scope"> {{ scope.row.version }} {{ scope.row.versionNum }} </template> | ||
| 76 | + </el-table-column> | ||
| 77 | + <el-table-column prop="desc" :label="$t('clusterMonitor.list.stateDesc')" show-overflow-tooltip /> | ||
| 78 | + <el-table-column :label="$t('app.operate')" align="center" fixed="right" width="80"> | ||
| 79 | + <template #default="scope"> | ||
| 80 | + <el-link size="small" type="primary" @click="gotoInstance(scope.row)" | ||
| 81 | + >{{ $t('clusterMonitor.instanceMonitor') }} | ||
| 82 | + </el-link> | ||
| 83 | + </template> | ||
| 84 | + </el-table-column> | ||
| 85 | + </el-table> | ||
| 86 | + </el-tab-pane> | ||
| 87 | + <el-tab-pane class="min-height" :label="$t('clusterMonitor.delayList')" name="delayList"> | ||
| 88 | + <div class="filter-bar"> | ||
| 89 | + <div class="item"> | ||
| 90 | + <div style="white-space: nowrap">{{ $t('clusterMonitor.delay.syncModeN') }}</div> | ||
| 91 | + <el-select v-model="selectedSyncMode" style="width: 130px; margin: 0 4px"> | ||
| 92 | + <el-option :value="''" :label="$t('app.all')" /> | ||
| 93 | + <el-option v-for="item in syncWaySelections" :key="item" :value="item" :label="item" /> | ||
| 94 | + </el-select> | ||
| 95 | + </div> | ||
| 96 | + <div class="item"> | ||
| 97 | + <div style="white-space: nowrap">{{ $t('clusterMonitor.delay.syncStatusN') }}</div> | ||
| 98 | + <el-select v-model="selectedSyncStatus" style="width: 130px; margin: 0 4px"> | ||
| 99 | + <el-option :value="''" :label="$t('app.all')" /> | ||
| 100 | + <el-option v-for="item in syncStateSelections" :key="item" :value="item" :label="item" /> | ||
| 101 | + </el-select> | ||
| 102 | + </div> | ||
| 103 | + <div class="item"> | ||
| 104 | + <el-input | ||
| 105 | + v-model="syncSearchText" | ||
| 106 | + :placeholder="$t('clusterMonitor.list.searchInstanceName')" | ||
| 107 | + :suffix-icon="Search" | ||
| 108 | + style="width: 268px" | ||
| 109 | + /> | ||
| 110 | + </div> | ||
| 111 | + </div> | ||
| 112 | + | ||
| 113 | + <el-table | ||
| 114 | + :table-layout="'auto'" | ||
| 115 | + :data="filterNodes" | ||
| 116 | + style="width: 100%" | ||
| 117 | + border | ||
| 118 | + :header-cell-class-name=" | ||
| 119 | + () => { | ||
| 120 | + return 'grid-header' | ||
| 121 | + } | ||
| 122 | + " | ||
| 123 | + v-loading="loadingNodes" | ||
| 124 | + > | ||
| 125 | + <el-table-column :label="$t('clusterMonitor.delay.nodeName')"> | ||
| 126 | + <template #default="scope"> | ||
| 127 | + <el-link size="small" type="primary" @click="gotoCluster(scope.row)">{{ | ||
| 128 | + scope.row.nodeName | ||
| 129 | + }}</el-link> | ||
| 130 | + </template> | ||
| 131 | + </el-table-column> | ||
| 132 | + <el-table-column prop="nodeState.value" :label="$t('clusterMonitor.delay.nodeStatus')" width="80"> | ||
| 133 | + <template #default="scope"> | ||
| 134 | + <div class="state-row"> | ||
| 135 | + <div class="state" :class="[scope.row.nodeState?.color?.toLowerCase()]"></div> | ||
| 136 | + {{ scope.row.nodeState?.value }} | ||
| 137 | + </div> | ||
| 138 | + </template> | ||
| 139 | + </el-table-column> | ||
| 140 | + <el-table-column prop="primaryAddr" :label="$t('clusterMonitor.delay.primaryIpPort')" width="140" /> | ||
| 141 | + <el-table-column prop="localAddr" :label="$t('clusterMonitor.delay.secondaryIpPort')" width="140" /> | ||
| 142 | + <el-table-column prop="sync" :label="$t('clusterMonitor.delay.syncMode')" width="80" /> | ||
| 143 | + <el-table-column prop="syncState.value" :label="$t('clusterMonitor.delay.syncStatus')" width="80"> | ||
| 144 | + <template #default="scope"> | ||
| 145 | + <div class="state-row"> | ||
| 146 | + <div class="state" :class="[scope.row.syncState?.color?.toLowerCase()]"></div> | ||
| 147 | + {{ scope.row.syncState?.value }} | ||
| 148 | + </div> | ||
| 149 | + </template> | ||
| 150 | + </el-table-column> | ||
| 151 | + <el-table-column prop="syncPriority" :label="$t('clusterMonitor.delay.syncPriority')" width="80" /> | ||
| 152 | + <el-table-column prop="receivedDelay" :label="$t('clusterMonitor.delay.receiveDelay')" width="100" /> | ||
| 153 | + <el-table-column prop="writeDelay" :label="$t('clusterMonitor.delay.diskDelay')" width="100" /> | ||
| 154 | + <el-table-column prop="replayDelay" :label="$t('clusterMonitor.delay.replayDelay')" width="100" /> | ||
| 155 | + <el-table-column :label="$t('app.operate')" align="center" fixed="right" width="80"> | ||
| 156 | + <template #default="scope"> | ||
| 157 | + <el-link size="small" type="primary" @click="gotoInstance(scope.row)" | ||
| 158 | + >{{ $t('clusterMonitor.instanceMonitor') }} | ||
| 159 | + </el-link> | ||
| 160 | + </template> | ||
| 161 | + </el-table-column> | ||
| 162 | + </el-table> | ||
| 163 | + </el-tab-pane> | ||
| 164 | + </el-tabs> | ||
| 165 | + </div> | ||
| 166 | + </el-main> | ||
| 167 | + </el-container> | ||
| 168 | + </div> | ||
| 169 | +</template> | ||
| 170 | + | ||
| 171 | +<script setup lang="ts"> | ||
| 172 | +import { ref } from 'vue' | ||
| 173 | +import { useRequest } from 'vue-request' | ||
| 174 | +import { ClusterListItem, getAllClusters, getAllClustersStates, getAllNodes, NodeStateItem } from '@/api/cluster' | ||
| 175 | +import { Search, Refresh } from '@element-plus/icons-vue' | ||
| 176 | +import Cluster from '@/pages/clusterMonitor/cluster/Index.vue' | ||
| 177 | +import router from '@/router' | ||
| 178 | +import type { TabPanelName } from 'element-plus' | ||
| 179 | +import { ElMessage } from 'element-plus' | ||
| 180 | +import { useI18n } from 'vue-i18n' | ||
| 181 | +const { t } = useI18n() | ||
| 182 | +const clusterRef = ref() | ||
| 183 | +const dashboardTabKey = ref<string>('clusterList') | ||
| 184 | +const selectedArch = ref<string>('') | ||
| 185 | +const selectedSyncMode = ref<string>('') | ||
| 186 | +const selectedSyncStatus = ref<string>('') | ||
| 187 | +const searchText = ref<string>('') | ||
| 188 | +const syncSearchText = ref<string>('') | ||
| 189 | +const indexs = ref<any>({ listOpened: true, clusterOpened: false, showingComponent: 'list' }) | ||
| 190 | +const clusterData = ref<void | ClusterListItem[]>([]) | ||
| 191 | +const nodeData = ref<void | NodeStateItem[]>([]) | ||
| 192 | + | ||
| 193 | +onMounted(() => { | ||
| 194 | + loadAllClusters() | ||
| 195 | +}) | ||
| 196 | +const gotoCluster = (row: any) => { | ||
| 197 | + indexs.value.clusterOpened = true | ||
| 198 | + indexs.value.showingComponent = 'cluster' | ||
| 199 | + nextTick(() => { | ||
| 200 | + clusterRef.value!.goInto(row) | ||
| 201 | + }) | ||
| 202 | +} | ||
| 203 | +const backToHome = () => { | ||
| 204 | + indexs.value.showingComponent = 'list' | ||
| 205 | +} | ||
| 206 | +const autoRefreshFn = () => { | ||
| 207 | + if (indexs.value.showingComponent === 'list') { | ||
| 208 | + if (dashboardTabKey.value === 'clusterList') { | ||
| 209 | + loadAllClusters() | ||
| 210 | + } | ||
| 211 | + if (dashboardTabKey.value === 'delayList') { | ||
| 212 | + loadAllNodes() | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | +} | ||
| 216 | +const gotoInstance = (row: any) => { | ||
| 217 | + let nodeId = row.nodeId | ||
| 218 | + if (!nodeId) { | ||
| 219 | + ElMessage({ | ||
| 220 | + showClose: true, | ||
| 221 | + message: t('clusterMonitor.list.noNodeId'), | ||
| 222 | + type: 'warning', | ||
| 223 | + }) | ||
| 224 | + return | ||
| 225 | + } | ||
| 226 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 227 | + if (curMode === 'wujie') { | ||
| 228 | + // @ts-ignore plug-in components | ||
| 229 | + window.$wujie?.props.methods.jump({ | ||
| 230 | + name: `Static-pluginObservability-instanceVemDashboardInstance`, | ||
| 231 | + query: { | ||
| 232 | + nodeId, | ||
| 233 | + }, | ||
| 234 | + }) | ||
| 235 | + } else { | ||
| 236 | + // local | ||
| 237 | + router.push({ path: `/vem/dashboard/instance`, query: { nodeId } }) | ||
| 238 | + } | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +const tabChange = (tab: TabPanelName) => { | ||
| 242 | + if (tab === 'clusterList' && clusterData.value?.length === 0) { | ||
| 243 | + loadAllClusters() | ||
| 244 | + } | ||
| 245 | + if (tab === 'delayList' && nodeData.value?.length === 0) { | ||
| 246 | + loadAllNodes() | ||
| 247 | + } | ||
| 248 | +} | ||
| 249 | + | ||
| 250 | +const archSelections = computed(() => { | ||
| 251 | + const result: string[] = Array.from(new Set(clusterData.value?.map((obj: ClusterListItem) => obj.arch))) | ||
| 252 | + return result | ||
| 253 | +}) | ||
| 254 | +const syncWaySelections = computed(() => { | ||
| 255 | + const result: string[] = Array.from(new Set(nodeData.value?.map((obj: NodeStateItem) => obj.sync))) | ||
| 256 | + return result | ||
| 257 | +}) | ||
| 258 | +const syncStateSelections = computed(() => { | ||
| 259 | + const result: string[] = Array.from(new Set(nodeData.value?.map((obj: NodeStateItem) => obj.syncState.value))) | ||
| 260 | + return result | ||
| 261 | +}) | ||
| 262 | + | ||
| 263 | +const filterClusters = computed(() => { | ||
| 264 | + return clusterData.value?.filter((obj: ClusterListItem) => { | ||
| 265 | + let result = true | ||
| 266 | + if (selectedArch.value !== '' && obj.arch !== selectedArch.value) result = false | ||
| 267 | + if (searchText.value !== '' && obj.clusterId.indexOf(searchText.value) < 0) result = false | ||
| 268 | + return result | ||
| 269 | + }) | ||
| 270 | +}) | ||
| 271 | + | ||
| 272 | +const filterNodes = computed(() => { | ||
| 273 | + return nodeData.value?.filter((obj: NodeStateItem) => { | ||
| 274 | + let result = true | ||
| 275 | + if (selectedSyncMode.value !== '' && obj.sync !== selectedSyncMode.value) result = false | ||
| 276 | + if (selectedSyncStatus.value !== '' && obj.syncState.value !== selectedSyncStatus.value) result = false | ||
| 277 | + if (syncSearchText.value !== '' && obj.nodeName.indexOf(syncSearchText.value) < 0) result = false | ||
| 278 | + return result | ||
| 279 | + }) | ||
| 280 | +}) | ||
| 281 | + | ||
| 282 | +const { | ||
| 283 | + data: allClusters, | ||
| 284 | + run: loadAllClusters, | ||
| 285 | + loading, | ||
| 286 | +} = useRequest( | ||
| 287 | + () => { | ||
| 288 | + clusterData.value = [] | ||
| 289 | + return getAllClusters() | ||
| 290 | + }, | ||
| 291 | + { manual: true } | ||
| 292 | +) | ||
| 293 | +watch(allClusters, () => { | ||
| 294 | + if (!allClusters.value) return | ||
| 295 | + clusterData.value = allClusters.value | ||
| 296 | + loadAllClustersStates() | ||
| 297 | +}) | ||
| 298 | +const { data: allClusterStates, run: loadAllClustersStates } = useRequest(getAllClustersStates, { manual: true }) | ||
| 299 | +watch( | ||
| 300 | + allClusterStates, | ||
| 301 | + () => { | ||
| 302 | + if (!allClusterStates.value) return | ||
| 303 | + allClusterStates.value.forEach((objA) => { | ||
| 304 | + const matchedObjB = clusterData.value?.find((objB) => objB.clusterId === objA.clusterId) | ||
| 305 | + if (matchedObjB) { | ||
| 306 | + matchedObjB.clusterState = objA.clusterState | ||
| 307 | + matchedObjB.desc = objA.desc | ||
| 308 | + matchedObjB.nodeId = objA.primaryNodeId | ||
| 309 | + } | ||
| 310 | + }) | ||
| 311 | + }, | ||
| 312 | + { deep: true } | ||
| 313 | +) | ||
| 314 | +const { | ||
| 315 | + data: allNodes, | ||
| 316 | + run: loadAllNodes, | ||
| 317 | + loading: loadingNodes, | ||
| 318 | +} = useRequest( | ||
| 319 | + () => { | ||
| 320 | + nodeData.value = [] | ||
| 321 | + return getAllNodes() | ||
| 322 | + }, | ||
| 323 | + { manual: true } | ||
| 324 | +) | ||
| 325 | +watch( | ||
| 326 | + allNodes, | ||
| 327 | + () => { | ||
| 328 | + if (!allNodes.value) return | ||
| 329 | + nodeData.value = allNodes.value | ||
| 330 | + }, | ||
| 331 | + { deep: true } | ||
| 332 | +) | ||
| 333 | +</script> | ||
| 334 | + | ||
| 335 | +<style scoped lang="scss"></style> | ||
| @@ -0,0 +1,595 @@ | |||
| 1 | +<template> | ||
| 2 | + <div class="tab-wrapper"> | ||
| 3 | + <el-container> | ||
| 4 | + <el-main style="position: relative; padding-top: 0px" class="padding-fix"> | ||
| 5 | + <div class="page-header" style="padding-left: 20px"> | ||
| 6 | + <div class="icon"></div> | ||
| 7 | + <div class="title">{{ $t('clusterMonitor.clusterMonitor') }}</div> | ||
| 8 | + <div class="seperator"></div> | ||
| 9 | + <el-breadcrumb separator="/" style="flex-grow: 1"> | ||
| 10 | + <el-breadcrumb-item> | ||
| 11 | + <div @click="goback"> | ||
| 12 | + <a>{{ $t('clusterMonitor.clusterMonitor') }}</a> | ||
| 13 | + </div> | ||
| 14 | + </el-breadcrumb-item> | ||
| 15 | + <el-breadcrumb-item>{{ | ||
| 16 | + $t('clusterMonitor.detail.title').replace('temp', clusterRow.clusterId) | ||
| 17 | + }}</el-breadcrumb-item> | ||
| 18 | + </el-breadcrumb> | ||
| 19 | + | ||
| 20 | + <el-button | ||
| 21 | + class="refresh-button" | ||
| 22 | + type="primary" | ||
| 23 | + :icon="Refresh" | ||
| 24 | + style="padding: 8px" | ||
| 25 | + @click="loadClusterNodes(clusterRow.clusterId)" | ||
| 26 | + /> | ||
| 27 | + </div> | ||
| 28 | + | ||
| 29 | + <div class="main-container"> | ||
| 30 | + <my-card :title="$t('clusterMonitor.detail.info')" :bodyPadding="false" skipBodyHeight> | ||
| 31 | + <el-table | ||
| 32 | + :data="clusterNodesData" | ||
| 33 | + style="width: 100%" | ||
| 34 | + border | ||
| 35 | + :header-cell-class-name=" | ||
| 36 | + () => { | ||
| 37 | + return 'grid-header' | ||
| 38 | + } | ||
| 39 | + " | ||
| 40 | + @selection-change="selectionChange" | ||
| 41 | + v-loading="loadingNodes" | ||
| 42 | + > | ||
| 43 | + <el-table-column | ||
| 44 | + type="selection" | ||
| 45 | + prop="xxxx" | ||
| 46 | + :label="$t('clusterMonitor.detail.instance.legend')" | ||
| 47 | + align="center" | ||
| 48 | + width="40" | ||
| 49 | + /> | ||
| 50 | + <el-table-column :label="$t('clusterMonitor.detail.instance.legend')" align="center" width="50"> | ||
| 51 | + <template #default="scope"> | ||
| 52 | + <div style="width: 100%; display: flex; flex-direction: row; justify-content: center"> | ||
| 53 | + <div | ||
| 54 | + style="width: 12px; height: 12px; border-radius: 2px" | ||
| 55 | + :style="{ background: scope.row.color }" | ||
| 56 | + ></div> | ||
| 57 | + </div> | ||
| 58 | + </template> | ||
| 59 | + </el-table-column> | ||
| 60 | + <el-table-column prop="nodeName" :label="$t('clusterMonitor.detail.instance.nodeName')" /> | ||
| 61 | + <el-table-column prop="localAddr" :label="$t('clusterMonitor.detail.instance.ipPort')" width="140" /> | ||
| 62 | + <el-table-column prop="role" :label="$t('clusterMonitor.detail.instance.role')" width="60" /> | ||
| 63 | + <el-table-column | ||
| 64 | + prop="nodeState.value" | ||
| 65 | + :label="$t('clusterMonitor.detail.instance.nodeStatus')" | ||
| 66 | + width="80" | ||
| 67 | + > | ||
| 68 | + <template #default="scope"> | ||
| 69 | + <div class="state-row"> | ||
| 70 | + <div class="state" :class="[scope.row.nodeState?.color?.toLowerCase()]"></div> | ||
| 71 | + {{ scope.row.nodeState?.value }} | ||
| 72 | + </div> | ||
| 73 | + </template> | ||
| 74 | + </el-table-column> | ||
| 75 | + <el-table-column prop="cmServerState.value" label="CM_server" width="90"> | ||
| 76 | + <template #default="scope"> | ||
| 77 | + <div class="state-row"> | ||
| 78 | + <div class="state" :class="[scope.row.cmServerState?.color?.toLowerCase()]"></div> | ||
| 79 | + {{ scope.row.cmServerState?.value }} | ||
| 80 | + </div> | ||
| 81 | + </template> | ||
| 82 | + </el-table-column> | ||
| 83 | + <el-table-column prop="omMonitorState.value" label="OM_moniter" width="100"> | ||
| 84 | + <template #default="scope"> | ||
| 85 | + <div class="state-row"> | ||
| 86 | + <div class="state" :class="[scope.row.omMonitorState?.color?.toLowerCase()]"></div> | ||
| 87 | + {{ scope.row.omMonitorState?.value }} | ||
| 88 | + </div> | ||
| 89 | + </template> | ||
| 90 | + </el-table-column> | ||
| 91 | + <el-table-column prop="cmAgentState.value" label="CM_agent" width="80"> | ||
| 92 | + <template #default="scope"> | ||
| 93 | + <div class="state-row"> | ||
| 94 | + <div class="state" :class="[scope.row.cmAgentState?.color?.toLowerCase()]"></div> | ||
| 95 | + {{ scope.row.cmAgentState?.value }} | ||
| 96 | + </div> | ||
| 97 | + </template> | ||
| 98 | + </el-table-column> | ||
| 99 | + <el-table-column prop="sync" :label="$t('clusterMonitor.detail.instance.syncMode')" width="80" /> | ||
| 100 | + <el-table-column | ||
| 101 | + prop="syncPriority" | ||
| 102 | + :label="$t('clusterMonitor.detail.instance.syncPriority')" | ||
| 103 | + width="80" | ||
| 104 | + /> | ||
| 105 | + | ||
| 106 | + <el-table-column | ||
| 107 | + prop="syncState.value" | ||
| 108 | + :label="$t('clusterMonitor.detail.instance.syncStatus')" | ||
| 109 | + width="80" | ||
| 110 | + > | ||
| 111 | + <template #default="scope"> | ||
| 112 | + <div class="state-row"> | ||
| 113 | + <div class="state" :class="[scope.row.syncState?.color?.toLowerCase()]"></div> | ||
| 114 | + {{ scope.row.syncState?.value }} | ||
| 115 | + </div> | ||
| 116 | + </template> | ||
| 117 | + </el-table-column> | ||
| 118 | + <el-table-column | ||
| 119 | + prop="receivedDelay" | ||
| 120 | + :label="$t('clusterMonitor.detail.instance.receiveDelay')" | ||
| 121 | + width="80" | ||
| 122 | + /> | ||
| 123 | + <el-table-column prop="writeDelay" :label="$t('clusterMonitor.detail.instance.diskDelay')" width="80" /> | ||
| 124 | + <el-table-column | ||
| 125 | + prop="replayDelay" | ||
| 126 | + :label="$t('clusterMonitor.detail.instance.replayDelay')" | ||
| 127 | + width="80" | ||
| 128 | + /> | ||
| 129 | + <el-table-column :label="$t('app.operate')" align="center" fixed="right" width="80"> | ||
| 130 | + <template #default="scope"> | ||
| 131 | + <el-link size="small" type="primary" @click="gotoInstance(scope.row)">{{ | ||
| 132 | + $t('clusterMonitor.detail.instance.performanceMonitoring') | ||
| 133 | + }}</el-link> | ||
| 134 | + </template> | ||
| 135 | + </el-table-column> | ||
| 136 | + </el-table> | ||
| 137 | + | ||
| 138 | + <div style="padding: 12px" v-loading="loading"> | ||
| 139 | + <el-row :gutter="12"> | ||
| 140 | + <el-col :span="6"> | ||
| 141 | + <my-card :title="'CPU'" height="200" :bodyPadding="false"> | ||
| 142 | + <LazyLine | ||
| 143 | + :tabId="tabId" | ||
| 144 | + :formatter="toFixed" | ||
| 145 | + :data="metricsData.cpu" | ||
| 146 | + :xData="metricsData.time" | ||
| 147 | + :legendShown="false" | ||
| 148 | + :tool-tips-sort="'desc'" | ||
| 149 | + :tool-tips-exclude-zero="true" | ||
| 150 | + :max="100" | ||
| 151 | + :min="0" | ||
| 152 | + :interval="25" | ||
| 153 | + :unit="'%'" | ||
| 154 | + /> | ||
| 155 | + </my-card> | ||
| 156 | + </el-col> | ||
| 157 | + <el-col :span="6"> | ||
| 158 | + <my-card :title="$t('clusterMonitor.detail.instance.memory')" height="200" :bodyPadding="false"> | ||
| 159 | + <LazyLine | ||
| 160 | + :tabId="tabId" | ||
| 161 | + :formatter="toFixed" | ||
| 162 | + :data="metricsData.memory" | ||
| 163 | + :xData="metricsData.time" | ||
| 164 | + :legendShown="false" | ||
| 165 | + :tool-tips-sort="'desc'" | ||
| 166 | + :tool-tips-exclude-zero="true" | ||
| 167 | + :max="100" | ||
| 168 | + :min="0" | ||
| 169 | + :interval="25" | ||
| 170 | + :unit="'%'" | ||
| 171 | + /> | ||
| 172 | + </my-card> | ||
| 173 | + </el-col> | ||
| 174 | + <el-col :span="6"> | ||
| 175 | + <my-card | ||
| 176 | + :title="$t('clusterMonitor.detail.instance.networkReceive')" | ||
| 177 | + height="200" | ||
| 178 | + :bodyPadding="false" | ||
| 179 | + > | ||
| 180 | + <LazyLine | ||
| 181 | + :tabId="tabId" | ||
| 182 | + :formatter="toFixed" | ||
| 183 | + :data="metricsData.networkIn" | ||
| 184 | + :xData="metricsData.time" | ||
| 185 | + :legendShown="false" | ||
| 186 | + :tool-tips-sort="'desc'" | ||
| 187 | + :tool-tips-exclude-zero="true" | ||
| 188 | + :unit="'M/S'" | ||
| 189 | + /> | ||
| 190 | + </my-card> | ||
| 191 | + </el-col> | ||
| 192 | + <el-col :span="6"> | ||
| 193 | + <my-card :title="$t('clusterMonitor.detail.instance.networkSend')" height="200" :bodyPadding="false"> | ||
| 194 | + <LazyLine | ||
| 195 | + :tabId="tabId" | ||
| 196 | + :formatter="toFixed" | ||
| 197 | + :data="metricsData.networkOut" | ||
| 198 | + :xData="metricsData.time" | ||
| 199 | + :legendShown="false" | ||
| 200 | + :tool-tips-sort="'desc'" | ||
| 201 | + :tool-tips-exclude-zero="true" | ||
| 202 | + :unit="'M/S'" | ||
| 203 | + /> | ||
| 204 | + </my-card> | ||
| 205 | + </el-col> | ||
| 206 | + </el-row> | ||
| 207 | + | ||
| 208 | + <div class="gap-row"></div> | ||
| 209 | + <el-row :gutter="12"> | ||
| 210 | + <el-col :span="6"> | ||
| 211 | + <my-card :title="$t('clusterMonitor.detail.instance.diskRead')" height="200" :bodyPadding="false"> | ||
| 212 | + <LazyLine | ||
| 213 | + :tabId="tabId" | ||
| 214 | + :formatter="toFixed" | ||
| 215 | + :data="metricsData.io" | ||
| 216 | + :xData="metricsData.time" | ||
| 217 | + :legendShown="false" | ||
| 218 | + :tool-tips-sort="'desc'" | ||
| 219 | + :tool-tips-exclude-zero="true" | ||
| 220 | + :unit="'B'" | ||
| 221 | + /> | ||
| 222 | + </my-card> | ||
| 223 | + </el-col> | ||
| 224 | + <el-col :span="6"> | ||
| 225 | + <my-card :title="'QPS'" height="200" :bodyPadding="false"> | ||
| 226 | + <LazyLine | ||
| 227 | + :tabId="tabId" | ||
| 228 | + :formatter="toFixed" | ||
| 229 | + :data="metricsData.qps" | ||
| 230 | + :xData="metricsData.time" | ||
| 231 | + :legendShown="false" | ||
| 232 | + :tool-tips-sort="'desc'" | ||
| 233 | + :tool-tips-exclude-zero="true" | ||
| 234 | + /> | ||
| 235 | + </my-card> | ||
| 236 | + </el-col> | ||
| 237 | + <el-col :span="6"> | ||
| 238 | + <my-card | ||
| 239 | + :title="$t('clusterMonitor.detail.instance.sqlResponseTime80')" | ||
| 240 | + height="200" | ||
| 241 | + :bodyPadding="false" | ||
| 242 | + > | ||
| 243 | + <LazyLine | ||
| 244 | + :tabId="tabId" | ||
| 245 | + :formatter="toFixed" | ||
| 246 | + :data="metricsData.sql80" | ||
| 247 | + :xData="metricsData.time" | ||
| 248 | + :legendShown="false" | ||
| 249 | + :tool-tips-sort="'desc'" | ||
| 250 | + :tool-tips-exclude-zero="true" | ||
| 251 | + :unit="'ms'" | ||
| 252 | + /> | ||
| 253 | + </my-card> | ||
| 254 | + </el-col> | ||
| 255 | + <el-col :span="6"> | ||
| 256 | + <my-card | ||
| 257 | + :title="$t('clusterMonitor.detail.instance.sqlResponseTime95')" | ||
| 258 | + height="200" | ||
| 259 | + :bodyPadding="false" | ||
| 260 | + > | ||
| 261 | + <LazyLine | ||
| 262 | + :tabId="tabId" | ||
| 263 | + :formatter="toFixed" | ||
| 264 | + :data="metricsData.sql95" | ||
| 265 | + :xData="metricsData.time" | ||
| 266 | + :legendShown="false" | ||
| 267 | + :tool-tips-sort="'desc'" | ||
| 268 | + :tool-tips-exclude-zero="true" | ||
| 269 | + :unit="'ms'" | ||
| 270 | + /> | ||
| 271 | + </my-card> | ||
| 272 | + </el-col> | ||
| 273 | + </el-row> | ||
| 274 | + | ||
| 275 | + <div class="gap-row"></div> | ||
| 276 | + <el-row :gutter="12"> | ||
| 277 | + <el-col :span="8"> | ||
| 278 | + <my-card | ||
| 279 | + :title="$t('clusterMonitor.detail.instance.primaryWalAccumulation')" | ||
| 280 | + height="200" | ||
| 281 | + :bodyPadding="false" | ||
| 282 | + > | ||
| 283 | + <LazyLine | ||
| 284 | + :tabId="tabId" | ||
| 285 | + :formatter="toFixed" | ||
| 286 | + :data="metricsData.writeTotal" | ||
| 287 | + :xData="metricsData.writeTotalTime" | ||
| 288 | + :xFormater="'MM-DD'" | ||
| 289 | + :legendShown="false" | ||
| 290 | + :tool-tips-sort="'desc'" | ||
| 291 | + :tool-tips-exclude-zero="true" | ||
| 292 | + /> | ||
| 293 | + </my-card> | ||
| 294 | + </el-col> | ||
| 295 | + <el-col :span="8"> | ||
| 296 | + <my-card | ||
| 297 | + :title="$t('clusterMonitor.detail.instance.primaryWalSendPressure')" | ||
| 298 | + height="200" | ||
| 299 | + :bodyPadding="false" | ||
| 300 | + > | ||
| 301 | + <LazyLine | ||
| 302 | + :tabId="tabId" | ||
| 303 | + :formatter="toFixed" | ||
| 304 | + :data="metricsData.sendPressure" | ||
| 305 | + :xData="metricsData.time" | ||
| 306 | + :legendShown="false" | ||
| 307 | + :tool-tips-sort="'desc'" | ||
| 308 | + :tool-tips-exclude-zero="true" | ||
| 309 | + /> | ||
| 310 | + </my-card> | ||
| 311 | + </el-col> | ||
| 312 | + <el-col :span="8"> | ||
| 313 | + <my-card | ||
| 314 | + :title="$t('clusterMonitor.detail.instance.primaryWalWriteRate')" | ||
| 315 | + height="200" | ||
| 316 | + :bodyPadding="false" | ||
| 317 | + > | ||
| 318 | + <LazyLine | ||
| 319 | + :tabId="tabId" | ||
| 320 | + :formatter="toFixed" | ||
| 321 | + :data="metricsData.writePerSecond" | ||
| 322 | + :xData="metricsData.time" | ||
| 323 | + :legendShown="false" | ||
| 324 | + :tool-tips-sort="'desc'" | ||
| 325 | + :tool-tips-exclude-zero="true" | ||
| 326 | + /> | ||
| 327 | + </my-card> | ||
| 328 | + </el-col> | ||
| 329 | + </el-row> | ||
| 330 | + | ||
| 331 | + <div class="gap-row"></div> | ||
| 332 | + <el-row :gutter="12"> | ||
| 333 | + <el-col :span="8"> | ||
| 334 | + <my-card | ||
| 335 | + :title="$t('clusterMonitor.detail.instance.standbyReceiveDelay')" | ||
| 336 | + height="200" | ||
| 337 | + :bodyPadding="false" | ||
| 338 | + > | ||
| 339 | + <LazyLine | ||
| 340 | + :tabId="tabId" | ||
| 341 | + :formatter="toFixed" | ||
| 342 | + :data="metricsData.receivedDelay" | ||
| 343 | + :xData="metricsData.time" | ||
| 344 | + :legendShown="false" | ||
| 345 | + :tool-tips-sort="'desc'" | ||
| 346 | + :tool-tips-exclude-zero="true" | ||
| 347 | + /> | ||
| 348 | + </my-card> | ||
| 349 | + </el-col> | ||
| 350 | + <el-col :span="8"> | ||
| 351 | + <my-card | ||
| 352 | + :title="$t('clusterMonitor.detail.instance.standbyDiskDelay')" | ||
| 353 | + height="200" | ||
| 354 | + :bodyPadding="false" | ||
| 355 | + > | ||
| 356 | + <LazyLine | ||
| 357 | + :tabId="tabId" | ||
| 358 | + :formatter="toFixed" | ||
| 359 | + :data="metricsData.writeDelay" | ||
| 360 | + :xData="metricsData.time" | ||
| 361 | + :legendShown="false" | ||
| 362 | + :tool-tips-sort="'desc'" | ||
| 363 | + :tool-tips-exclude-zero="true" | ||
| 364 | + /> | ||
| 365 | + </my-card> | ||
| 366 | + </el-col> | ||
| 367 | + <el-col :span="8"> | ||
| 368 | + <my-card | ||
| 369 | + :title="$t('clusterMonitor.detail.instance.standbyReplayDelay')" | ||
| 370 | + height="200" | ||
| 371 | + :bodyPadding="false" | ||
| 372 | + > | ||
| 373 | + <LazyLine | ||
| 374 | + :tabId="tabId" | ||
| 375 | + :formatter="toFixed" | ||
| 376 | + :data="metricsData.replayDelay" | ||
| 377 | + :xData="metricsData.time" | ||
| 378 | + :legendShown="false" | ||
| 379 | + :tool-tips-sort="'desc'" | ||
| 380 | + :tool-tips-exclude-zero="true" | ||
| 381 | + /> | ||
| 382 | + </my-card> | ||
| 383 | + </el-col> | ||
| 384 | + </el-row> | ||
| 385 | + </div> | ||
| 386 | + </my-card> | ||
| 387 | + </div> | ||
| 388 | + </el-main> | ||
| 389 | + </el-container> | ||
| 390 | + </div> | ||
| 391 | +</template> | ||
| 392 | + | ||
| 393 | +<script setup lang="ts"> | ||
| 394 | +import { ref } from 'vue' | ||
| 395 | +import { useRequest } from 'vue-request' | ||
| 396 | +import { getClusterDetails, getClusterNodes, ClusterNode } from '@/api/cluster' | ||
| 397 | +import { toFixed, uuid } from '@/shared' | ||
| 398 | +import { ElMessage } from 'element-plus' | ||
| 399 | +import { useI18n } from 'vue-i18n' | ||
| 400 | +import colorCharts from '@/assets/style/color.module.scss' | ||
| 401 | +import router from '@/router' | ||
| 402 | +import { Refresh } from '@element-plus/icons-vue' | ||
| 403 | +const { t } = useI18n() | ||
| 404 | +const tabId = ref<string>(uuid()) | ||
| 405 | +const clusterRow = ref<any>({ clusterId: '' }) | ||
| 406 | +const clusterNodesData = ref<ClusterNode[]>([]) | ||
| 407 | + | ||
| 408 | +interface LineData { | ||
| 409 | + name: string | ||
| 410 | + data: any[] | ||
| 411 | + [other: string]: any | ||
| 412 | +} | ||
| 413 | +interface MetricsData { | ||
| 414 | + cpu: LineData[] | ||
| 415 | + memory: LineData[] | ||
| 416 | + networkIn: LineData[] | ||
| 417 | + networkOut: LineData[] | ||
| 418 | + io: LineData[] | ||
| 419 | + qps: LineData[] | ||
| 420 | + sql80: LineData[] | ||
| 421 | + sql95: LineData[] | ||
| 422 | + sendPressure: LineData[] | ||
| 423 | + writePerSecond: LineData[] | ||
| 424 | + receivedDelay: LineData[] | ||
| 425 | + writeDelay: LineData[] | ||
| 426 | + replayDelay: LineData[] | ||
| 427 | + writeTotal: LineData[] | ||
| 428 | + writeTotalTime: string[] | ||
| 429 | + time: string[] | ||
| 430 | +} | ||
| 431 | +const defaultData = { | ||
| 432 | + cpu: [], | ||
| 433 | + memory: [], | ||
| 434 | + networkIn: [], | ||
| 435 | + networkOut: [], | ||
| 436 | + io: [], | ||
| 437 | + qps: [], | ||
| 438 | + sql80: [], | ||
| 439 | + sql95: [], | ||
| 440 | + sendPressure: [], | ||
| 441 | + writePerSecond: [], | ||
| 442 | + receivedDelay: [], | ||
| 443 | + writeDelay: [], | ||
| 444 | + replayDelay: [], | ||
| 445 | + writeTotal: [], | ||
| 446 | + writeTotalTime: [], | ||
| 447 | + time: [], | ||
| 448 | +} | ||
| 449 | +const metricsData = ref<MetricsData>(defaultData) | ||
| 450 | +const colorArray: Array<string> = colorCharts.chartColors.split(',') | ||
| 451 | + | ||
| 452 | +onMounted(() => {}) | ||
| 453 | + | ||
| 454 | +const myEmit = defineEmits(['goback']) | ||
| 455 | +const goback = () => { | ||
| 456 | + myEmit('goback') | ||
| 457 | +} | ||
| 458 | +const goInto = (row: any) => { | ||
| 459 | + clusterRow.value = row | ||
| 460 | + loadClusterNodes(clusterRow.value.clusterId) | ||
| 461 | +} | ||
| 462 | +defineExpose({ goInto }) | ||
| 463 | + | ||
| 464 | +const gotoInstance = (row: any) => { | ||
| 465 | + let nodeId = row.nodeId | ||
| 466 | + if (!nodeId) { | ||
| 467 | + ElMessage({ | ||
| 468 | + showClose: true, | ||
| 469 | + message: t('clusterMonitor.list.noNodeId'), | ||
| 470 | + type: 'warning', | ||
| 471 | + }) | ||
| 472 | + return | ||
| 473 | + } | ||
| 474 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 475 | + if (curMode === 'wujie') { | ||
| 476 | + // @ts-ignore plug-in components | ||
| 477 | + window.$wujie?.props.methods.jump({ | ||
| 478 | + name: `Static-pluginObservability-instanceVemDashboardInstance`, | ||
| 479 | + query: { | ||
| 480 | + nodeId, | ||
| 481 | + }, | ||
| 482 | + }) | ||
| 483 | + } else { | ||
| 484 | + // local | ||
| 485 | + router.push({ path: `/vem/dashboard/instance`, query: { nodeId } }) | ||
| 486 | + } | ||
| 487 | +} | ||
| 488 | +const selectionChange = (selection: Array) => { | ||
| 489 | + if (selection.length <= 0) { | ||
| 490 | + for (let prop in metricsData.value) { | ||
| 491 | + if (Object.prototype.hasOwnProperty.call(metricsData.value, prop)) { | ||
| 492 | + metricsData.value[prop].forEach((element) => { | ||
| 493 | + element.lineStyle = undefined | ||
| 494 | + }) | ||
| 495 | + } | ||
| 496 | + } | ||
| 497 | + } else { | ||
| 498 | + for (let prop in metricsData.value) { | ||
| 499 | + if (Object.prototype.hasOwnProperty.call(metricsData.value, prop)) { | ||
| 500 | + metricsData.value[prop].forEach((element) => { | ||
| 501 | + if ( | ||
| 502 | + selection.some((item: any) => { | ||
| 503 | + return item.nodeId === element.name | ||
| 504 | + }) | ||
| 505 | + ) { | ||
| 506 | + element.lineStyle = undefined | ||
| 507 | + } else { | ||
| 508 | + element.lineStyle = { | ||
| 509 | + opacity: 0.1, | ||
| 510 | + } | ||
| 511 | + } | ||
| 512 | + }) | ||
| 513 | + } | ||
| 514 | + } | ||
| 515 | + } | ||
| 516 | +} | ||
| 517 | +const { data: allClusters, run: loadAllClusters, loading } = useRequest(getClusterDetails, { manual: true }) | ||
| 518 | +watch( | ||
| 519 | + allClusters, | ||
| 520 | + () => { | ||
| 521 | + // clear data | ||
| 522 | + metricsData.value = JSON.parse(JSON.stringify(defaultData)) | ||
| 523 | + | ||
| 524 | + if (!allClusters.value) return | ||
| 525 | + | ||
| 526 | + // get sort | ||
| 527 | + let nodeIds = clusterNodesData.value.map((node) => node.nodeId) | ||
| 528 | + | ||
| 529 | + let responseKeys = [ | ||
| 530 | + ['CPU', 'cpu'], // cpu | ||
| 531 | + ['MEMORY', 'memory'], // memory | ||
| 532 | + ['NETWORK_IN_TOTAL', 'networkIn'], // network | ||
| 533 | + ['NETWORK_OUT_TOTAL', 'networkOut'], // network | ||
| 534 | + ['IOPS_R_TOTAL', 'io'], // io | ||
| 535 | + ['INSTANCE_QPS', 'qps'], // qps | ||
| 536 | + ['INSTANCE_DB_RESPONSETIME_P80', 'sql80'], // 80% | ||
| 537 | + ['INSTANCE_DB_RESPONSETIME_P95', 'sql95'], // 95% | ||
| 538 | + ['CLUSTER_PRIMARY_WAL_SEND_PRESSURE', 'sendPressure'], // Send Pressure | ||
| 539 | + ['CLUSTER_PRIMARY_WAL_WRITE_PER_SEC', 'writePerSecond'], // write per sencend | ||
| 540 | + ['CLUSTER_WAL_RECEIVED_DELAY', 'receivedDelay'], // received delay | ||
| 541 | + ['CLUSTER_WAL_WRITE_DELAY', 'writeDelay'], // write delay | ||
| 542 | + ['CLUSTER_WAL_REPLAY_DELAY', 'replayDelay'], // replay delay | ||
| 543 | + ['CLUSTER_PRIMARY_WAL_WRITE_TOTAL', 'writeTotal'], // write total daily | ||
| 544 | + ] | ||
| 545 | + responseKeys.forEach((responseKeyArray) => { | ||
| 546 | + for (let key in nodeIds) { | ||
| 547 | + let tempData: string[] = [] | ||
| 548 | + if (allClusters.value[responseKeyArray[0]][nodeIds[key]]) { | ||
| 549 | + allClusters.value[responseKeyArray[0]][nodeIds[key]].forEach((element) => { | ||
| 550 | + if (responseKeyArray[0] === 'NETWORK_IN_TOTAL' || responseKeyArray[0] === 'NETWORK_OUT_TOTAL') { | ||
| 551 | + tempData.push(toFixed(element / 1024 / 1024, 1)) | ||
| 552 | + } else if ( | ||
| 553 | + responseKeyArray[0] === 'INSTANCE_DB_RESPONSETIME_P80' || | ||
| 554 | + responseKeyArray[0] === 'INSTANCE_DB_RESPONSETIME_P95' | ||
| 555 | + ) { | ||
| 556 | + tempData.push(toFixed(element / 1000, 1)) | ||
| 557 | + } else tempData.push(toFixed(element)) | ||
| 558 | + }) | ||
| 559 | + metricsData.value[responseKeyArray[1]].push({ data: tempData, name: nodeIds[key], key: nodeIds[key] }) | ||
| 560 | + } else { | ||
| 561 | + metricsData.value[responseKeyArray[1]].push({ data: [], name: nodeIds[key], key: nodeIds[key] }) | ||
| 562 | + } | ||
| 563 | + } | ||
| 564 | + }) | ||
| 565 | + | ||
| 566 | + // time | ||
| 567 | + metricsData.value.time = allClusters.value.time | ||
| 568 | + metricsData.value.writeTotalTime = allClusters.value.CLUSTER_PRIMARY_WAL_WRITE_TOTAL_TIME | ||
| 569 | + }, | ||
| 570 | + { deep: true } | ||
| 571 | +) | ||
| 572 | + | ||
| 573 | +const { | ||
| 574 | + data: clusterNodes, | ||
| 575 | + run: loadClusterNodes, | ||
| 576 | + loading: loadingNodes, | ||
| 577 | +} = useRequest(getClusterNodes, { manual: true }) | ||
| 578 | +watch( | ||
| 579 | + clusterNodes, | ||
| 580 | + () => { | ||
| 581 | + if (!clusterNodes.value) return | ||
| 582 | + | ||
| 583 | + clusterNodesData.value = clusterNodes.value | ||
| 584 | + | ||
| 585 | + for (let index = 0; index < clusterNodesData.value.length; index++) { | ||
| 586 | + const element = clusterNodesData.value[index] | ||
| 587 | + element.color = colorArray[index] | ||
| 588 | + } | ||
| 589 | + loadAllClusters(clusterRow.value.clusterId) | ||
| 590 | + }, | ||
| 591 | + { deep: true } | ||
| 592 | +) | ||
| 593 | +</script> | ||
| 594 | + | ||
| 595 | +<style scoped lang="scss"></style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/Index.vue+0-359
| @@ -1,359 +0,0 @@ | |||
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { Fold, Expand } from "@element-plus/icons-vue"; | ||
| 3 | -import { Refresh } from "@element-plus/icons-vue"; | ||
| 4 | -import { storeToRefs } from "pinia"; | ||
| 5 | -import { useI18n } from "vue-i18n"; | ||
| 6 | -import { useMonitorStore } from "../../store/monitor"; | ||
| 7 | -import { useWindowStore } from "../../store/window"; | ||
| 8 | -import PerformanceLoad from "./performance_load/Index.vue"; | ||
| 9 | -import TopSql from "./topSQL/Index.vue"; | ||
| 10 | -import Wdr from "./wdr/Index.vue"; | ||
| 11 | -import { i18n } from "../../i18n"; | ||
| 12 | -import ogRequest from "../../request"; | ||
| 13 | -import { useRequest } from "vue-request"; | ||
| 14 | -import Install from "./install/Index.vue"; | ||
| 15 | -import SystemConfiguration from "./system_configuration/Index.vue"; | ||
| 16 | - | ||
| 17 | -const { t } = useI18n(); | ||
| 18 | - | ||
| 19 | -type Res = | ||
| 20 | - | [ | ||
| 21 | - { | ||
| 22 | - [propName: string]: string | number; | ||
| 23 | - } | ||
| 24 | - ] | ||
| 25 | - | undefined; | ||
| 26 | - | ||
| 27 | -const datePickerRef = ref<HTMLDivElement>(); | ||
| 28 | -const clusterNodeId = ref(); | ||
| 29 | -const clusterList = ref<Array<any>[]>([]); | ||
| 30 | -const connectStatus = ref<boolean | undefined>(undefined); | ||
| 31 | -const curServerInfoText = ref(""); | ||
| 32 | -const nodeVersion = ref<string>(""); | ||
| 33 | -const lastNodeId = ref<string>(""); | ||
| 34 | -const wdrComponent = ref(null); | ||
| 35 | -const paramConfigComponent = ref(null); | ||
| 36 | - | ||
| 37 | -const { serverInfoText } = storeToRefs(useWindowStore()); | ||
| 38 | -const { tab, filters, autoRefresh, rangeTime, instanceId } = storeToRefs(useMonitorStore()); | ||
| 39 | -// tab render only once | ||
| 40 | -const tabLoaded = reactive([tab.value === 0, tab.value === 1, tab.value === 2, tab.value === 3]); | ||
| 41 | -watch(tab, (v) => { | ||
| 42 | - if (!tabLoaded[v]) { | ||
| 43 | - tabLoaded[v] = true; | ||
| 44 | - } | ||
| 45 | - if (v === 0 || v === 1) { | ||
| 46 | - nextTick(() => { | ||
| 47 | - if (nodeIdChangedByOtherTabs.value !== "") { | ||
| 48 | - clusterNodeId.value = nodeIdChangedByOtherTabs.value; | ||
| 49 | - nodeIdChangedByOtherTabs.value = ""; | ||
| 50 | - } | ||
| 51 | - }); | ||
| 52 | - } | ||
| 53 | - if (v === 2) { | ||
| 54 | - nextTick(() => { | ||
| 55 | - wdrComponent.value.syncNodeId(lastNodeId.value); | ||
| 56 | - }); | ||
| 57 | - } | ||
| 58 | - if (v === 3) { | ||
| 59 | - nextTick(() => { | ||
| 60 | - paramConfigComponent.value.syncNodeId(lastNodeId.value); | ||
| 61 | - }); | ||
| 62 | - } | ||
| 63 | -}); | ||
| 64 | -const isCollapse = ref(true); | ||
| 65 | -const toggleCollapse = () => { | ||
| 66 | - isCollapse.value = !isCollapse.value; | ||
| 67 | -}; | ||
| 68 | - | ||
| 69 | -// nodeId sync | ||
| 70 | -const nodeIdChangedByOtherTabs = ref<string>(""); | ||
| 71 | -const nodeIdChanged = (nodeId: any) => { | ||
| 72 | - nodeIdChangedByOtherTabs.value = nodeId; | ||
| 73 | - lastNodeId.value = nodeId; | ||
| 74 | -}; | ||
| 75 | - | ||
| 76 | -const autoRefreshFn = () => { | ||
| 77 | - autoRefresh.value = !autoRefresh.value; | ||
| 78 | -}; | ||
| 79 | - | ||
| 80 | -const { data: opsClusterData } = useRequest(() => ogRequest.get("/observability/v1/topsql/cluster"), { manual: false }); | ||
| 81 | - | ||
| 82 | -const { data: connectStatusData, run: runConnectStatus, loading: connectStatusLoadding } = useRequest((nodeId: String) => ogRequest.get(`/observability/v1/topsql/connect/${nodeId}`), { manual: true }); | ||
| 83 | - | ||
| 84 | -const treeTransform = (arr: any) => { | ||
| 85 | - let obj: any = []; | ||
| 86 | - if (arr instanceof Array) { | ||
| 87 | - arr.forEach((item) => { | ||
| 88 | - // init current cluster node | ||
| 89 | - if (item.nodeId && item.nodeId === instanceId.value) { | ||
| 90 | - clusterNodeId.value = instanceId.value; | ||
| 91 | - } | ||
| 92 | - obj.push({ | ||
| 93 | - label: item.clusterId ? item.clusterId : (item.azName ? item.azName + "_" : "") + item.publicIp + ":" + item.dbPort + (item.clusterRole ? "(" + item.clusterRole + ")" : ""), | ||
| 94 | - value: item.clusterId ? item.clusterId : item.nodeId, | ||
| 95 | - children: treeTransform(item.clusterNodes), | ||
| 96 | - }); | ||
| 97 | - }); | ||
| 98 | - } | ||
| 99 | - return obj; | ||
| 100 | -}; | ||
| 101 | - | ||
| 102 | -const showConnectStatus = (status: boolean | undefined) => { | ||
| 103 | - if (status === undefined) { | ||
| 104 | - return ""; | ||
| 105 | - } | ||
| 106 | - return status ? t("dashboard.connectStatus.success") : t("dashboard.connectStatus.error"); | ||
| 107 | -}; | ||
| 108 | - | ||
| 109 | -const onDatePackerVisible = (v: boolean) => { | ||
| 110 | - if (!v) { | ||
| 111 | - const docu = document.getElementsByClassName("el-range-input"); | ||
| 112 | - // @ts-ignore | ||
| 113 | - docu[0]?.blur(); | ||
| 114 | - } | ||
| 115 | -}; | ||
| 116 | - | ||
| 117 | -const getVersionByNodeId = (curNodeId: string) => { | ||
| 118 | - if (!Array.isArray(opsClusterData.value)) { | ||
| 119 | - return ""; | ||
| 120 | - } | ||
| 121 | - for (let i = 0; i < opsClusterData.value.length; i += 1) { | ||
| 122 | - const version = opsClusterData.value[i].version || ""; | ||
| 123 | - const children = opsClusterData.value[i].clusterNodes; | ||
| 124 | - if (!Array.isArray(children)) { | ||
| 125 | - continue; | ||
| 126 | - } | ||
| 127 | - for (let j = 0; j < children.length; j += 1) { | ||
| 128 | - if (children[j]?.nodeId === curNodeId) { | ||
| 129 | - return version.toLocaleUpperCase(); | ||
| 130 | - } | ||
| 131 | - } | ||
| 132 | - } | ||
| 133 | - return ""; | ||
| 134 | -}; | ||
| 135 | - | ||
| 136 | -watch(opsClusterData, (res: Res) => { | ||
| 137 | - if (res && Object.keys(res).length) { | ||
| 138 | - clusterList.value = treeTransform(res); | ||
| 139 | - } | ||
| 140 | -}); | ||
| 141 | - | ||
| 142 | -watch(clusterNodeId, (res) => { | ||
| 143 | - let curInstanceId = instanceId.value; | ||
| 144 | - if (typeof res === "string") { | ||
| 145 | - curInstanceId = res; | ||
| 146 | - } else if (Array.isArray(res) && res.length > 0) { | ||
| 147 | - curInstanceId = res[res.length - 1]; | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | - lastNodeId.value = curInstanceId; | ||
| 151 | - // get connection status | ||
| 152 | - runConnectStatus(curInstanceId); | ||
| 153 | - // set instanceId value | ||
| 154 | - instanceId.value = curInstanceId; | ||
| 155 | - useMonitorStore().instanceId = curInstanceId; | ||
| 156 | - // useMonitorStore().tab = 0; | ||
| 157 | - nodeVersion.value = getVersionByNodeId(curInstanceId); | ||
| 158 | -}); | ||
| 159 | - | ||
| 160 | -watch(connectStatusData, (res) => { | ||
| 161 | - connectStatus.value = res; | ||
| 162 | -}); | ||
| 163 | - | ||
| 164 | -watch(rangeTime, (r) => { | ||
| 165 | - if (r !== -1) { | ||
| 166 | - filters.value[tab.value].time = null; | ||
| 167 | - } | ||
| 168 | -}); | ||
| 169 | - | ||
| 170 | -watch(serverInfoText, (val) => { | ||
| 171 | - if (typeof val === "string" && val !== "") { | ||
| 172 | - curServerInfoText.value = val; | ||
| 173 | - } else { | ||
| 174 | - curServerInfoText.value = ""; | ||
| 175 | - } | ||
| 176 | -}); | ||
| 177 | -</script> | ||
| 178 | - | ||
| 179 | -<template> | ||
| 180 | - <div class="tab-wrapper" :key="clusterNodeId"> | ||
| 181 | - <el-container> | ||
| 182 | - <el-aside :width="isCollapse ? '0px' : '300px'"> | ||
| 183 | - <div style="height: 13px"></div> | ||
| 184 | - <Install /> | ||
| 185 | - </el-aside> | ||
| 186 | - <el-main style="position: relative;padding-top: 0px;"> | ||
| 187 | - <div> | ||
| 188 | - <div style="position: absolute; left: 10px; top: 11px; z-index: 9999" @click="toggleCollapse"> | ||
| 189 | - <el-icon v-if="!isCollapse" size="20px"><Fold /></el-icon> | ||
| 190 | - <el-icon v-if="isCollapse" size="20px"><Expand /></el-icon> | ||
| 191 | - </div> | ||
| 192 | - </div> | ||
| 193 | - <el-tabs v-model="tab"> | ||
| 194 | - <div class="tab-wrapper-container" v-show="tab === 0 || tab === 1"> | ||
| 195 | - <div class="cluster-container"> | ||
| 196 | - <div class="cluster-container-title">{{ $t("datasource.cluterTitle") }}</div> | ||
| 197 | - <el-cascader v-model="clusterNodeId" :options="clusterList" /> | ||
| 198 | - <div v-if="false" class="divider" /> | ||
| 199 | - <div class="cluster-info-loading" v-if="false && connectStatusLoadding" v-loading="connectStatusLoadding"></div> | ||
| 200 | - <div class="cluster-info" v-if="false && connectStatus !== undefined && !connectStatusLoadding"> | ||
| 201 | - <span class="cluster-info-light" :style="{ backgroundColor: connectStatus ? 'green' : 'red' }" /> | ||
| 202 | - <span>{{ showConnectStatus(connectStatus) }}</span> | ||
| 203 | - </div> | ||
| 204 | - <div v-if="false && curServerInfoText !== ''" class="divider" /> | ||
| 205 | - <div v-if="false && curServerInfoText !== ''">{{ serverInfoText }}</div> | ||
| 206 | - </div> | ||
| 207 | - <div class="tab-wrapper-filter"> | ||
| 208 | - <span>{{ $t("app.autoRefresh") }}:</span> | ||
| 209 | - <el-select v-model="filters[tab].refreshTime" style="width: 60px; margin: 0 4px"> | ||
| 210 | - <el-option :value="15" label="15s" /> | ||
| 211 | - <el-option :value="30" label="30s" /> | ||
| 212 | - <el-option :value="60" label="60s" /> | ||
| 213 | - </el-select> | ||
| 214 | - <el-button type="primary" :icon="Refresh" style="padding: 8px" @click="autoRefreshFn" /> | ||
| 215 | - <div class="divider"></div> | ||
| 216 | - <span>{{ $t("dashboard.range") }}:</span> | ||
| 217 | - <el-select v-model="filters[tab].rangeTime" :style="{ width: i18n.global.locale.value === 'en' ? '115px' : '85px' }"> | ||
| 218 | - <el-option :value="1" :label="$t('dashboard.last1H')" /> | ||
| 219 | - <el-option :value="12" :label="$t('dashboard.last12H')" /> | ||
| 220 | - <el-option :value="24" :label="$t('dashboard.last1D')" /> | ||
| 221 | - <el-option :value="48" :label="$t('dashboard.last2D')" /> | ||
| 222 | - <el-option :value="168" :label="$t('dashboard.last7D')" /> | ||
| 223 | - <el-option :value="-1" :label="$t('app.custom')" /> | ||
| 224 | - </el-select> | ||
| 225 | - <el-date-picker ref="datePickerRef" :disabled="filters[tab].rangeTime !== -1" type="datetimerange" v-model="filters[tab].time" :start-placeholder="$t('app.startDate')" :end-placeholder="$t('app.endDate')" :range-separator="$t('app.to')" @visible-change="onDatePackerVisible" /> | ||
| 226 | - </div> | ||
| 227 | - </div> | ||
| 228 | - | ||
| 229 | - <el-tab-pane :label="$t('dashboard.load')" :name="0"> | ||
| 230 | - <performance-load v-if="tabLoaded[0] || tab === 0" :nodeVersion="nodeVersion" /> | ||
| 231 | - </el-tab-pane> | ||
| 232 | - <el-tab-pane :label="$t('dashboard.top')" :name="1"> | ||
| 233 | - <top-sql v-if="tabLoaded[1] || tab === 1" :instanceId="instanceId" /> | ||
| 234 | - </el-tab-pane> | ||
| 235 | - <el-tab-pane :label="$t('dashboard.wdrReports.tabName')" :name="2"> | ||
| 236 | - <wdr @nodeIdChanged="nodeIdChanged" ref="wdrComponent" v-if="tabLoaded[2] || tab === 2" :instanceId="instanceId" /> | ||
| 237 | - </el-tab-pane> | ||
| 238 | - <el-tab-pane :label="$t('dashboard.systemConfig.tabName')" :name="3"> | ||
| 239 | - <system-configuration @nodeIdChanged="nodeIdChanged" ref="paramConfigComponent" v-if="tabLoaded[3] || tab === 3" :instanceId="instanceId" /> | ||
| 240 | - </el-tab-pane> | ||
| 241 | - </el-tabs> | ||
| 242 | - </el-main> | ||
| 243 | - </el-container> | ||
| 244 | - </div> | ||
| 245 | -</template> | ||
| 246 | - | ||
| 247 | -<style scoped lang="scss"> | ||
| 248 | -.cluster-container { | ||
| 249 | - height: 40px; | ||
| 250 | - // background-color: var(--el-bg-color-sub); | ||
| 251 | - padding: 0 16px; | ||
| 252 | - display: flex; | ||
| 253 | - align-items: center; | ||
| 254 | - | ||
| 255 | - &-title { | ||
| 256 | - font-size: 14px; | ||
| 257 | - margin-right: 10px; | ||
| 258 | - } | ||
| 259 | - | ||
| 260 | - :deep(.el-cascader) { | ||
| 261 | - width: 210px; | ||
| 262 | - } | ||
| 263 | - | ||
| 264 | - :deep(.el-input__wrapper) { | ||
| 265 | - border-radius: 5px; | ||
| 266 | - font-size: 12px; | ||
| 267 | - font-weight: 700; | ||
| 268 | - } | ||
| 269 | -} | ||
| 270 | - | ||
| 271 | -.cluster-info { | ||
| 272 | - height: inherit; | ||
| 273 | - display: flex; | ||
| 274 | - align-items: center; | ||
| 275 | - font-size: 12px; | ||
| 276 | - | ||
| 277 | - &-light { | ||
| 278 | - display: inline-block; | ||
| 279 | - width: 6px; | ||
| 280 | - height: 6px; | ||
| 281 | - border-radius: 50%; | ||
| 282 | - background-color: green; | ||
| 283 | - margin-right: 8px; | ||
| 284 | - } | ||
| 285 | - | ||
| 286 | - &-loading { | ||
| 287 | - width: 50px; | ||
| 288 | - } | ||
| 289 | -} | ||
| 290 | - | ||
| 291 | -.tab-wrapper { | ||
| 292 | - position: relative; | ||
| 293 | - | ||
| 294 | - &-container { | ||
| 295 | - display: flex; | ||
| 296 | - align-items: center; | ||
| 297 | - margin-bottom: 10px; | ||
| 298 | - justify-content: end; | ||
| 299 | - overflow: hidden; | ||
| 300 | - font-size: 12px; | ||
| 301 | - } | ||
| 302 | - | ||
| 303 | - &-filter { | ||
| 304 | - font-size: 12px; | ||
| 305 | - width: 600px; | ||
| 306 | - z-index: 10; | ||
| 307 | - padding-right: 16px; | ||
| 308 | - display: flex; | ||
| 309 | - align-items: center; | ||
| 310 | - padding: 0 10px; | ||
| 311 | - height: 40px; | ||
| 312 | - > div:not(:last-of-type), | ||
| 313 | - > span, | ||
| 314 | - > button { | ||
| 315 | - margin-right: 4px; | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - :deep(.el-button .el-icon svg) { | ||
| 319 | - color: var(--el-color-icon-refresh-color); | ||
| 320 | - } | ||
| 321 | - | ||
| 322 | - :deep(.el-button--small) { | ||
| 323 | - background-color: var(--el-color-button-small-bg) !important; | ||
| 324 | - border: 1px solid var(--el-bg-color-og-hover) !important; | ||
| 325 | - color: var(--el-bg-color-og-hover) !important; | ||
| 326 | - padding: 5px !important; | ||
| 327 | - } | ||
| 328 | - | ||
| 329 | - :deep(.el-select .el-input.is-focus .el-input__wrapper) { | ||
| 330 | - box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset !important; | ||
| 331 | - } | ||
| 332 | - :deep(.el-select-dropdown__item.selected) { | ||
| 333 | - color: var(--el-color-tabbar-active) !important; | ||
| 334 | - } | ||
| 335 | - :deep(.el-range-editor.is-active) { | ||
| 336 | - box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset !important; | ||
| 337 | - } | ||
| 338 | - } | ||
| 339 | - | ||
| 340 | - :deep(.el-range-input) { | ||
| 341 | - background-color: var(--el-bg-color); | ||
| 342 | - } | ||
| 343 | - | ||
| 344 | - :deep(.el-date-editor--datetimerange) { | ||
| 345 | - width: 100px; | ||
| 346 | - background-color: var(--el-bg-color); | ||
| 347 | - } | ||
| 348 | -} | ||
| 349 | -.divider { | ||
| 350 | - height: 24px; | ||
| 351 | - width: 1px; | ||
| 352 | - margin: 0 8px !important; | ||
| 353 | - background-color: var(--el-color-divider-border-color); | ||
| 354 | -} | ||
| 355 | -:deep(.el-tabs__header) { | ||
| 356 | - padding: 0 16px; | ||
| 357 | - // width: v-bind(tabHeaderW); | ||
| 358 | -} | ||
| 359 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/performance_load/Index.vue+0-626
| @@ -1,626 +0,0 @@ | |||
| 1 | -<!-- eslint-disable camelcase --> | ||
| 2 | -<script setup lang="ts"> | ||
| 3 | -import { useI18n } from 'vue-i18n'; | ||
| 4 | -import ListMetric from './ListMetric.vue'; | ||
| 5 | -import LazyLine from '../LazyLine.vue'; | ||
| 6 | -import { useMonitorStore } from '../../../store/monitor'; | ||
| 7 | -import { toFixed } from '../../../shared'; | ||
| 8 | -import { storeToRefs } from 'pinia'; | ||
| 9 | -import { getDatabaseMetrics } from '../../../api/prometheus'; | ||
| 10 | -import { useIntervalTime } from '../../../hooks/time'; | ||
| 11 | - | ||
| 12 | -const { t } = useI18n(); | ||
| 13 | - | ||
| 14 | -const props = withDefaults(defineProps<{ | ||
| 15 | - nodeVersion?: string, | ||
| 16 | -}>(), { | ||
| 17 | - nodeVersion: "", | ||
| 18 | -}) | ||
| 19 | - | ||
| 20 | -const brushRangeSign = ref<boolean>(false); | ||
| 21 | -const tempSaveTime = ref<Array<Date>>([]); | ||
| 22 | -const tempSaveRangeTime = ref<number>(-2); | ||
| 23 | - | ||
| 24 | -const monitorStore = useMonitorStore() | ||
| 25 | -const { refreshTime, rangeTime, time, tab: topTab, autoRefresh, instanceId, brushRange, timeRange } = storeToRefs(useMonitorStore()) | ||
| 26 | - | ||
| 27 | -const load = (checkTab?: boolean, checkRange?: boolean) => { | ||
| 28 | - if (checkTab && topTab.value !== 0) { | ||
| 29 | - return | ||
| 30 | - } | ||
| 31 | - if (checkRange && (brushRange.value.length > 0)) { | ||
| 32 | - return | ||
| 33 | - } | ||
| 34 | - if (rangeTime.value > 0 || (time.value && time.value.length === 2)) { | ||
| 35 | - getDatabaseMetrics() | ||
| 36 | - } | ||
| 37 | -} | ||
| 38 | -if (topTab.value === 0) { | ||
| 39 | - useIntervalTime(() => { | ||
| 40 | - if (instanceId.value) { | ||
| 41 | - load(true); | ||
| 42 | - } | ||
| 43 | - }, computed(() => refreshTime.value * 1000)) | ||
| 44 | -} | ||
| 45 | - | ||
| 46 | -watch(autoRefresh, () => load(true, true)) | ||
| 47 | - | ||
| 48 | -watch(rangeTime, v => { | ||
| 49 | - if (v > 0 && topTab.value === 0) { | ||
| 50 | - if (brushRangeSign.value) { | ||
| 51 | - brushRangeSign.value = false; | ||
| 52 | - } else { | ||
| 53 | - brushRange.value = [] | ||
| 54 | - } | ||
| 55 | - getDatabaseMetrics() | ||
| 56 | - } | ||
| 57 | -}) | ||
| 58 | -watch(time, v => { | ||
| 59 | - if (v && topTab.value === 0) { | ||
| 60 | - if (brushRangeSign.value) { | ||
| 61 | - brushRangeSign.value = false; | ||
| 62 | - } else { | ||
| 63 | - brushRange.value = [] | ||
| 64 | - } | ||
| 65 | - load() | ||
| 66 | - } | ||
| 67 | -}) | ||
| 68 | - | ||
| 69 | -const ioRateData = ref<{ name: string, cur: string, min: string, avg: string, max: string }[]>([]) | ||
| 70 | -const loadRateData = (data: any[]) => { | ||
| 71 | - if (data.length === 0) { | ||
| 72 | - ioRateData.value = [] | ||
| 73 | - return | ||
| 74 | - } | ||
| 75 | - ioRateData.value = data.map(d => { | ||
| 76 | - const count = d.data.reduce((a: number, s: string) => s != null ? a + Number.parseFloat(s) : a, 0) | ||
| 77 | - console.log("count", count); | ||
| 78 | - return { | ||
| 79 | - name: `${t(`metric.${d.name}`)}${t('dashboard.rate')}`, | ||
| 80 | - cur: `${d.data[Math.max(0, d.data.length - 1)]}KB/s`, | ||
| 81 | - min: `${toFixed(Math.min(...d.data))}KB/s`, | ||
| 82 | - avg: `${d.data.length ? toFixed(count / d.data.length) : '0.00'}KB/s`, | ||
| 83 | - max: `${toFixed(Math.max(...d.data))}KB/s`, | ||
| 84 | - } | ||
| 85 | - }) | ||
| 86 | -} | ||
| 87 | -const ioData = ref<{ name: string, cur: string, min: string, avg: string, max: string }[]>([]) | ||
| 88 | -const loadData = (data: any[]) => { | ||
| 89 | - if (data.length === 0) { | ||
| 90 | - ioData.value = [] | ||
| 91 | - return | ||
| 92 | - } | ||
| 93 | - ioData.value = data.map(d => { | ||
| 94 | - const count = d.data.reduce((a: number, s: string) => s != null ? a + Number.parseFloat(s) : a, 0) | ||
| 95 | - console.log("count", count); | ||
| 96 | - return { | ||
| 97 | - name: `${t(`metric.${d.name}`)}${t('dashboard.capacity')}`, | ||
| 98 | - cur: `${d.data[Math.max(0, d.data.length - 1)]}MB/s`, | ||
| 99 | - min: `${toFixed(Math.min(...d.data))}MB/s`, | ||
| 100 | - avg: `${d.data.length ? toFixed(count / d.data.length) : '0.00'}MB/s`, | ||
| 101 | - max: `${toFixed(Math.max(...d.data))}MB/s`, | ||
| 102 | - } | ||
| 103 | - }) | ||
| 104 | -} | ||
| 105 | - | ||
| 106 | -const toTopSQL = () => { | ||
| 107 | - monitorStore.filters[1].time = [new Date(timeRange.value[0]), new Date(timeRange.value[1])] | ||
| 108 | - brushRange.value = [] | ||
| 109 | - monitorStore.tab = 1 | ||
| 110 | - monitorStore.filters[1].rangeTime = -1 | ||
| 111 | -} | ||
| 112 | - | ||
| 113 | -const cardRef = ref() | ||
| 114 | -const colors = [ | ||
| 115 | - '#F5222D', '#FA8C16', '#FADB14', '#52C41A', '#13C2C2', '#1890FF', '#2F54EB', '#722ED1', '#EB2F96', '#A97526', | ||
| 116 | - '#FFB7B7', '#FFC9AB', '#FFFFAB', '#C0FF99', '#A8FFE5', '#B4E5FF', '#ADBAFF', '#D3ADF7', '#FFD1EC', | ||
| 117 | - '#FF7875', '#FFC069', '#FFF566', '#95DE64', '#5CDBD3', '#69C0FF', '#597EF7', '#9254DE', '#FF85C0', | ||
| 118 | - '#A8071A', '#AD4E00', '#AD8B00', '#237804', '#006D75', '#0050B3', '#1D39C4', '#531DAB', '#9E1068', | ||
| 119 | -] | ||
| 120 | -const waitLegends = ref<{color: string, name: string}[]>([]) | ||
| 121 | -const loadWaitData = (data: any[]) => { | ||
| 122 | - waitLegends.value = data.map((d, i) => { | ||
| 123 | - return { | ||
| 124 | - color: colors[i] as string, | ||
| 125 | - name: d.name as string, | ||
| 126 | - } | ||
| 127 | - }) | ||
| 128 | - nextTick(cardRef.value.trigger) | ||
| 129 | -} | ||
| 130 | - | ||
| 131 | -watch(instanceId, id => { | ||
| 132 | - if (id) { | ||
| 133 | - load() | ||
| 134 | - } | ||
| 135 | -}, { immediate: true }) | ||
| 136 | - | ||
| 137 | -const clearZoom = () => { | ||
| 138 | - brushRange.value = []; | ||
| 139 | - // reset | ||
| 140 | - if (tempSaveRangeTime.value > 0) { | ||
| 141 | - monitorStore.filters[0].rangeTime = tempSaveRangeTime.value; | ||
| 142 | - monitorStore.filters[0].time = null; | ||
| 143 | - } else { | ||
| 144 | - monitorStore.filters[0].time = [tempSaveTime.value[0], tempSaveTime.value[1]]; | ||
| 145 | - monitorStore.filters[0].rangeTime = -1; | ||
| 146 | - } | ||
| 147 | - brushRangeSign.value = false; | ||
| 148 | - // clear | ||
| 149 | - tempSaveTime.value = []; | ||
| 150 | - tempSaveRangeTime.value = -2; | ||
| 151 | -} | ||
| 152 | - | ||
| 153 | -watch(timeRange, () => { | ||
| 154 | - if (tempSaveTime.value.length === 0 && tempSaveRangeTime.value === -2) { | ||
| 155 | - if (rangeTime.value === -1) { | ||
| 156 | - tempSaveTime.value = [time.value![0], time.value![1]]; | ||
| 157 | - } else { | ||
| 158 | - tempSaveRangeTime.value = rangeTime.value; | ||
| 159 | - } | ||
| 160 | - } | ||
| 161 | - monitorStore.filters[0].time = [new Date(timeRange.value[0]), new Date(timeRange.value[1])]; | ||
| 162 | - monitorStore.filters[0].rangeTime = -1; | ||
| 163 | - brushRangeSign.value = true; | ||
| 164 | -}); | ||
| 165 | - | ||
| 166 | -</script> | ||
| 167 | - | ||
| 168 | -<template> | ||
| 169 | -<ListMetric /> | ||
| 170 | -<div class="load-flex"> | ||
| 171 | - <el-row :gutter="16" :key="nodeVersion"> | ||
| 172 | - <el-col :span="props.nodeVersion === 'LITE' ? 24 : 12"> | ||
| 173 | - <my-card :title="$t('dashboard.timeConsumption')" height="300" :legend="[ | ||
| 174 | - {color: '#9CCC65', name: 'CPU_TIME'}, | ||
| 175 | - {color: '#FA8C16', name: 'NET_SEND_TIME'}, | ||
| 176 | - {color: '#00C7F9', name: 'DATA_IO_TIME'}, | ||
| 177 | - ]" :bodyPadding="false"> | ||
| 178 | - <div class="instance_time"> | ||
| 179 | - <div class="instance_time-tip"><svg-icon name="info"/>{{ $t('dashboard.runningInAnalysisTip') }}</div> | ||
| 180 | - <div class="instance_time-button" v-show="brushRange && brushRange.length === 2"> | ||
| 181 | - <el-button type="primary" text bg @click="toTopSQL">{{ $t('dashboard.runningInAnalysis') }}</el-button> | ||
| 182 | - <el-button type="primary" text bg @click="clearZoom">{{ $t('dashboard.uncheckRegion') }}</el-button> | ||
| 183 | - </div> | ||
| 184 | - </div> | ||
| 185 | - <div style="height: 225px;"> | ||
| 186 | - <LazyLine | ||
| 187 | - :color="['#9CCC65', '#FA8C16', '#00C7F9']" | ||
| 188 | - :names="['CPU_TIME', 'NET_SEND_TIME', 'DATA_IO_TIME']" | ||
| 189 | - brush="time" | ||
| 190 | - :lineWidth="0" | ||
| 191 | - areaStyle | ||
| 192 | - stack | ||
| 193 | - :translate="false" | ||
| 194 | - /> | ||
| 195 | - </div> | ||
| 196 | - </my-card> | ||
| 197 | - </el-col> | ||
| 198 | - <el-col :span="12" v-if="props.nodeVersion !== 'LITE'"> | ||
| 199 | - <my-card :title="$t('dashboard.waitEvent')" height="300" :legend="waitLegends" :bodyPadding="false" style="margin-bottom: 16px;" ref="cardRef"> | ||
| 200 | - <div class="instance_time"> | ||
| 201 | - <div><svg-icon name="info"/>{{ $t('dashboard.runningInAnalysisTip') }}</div> | ||
| 202 | - <div v-show="brushRange && brushRange.length === 2"> | ||
| 203 | - <el-button type="primary" text bg @click="toTopSQL">{{ $t('dashboard.runningInAnalysis') }}</el-button> | ||
| 204 | - <el-button type="primary" text bg @click="clearZoom">{{ $t('dashboard.uncheckRegion') }}</el-button> | ||
| 205 | - </div> | ||
| 206 | - </div> | ||
| 207 | - <div style="height: 225px;"> | ||
| 208 | - <LazyLine | ||
| 209 | - :color="colors" | ||
| 210 | - @load-data="loadWaitData" | ||
| 211 | - legendName="event" | ||
| 212 | - brush="wait" | ||
| 213 | - bar | ||
| 214 | - stack | ||
| 215 | - enterable | ||
| 216 | - :translate="false" | ||
| 217 | - /> | ||
| 218 | - </div> | ||
| 219 | - </my-card> | ||
| 220 | - </el-col> | ||
| 221 | - </el-row> | ||
| 222 | -</div> | ||
| 223 | - | ||
| 224 | -<my-card :title="$t('dashboard.databaseLoad')" collapse style="margin-bottom: 16px;"> | ||
| 225 | - <el-row :gutter="16"> | ||
| 226 | - <el-col :span="12"> | ||
| 227 | - <my-card :title="$t('dashboard.tps')" height="255" :legend="[ | ||
| 228 | - {color: '#0D86E2', name: $t('metric.transactionRollbackNum')}, | ||
| 229 | - {color: '#9CCC65', name: $t('metric.transactionCommitments')}, | ||
| 230 | - {color: '#00C7F9', name: $t('metric.transactionAndRollbackTotal')}, | ||
| 231 | - ]" :bodyPadding="false"> | ||
| 232 | - <LazyLine | ||
| 233 | - :color="['#0D86E2', '#9CCC65', '#00C7F9']" | ||
| 234 | - :names="['transactionRollbackNum', 'transactionCommitments', 'transactionAndRollbackTotal']" | ||
| 235 | - :formatter="toFixed" | ||
| 236 | - /> | ||
| 237 | - </my-card> | ||
| 238 | - </el-col> | ||
| 239 | - <el-col :span="12"> | ||
| 240 | - <my-card :title="$t('dashboard.qps')" height="255" :legend="[ | ||
| 241 | - {color: '#00C7F9', name: $t('metric.queryTransactions')}, | ||
| 242 | - ]" :bodyPadding="false"> | ||
| 243 | - <LazyLine | ||
| 244 | - :color="['#00C7F9']" | ||
| 245 | - :names="['queryTransactions']" | ||
| 246 | - /> | ||
| 247 | - </my-card> | ||
| 248 | - </el-col> | ||
| 249 | - <el-col :span="12"> | ||
| 250 | - <my-card :title="$t('dashboard.connectionNum')" height="255" :legend="[ | ||
| 251 | - {color: '#E64A19', name: $t('metric.currentIdleConnections')}, | ||
| 252 | - {color: '#0D86E2', name: $t('metric.currentActiveConnections')}, | ||
| 253 | - {color: '#9CCC65', name: $t('metric.currentConnections')}, | ||
| 254 | - {color: '#00C7F9', name: $t('metric.totalConnections')}, | ||
| 255 | - ]" :bodyPadding="false"> | ||
| 256 | - <LazyLine | ||
| 257 | - :color="['#E64A19', '#0D86E2', '#9CCC65', '#00C7F9']" | ||
| 258 | - :names="['currentIdleConnections', 'currentActiveConnections', 'currentConnections', 'totalConnections']" | ||
| 259 | - /> | ||
| 260 | - </my-card> | ||
| 261 | - </el-col> | ||
| 262 | - <el-col :span="12"> | ||
| 263 | - <my-card :title="$t('dashboard.slowSqlMoreThan3Seconds')" height="255" :legend="[ | ||
| 264 | - {color: '#00C7F9', name: $t('metric.slowSqlNum')}, | ||
| 265 | - ]" :bodyPadding="false"> | ||
| 266 | - <LazyLine | ||
| 267 | - :color="['#00C7F9']" | ||
| 268 | - :names="['slowSqlNum']" | ||
| 269 | - /> | ||
| 270 | - </my-card> | ||
| 271 | - </el-col> | ||
| 272 | - <el-col :span="12"> | ||
| 273 | - <my-card :title="$t('dashboard.longTransactionNumGreaterThan30Seconds')" height="255" :legend="[ | ||
| 274 | - {color: '#00C7F9', name: $t('metric.longTransactions')}, | ||
| 275 | - ]" :bodyPadding="false"> | ||
| 276 | - <LazyLine | ||
| 277 | - :color="['#00C7F9']" | ||
| 278 | - :names="['longTransactions']" | ||
| 279 | - /> | ||
| 280 | - </my-card> | ||
| 281 | - </el-col> | ||
| 282 | - <el-col :span="12" v-if="props.nodeVersion !== 'LITE'"> | ||
| 283 | - <my-card :title="$t('dashboard.sqlResponseTime')" height="255" :legend="[ | ||
| 284 | - {color: '#9CCC65', name: $t('metric.sqlResponseTime80')}, | ||
| 285 | - {color: '#00C7F9', name: $t('metric.sqlResponseTime95')}, | ||
| 286 | - ]" :bodyPadding="false"> | ||
| 287 | - <LazyLine | ||
| 288 | - :color="['#9CCC65', '#00C7F9']" | ||
| 289 | - :names="['sqlResponseTime80', 'sqlResponseTime95']" | ||
| 290 | - unit="ms" | ||
| 291 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1000))" | ||
| 292 | - /> | ||
| 293 | - </my-card> | ||
| 294 | - </el-col> | ||
| 295 | - <el-col :span="12"> | ||
| 296 | - <my-card :title="$t('dashboard.transactionLockInfo')" height="255" :legend="[ | ||
| 297 | - {color: '#E64A19', name: 'accessExclusiveLock'}, | ||
| 298 | - {color: '#0D86E2', name: 'accessShareLock'}, | ||
| 299 | - {color: '#9CCC65', name: 'ExclusiveLock'}, | ||
| 300 | - {color: '#00C7F9', name: 'ShareUpdateExclusiveLock'}, | ||
| 301 | - {color: '#0F866A', name: 'ShareRowExclusiveLock'}, | ||
| 302 | - {color: '#37D4D1', name: 'RowShareLock'}, | ||
| 303 | - {color: '#425ADD', name: 'RowExclusiveLock'}, | ||
| 304 | - {color: '#A97526', name: 'ShareLock'}, | ||
| 305 | - ]" :bodyPadding="false" :overflowHidden="false"> | ||
| 306 | - <LazyLine | ||
| 307 | - :color="['#E64A19', '#0D86E2', '#9CCC65', '#00C7F9', '#0F866A', '#37D4D1', '#425ADD', '#A97526']" | ||
| 308 | - :names="['accessExclusiveLock', 'accessShareLock', 'ExclusiveLock', 'ShareUpdateExclusiveLock', 'ShareRowExclusiveLock', 'RowShareLock', 'RowExclusiveLock', 'ShareLock']" | ||
| 309 | - :translate="false" | ||
| 310 | - /> | ||
| 311 | - </my-card> | ||
| 312 | - </el-col> | ||
| 313 | - <el-col :span="12"> | ||
| 314 | - <my-card :title="$t('dashboard.cacheHitRate')" height="255" :legend="[ | ||
| 315 | - {color: '#9CCC65', name: $t('metric.queryCacheHitRate')}, | ||
| 316 | - {color: '#00C7F9', name: $t('metric.databaseCacheHitRate')}, | ||
| 317 | - ]" :bodyPadding="false"> | ||
| 318 | - <LazyLine | ||
| 319 | - :color="['#9CCC65', '#00C7F9']" | ||
| 320 | - :names="['queryCacheHitRate', 'databaseCacheHitRate']" | ||
| 321 | - unit="%" | ||
| 322 | - :formatter="toFixed" | ||
| 323 | - /> | ||
| 324 | - </my-card> | ||
| 325 | - </el-col> | ||
| 326 | - <el-col :span="12"> | ||
| 327 | - <my-card :title="$t('dashboard.ioBlockNumberTrend')" height="255" :legend="[ | ||
| 328 | - {color: '#9CCC65', name: $t('metric.readPhysicalFileBlockNum')}, | ||
| 329 | - {color: '#00C7F9', name: $t('metric.writePhysicalFileBlockNum')}, | ||
| 330 | - ]" :bodyPadding="false"> | ||
| 331 | - <LazyLine | ||
| 332 | - :color="['#9CCC65', '#00C7F9']" | ||
| 333 | - :names="['readPhysicalFileBlockNum', 'writePhysicalFileBlockNum']" | ||
| 334 | - /> | ||
| 335 | - </my-card> | ||
| 336 | - </el-col> | ||
| 337 | - <el-col :span="12"> | ||
| 338 | - <my-card :title="$t('dashboard.ScrubDirtyPageInfo')" height="255" :legend="[ | ||
| 339 | - {color: '#9CCC65', name: $t('metric.lastBatchDirtyPageNum')}, | ||
| 340 | - {color: '#00C7F9', name: $t('metric.currentRemainingDirtyPages')}, | ||
| 341 | - ]" :bodyPadding="false"> | ||
| 342 | - <LazyLine | ||
| 343 | - :color="['#9CCC65', '#00C7F9']" | ||
| 344 | - :names="['lastBatchDirtyPageNum', 'currentRemainingDirtyPages']" | ||
| 345 | - /> | ||
| 346 | - </my-card> | ||
| 347 | - </el-col> | ||
| 348 | - </el-row> | ||
| 349 | -</my-card> | ||
| 350 | -<my-card :title="$t('dashboard.serverResources')" collapse> | ||
| 351 | - <el-row :gutter="16"> | ||
| 352 | - <el-col :span="12"> | ||
| 353 | - <my-card :title="$t('dashboard.loadAndCpu')" height="255" :legend="[ | ||
| 354 | - {color: '#E64A19', name: $t('metric.totalCoreNum')}, | ||
| 355 | - {color: '#9CCC65', name: $t('metric.total5mLoad')}, | ||
| 356 | - {color: '#00C7F9', name: $t('metric.totalAverageUtilization')}, | ||
| 357 | - ]" :bodyPadding="false"> | ||
| 358 | - <div class="linename"> | ||
| 359 | - <div>{{ $t('metric.totalCoreNum') }}</div> | ||
| 360 | - <div> | ||
| 361 | - <LazyLine | ||
| 362 | - :color="['#E64A19', '#9CCC65', '#00C7F9']" | ||
| 363 | - :names="['totalCoreNum', 'total5mLoad', 'totalAverageUtilization']" | ||
| 364 | - :nameIndexs="[2]" | ||
| 365 | - nameFix="1" | ||
| 366 | - scatterUnit="%" | ||
| 367 | - hasScatterData | ||
| 368 | - /> | ||
| 369 | - </div> | ||
| 370 | - <div>{{ $t('metric.totalAverageUtilization') }}</div> | ||
| 371 | - </div> | ||
| 372 | - </my-card> | ||
| 373 | - </el-col> | ||
| 374 | - <el-col :span="12"> | ||
| 375 | - <my-card :title="$t('dashboard.cpuUsage')" height="255" :legend="[ | ||
| 376 | - {color: '#E64A19', name: $t('metric.diskIOUsage')}, | ||
| 377 | - {color: '#0D86E2', name: $t('metric.systemUsage')}, | ||
| 378 | - {color: '#9CCC65', name: $t('metric.userUsage')}, | ||
| 379 | - {color: '#00C7F9', name: $t('metric.totalUsage')}, | ||
| 380 | - ]" :bodyPadding="false"> | ||
| 381 | - <LazyLine | ||
| 382 | - :color="['#E64A19', '#0D86E2', '#9CCC65', '#00C7F9']" | ||
| 383 | - :names="['diskIOUsage', 'systemUsage', 'userUsage', 'totalUsage']" | ||
| 384 | - unit="%" | ||
| 385 | - /> | ||
| 386 | - </my-card> | ||
| 387 | - </el-col> | ||
| 388 | - <el-col :span="12"> | ||
| 389 | - <my-card :title="$t('dashboard.memoryAndAverageMemory')" height="255" :legend="[ | ||
| 390 | - {color: '#9CCC65', name: $t('metric.totalMemory')}, | ||
| 391 | - {color: '#E64A19', name: $t('metric.usedMemory')}, | ||
| 392 | - {color: '#00C7F9', name: $t('metric.totalAverageUtilization')}, | ||
| 393 | - ]" :bodyPadding="false"> | ||
| 394 | - <div class="linename"> | ||
| 395 | - <div>{{ $t('metric.totalMemory') }}(GB)</div> | ||
| 396 | - <div> | ||
| 397 | - <LazyLine | ||
| 398 | - :color="['#9CCC65', '#E64A19', '#00C7F9']" | ||
| 399 | - :names="['totalMemory', 'usedMemory', 'totalAverageUtilization']" | ||
| 400 | - :nameIndexs="[2]" | ||
| 401 | - nameFix="2" | ||
| 402 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1073741824))" | ||
| 403 | - scatterUnit="%" | ||
| 404 | - hasScatterData | ||
| 405 | - /> | ||
| 406 | - </div> | ||
| 407 | - <div>{{ $t('metric.totalAverageUtilization') }}</div> | ||
| 408 | - </div> | ||
| 409 | - </my-card> | ||
| 410 | - </el-col> | ||
| 411 | - <el-col :span="12"> | ||
| 412 | - <my-card :title="$t('dashboard.diskAndAverageDisk')" height="255" :legend="[ | ||
| 413 | - {color: '#9CCC65', name: $t('metric.totalDisks')}, | ||
| 414 | - {color: '#E64A19', name: $t('metric.totalNumber')}, | ||
| 415 | - {color: '#00C7F9', name: $t('metric.totalAverageUtilization')}, | ||
| 416 | - ]" :bodyPadding="false"> | ||
| 417 | - <div class="linename"> | ||
| 418 | - <div>{{ $t('metric.totalDisks') }}(GB)</div> | ||
| 419 | - <div> | ||
| 420 | - <LazyLine | ||
| 421 | - :color="['#9CCC65', '#E64A19', '#00C7F9']" | ||
| 422 | - :names="['totalDisks', 'totalNumber', 'totalAverageUtilization']" | ||
| 423 | - :nameIndexs="[2]" | ||
| 424 | - nameFix="3" | ||
| 425 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1073741824))" | ||
| 426 | - scatterUnit="%" | ||
| 427 | - hasScatterData | ||
| 428 | - /> | ||
| 429 | - </div> | ||
| 430 | - <div>{{ $t('metric.totalAverageUtilization') }}</div> | ||
| 431 | - </div> | ||
| 432 | - </my-card> | ||
| 433 | - </el-col> | ||
| 434 | - <el-col :span="12"> | ||
| 435 | - <my-card :title="$t('dashboard.diskReadAndWriteRate')" height="255" style="margin-bottom: 0;" :legend="[ | ||
| 436 | - {color: '#0D86E2', name: $t('metric.read')}, | ||
| 437 | - {color: '#00C7F9', name: $t('metric.write')}, | ||
| 438 | - ]" :bodyPadding="false" :withTable="true"> | ||
| 439 | - <LazyLine | ||
| 440 | - :color="['#0D86E2', '#00C7F9']" | ||
| 441 | - :names="['read', 'write']" | ||
| 442 | - :nameIndexs="[0, 1]" | ||
| 443 | - nameFix="1" | ||
| 444 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1024))" | ||
| 445 | - unit="KB/s" | ||
| 446 | - @load-data="loadRateData" | ||
| 447 | - /> | ||
| 448 | - </my-card> | ||
| 449 | - <el-table :data="ioRateData" border> | ||
| 450 | - <el-table-column label="" prop="name" /> | ||
| 451 | - <el-table-column :label="$t('dashboard.currentRate')" prop="cur" /> | ||
| 452 | - <el-table-column :label="$t('dashboard.minimumRate')" prop="min" /> | ||
| 453 | - <el-table-column :label="$t('dashboard.averageRate')" prop="avg" /> | ||
| 454 | - <el-table-column :label="$t('dashboard.maxRate')" prop="max" /> | ||
| 455 | - </el-table> | ||
| 456 | - </el-col> | ||
| 457 | - <el-col :span="12"> | ||
| 458 | - <my-card :title="$t('dashboard.diskReadAndWritCapacity')" height="255" style="margin-bottom: 0;" :legend="[ | ||
| 459 | - {color: '#0D86E2', name: $t('metric.read')}, | ||
| 460 | - {color: '#00C7F9', name: $t('metric.write')}, | ||
| 461 | - ]" :bodyPadding="false" :withTable="true"> | ||
| 462 | - <LazyLine | ||
| 463 | - :color="['#0D86E2', '#00C7F9']" | ||
| 464 | - :names="['read', 'write']" | ||
| 465 | - :nameIndexs="[0, 1]" | ||
| 466 | - nameFix="2" | ||
| 467 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1048576))" | ||
| 468 | - unit="MB/s" | ||
| 469 | - @load-data="loadData" | ||
| 470 | - /> | ||
| 471 | - </my-card> | ||
| 472 | - <el-table :data="ioData" border> | ||
| 473 | - <el-table-column label="" prop="name" /> | ||
| 474 | - <el-table-column :label="$t('dashboard.currentCapacity')" prop="cur" /> | ||
| 475 | - <el-table-column :label="$t('dashboard.minimumCapacity')" prop="min" /> | ||
| 476 | - <el-table-column :label="$t('dashboard.averageCapacity')" prop="avg" /> | ||
| 477 | - <el-table-column :label="$t('dashboard.maxCapacity')" prop="max" /> | ||
| 478 | - </el-table> | ||
| 479 | - </el-col> | ||
| 480 | - <el-col :span="12"> | ||
| 481 | - <my-card :title="$t('dashboard.networkBandwidthUsage')" height="255" :legend="[ | ||
| 482 | - {color: '#0D86E2', name: $t('metric.upload')}, | ||
| 483 | - {color: '#00C7F9', name: $t('metric.download')}, | ||
| 484 | - ]" :bodyPadding="false"> | ||
| 485 | - <LazyLine | ||
| 486 | - :color="['#0D86E2', '#00C7F9']" | ||
| 487 | - :names="['upload', 'download']" | ||
| 488 | - unit="MB/s" | ||
| 489 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1048576))" | ||
| 490 | - /> | ||
| 491 | - </my-card> | ||
| 492 | - </el-col> | ||
| 493 | - <el-col :span="12"> | ||
| 494 | - <my-card :title="$t('dashboard.networkSocketConnection')" height="255" :legend="[ | ||
| 495 | - {color: '#0D86E2', name: 'TCPAlloc'}, | ||
| 496 | - {color: '#9CCC65', name: 'CurrEstab'}, | ||
| 497 | - {color: '#E64A19', name: 'TcpOutSegs'}, | ||
| 498 | - {color: '#0F866A', name: 'TcpInSegs'}, | ||
| 499 | - {color: '#37D4D1', name: 'UdpInuse'}, | ||
| 500 | - {color: '#425ADD', name: 'TcpTw'}, | ||
| 501 | - {color: '#A97526', name: 'TcpRetransSegs'}, | ||
| 502 | - {color: '#00C7F9', name: 'SocketsUsed'}, | ||
| 503 | - ]" :bodyPadding="false" :overflowHidden="false"> | ||
| 504 | - <div class="linename"> | ||
| 505 | - <div>{{ $t('dashboard.totalLoad') }}</div> | ||
| 506 | - <div> | ||
| 507 | - <LazyLine | ||
| 508 | - :color="['#0D86E2', '#9CCC65', '#E64A19', '#0F866A', '#37D4D1', '#425ADD', '#A97526', '#00C7F9']" | ||
| 509 | - :names="['TCP_alloc', 'CurrEStab', 'Tcp_OutSegs', 'Tcp_InSegs', 'UDP_inuse', 'TCP_tw', 'Tcp_RetransSegs', 'Sockets_used']" | ||
| 510 | - :formatter="toFixed" | ||
| 511 | - hasScatterData | ||
| 512 | - :translate="false" | ||
| 513 | - /> | ||
| 514 | - </div> | ||
| 515 | - <div>{{ $t('dashboard.allProtocolSocketsUsed') }}</div> | ||
| 516 | - </div> | ||
| 517 | - </my-card> | ||
| 518 | - </el-col> | ||
| 519 | - </el-row> | ||
| 520 | -</my-card> | ||
| 521 | - | ||
| 522 | -</template> | ||
| 523 | - | ||
| 524 | -<style scoped lang="scss"> | ||
| 525 | -.og-server { | ||
| 526 | - :deep(tr) { | ||
| 527 | - background-color: $og-background-color; | ||
| 528 | - } | ||
| 529 | - :deep(.el-table__inner-wrapper::before) { | ||
| 530 | - height: 0px; | ||
| 531 | - } | ||
| 532 | - :deep(.el-table__row:last-of-type td) { | ||
| 533 | - border-bottom: none; | ||
| 534 | - } | ||
| 535 | - :deep(.el-table__inner-wrapper tr:first-child td:first-child) { | ||
| 536 | - border-left: none; | ||
| 537 | - } | ||
| 538 | -} | ||
| 539 | -.instance_time { | ||
| 540 | - display: flex; | ||
| 541 | - justify-content: space-between; | ||
| 542 | - padding: 8px 16px 0; | ||
| 543 | - font-size: 12px; | ||
| 544 | - align-items: center; | ||
| 545 | - svg { | ||
| 546 | - margin-right: 8px; | ||
| 547 | - } | ||
| 548 | - | ||
| 549 | - &-tip { | ||
| 550 | - width: 68%; | ||
| 551 | - } | ||
| 552 | - &-button { | ||
| 553 | - width: 30%; | ||
| 554 | - } | ||
| 555 | - .el-button { | ||
| 556 | - text-decoration: underline; | ||
| 557 | - } | ||
| 558 | - &_tabs { | ||
| 559 | - :deep(.el-tabs__header) { | ||
| 560 | - padding: 0 16px; | ||
| 561 | - width: 100%; | ||
| 562 | - background-color: $og-border-color !important; | ||
| 563 | - } | ||
| 564 | - :deep(.el-tabs__content) { | ||
| 565 | - width: 100%; | ||
| 566 | - height: 100%; | ||
| 567 | - } | ||
| 568 | - } | ||
| 569 | -} | ||
| 570 | -.linename { | ||
| 571 | - display: flex; | ||
| 572 | - width: 100%; | ||
| 573 | - height: 100%; | ||
| 574 | - align-items: center; | ||
| 575 | - position: relative; | ||
| 576 | - justify-content: center; | ||
| 577 | - > div:nth-of-type(2) { | ||
| 578 | - width: calc(100% - 60px); | ||
| 579 | - height: 100%; | ||
| 580 | - margin: 0 10px; | ||
| 581 | - } | ||
| 582 | - > div:nth-of-type(1), > div:nth-of-type(3) { | ||
| 583 | - color: var(--el-color-line-text-color); | ||
| 584 | - font-size: 12px; | ||
| 585 | - text-align: center; | ||
| 586 | - position: absolute; | ||
| 587 | - width: 200px; | ||
| 588 | - height: 15px; | ||
| 589 | - } | ||
| 590 | - > div:nth-of-type(1) { | ||
| 591 | - transform: rotate(-90deg); | ||
| 592 | - left: -80px; | ||
| 593 | - } | ||
| 594 | - > div:nth-of-type(3) { | ||
| 595 | - transform: rotate(90deg); | ||
| 596 | - right: -80px; | ||
| 597 | - } | ||
| 598 | -} | ||
| 599 | -:deep(.og-card) { | ||
| 600 | - margin-bottom: 16px; | ||
| 601 | -} | ||
| 602 | -:deep(.og-card-body .el-row) { | ||
| 603 | - margin-bottom: -16px; | ||
| 604 | -} | ||
| 605 | -:deep(.el-table) { | ||
| 606 | - background-color: var(--el-bg-color-og); | ||
| 607 | - margin-bottom: 16px; | ||
| 608 | -} | ||
| 609 | -:deep(.el-table__header-wrapper th) { | ||
| 610 | - background-color: var(--el-bg-color-og); | ||
| 611 | - color: var(--el-text-color-og); | ||
| 612 | - } | ||
| 613 | -:deep(.el-table tr) { | ||
| 614 | - background-color: var(--el-bg-color-og); | ||
| 615 | -} | ||
| 616 | -:deep(.el-table th.el-table__cell) { | ||
| 617 | - background-color: var(--el-bg-color-og); | ||
| 618 | -} | ||
| 619 | - | ||
| 620 | -:deep(.el-table__row) { | ||
| 621 | - background-color: var(--el-bg-color-og); | ||
| 622 | -} | ||
| 623 | -:deep(.el-table__row th) { | ||
| 624 | - color: var(--el-text-color-og); | ||
| 625 | -} | ||
| 626 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/performance_load/ListMetric.vue+0-136
| @@ -1,136 +0,0 @@ | |||
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { storeToRefs } from 'pinia'; | ||
| 3 | -import { useRequest } from 'vue-request'; | ||
| 4 | -import { useIntervalTime } from '../../../hooks/time'; | ||
| 5 | -import ogRequest from '../../../request'; | ||
| 6 | -import { useMonitorStore } from '../../../store/monitor'; | ||
| 7 | - | ||
| 8 | -const { tab, refreshTime, instanceId } = storeToRefs(useMonitorStore()) | ||
| 9 | - | ||
| 10 | -const { data, run } = useRequest(() => { | ||
| 11 | - if (tab.value !== 0) { | ||
| 12 | - return new Promise(() => {}) | ||
| 13 | - } | ||
| 14 | - return ogRequest.get("/observability/v1/monitoring/server-metric", { | ||
| 15 | - // id: 'ogbrench', | ||
| 16 | - id: instanceId.value || 'ogbrench', | ||
| 17 | - }) | ||
| 18 | -}, { manual: true }) | ||
| 19 | - | ||
| 20 | -const formatter = (v: string | null, unit: string = '') => { | ||
| 21 | - if (v == null) { | ||
| 22 | - return '--' | ||
| 23 | - } | ||
| 24 | - let n = 1 | ||
| 25 | - if (unit && unit.startsWith('MB')) { | ||
| 26 | - n = 1048576 | ||
| 27 | - } else if (unit && unit.startsWith('KB')) { | ||
| 28 | - n = 1024 | ||
| 29 | - } | ||
| 30 | - return `${(Number.parseFloat(v) / n).toFixed(2)}${unit}` | ||
| 31 | -} | ||
| 32 | - | ||
| 33 | -useIntervalTime(() => { | ||
| 34 | - if (instanceId.value) { | ||
| 35 | - run(); | ||
| 36 | - } | ||
| 37 | -}, computed(() => refreshTime.value * 1000)) | ||
| 38 | -watch(instanceId, id => { | ||
| 39 | - if (id) { | ||
| 40 | - run() | ||
| 41 | - } | ||
| 42 | -}, { immediate: true }) | ||
| 43 | -</script> | ||
| 44 | - | ||
| 45 | -<template> | ||
| 46 | - <div class="og-list"> | ||
| 47 | - <div class="og-list-item"> | ||
| 48 | - <div> | ||
| 49 | - <div>{{ $t('dashboard.cpuUsage') }}</div> | ||
| 50 | - <div class="og-list-item--number">{{ (!data || data.cpu == undefined) ? '--' : formatter(data.cpu, '%') }}</div> | ||
| 51 | - </div> | ||
| 52 | - <svg-icon name="cpu" /> | ||
| 53 | - </div> | ||
| 54 | - <div class="og-list-item"> | ||
| 55 | - <div> | ||
| 56 | - <div>{{ $t('dashboard.load5m') }}</div> | ||
| 57 | - <div class="og-list-item--number">{{ (!data || !data.node_load5 || data.node_load5.value == undefined) ? '--' : formatter(data.node_load5.value) }}</div> | ||
| 58 | - </div> | ||
| 59 | - <svg-icon name="load" /> | ||
| 60 | - </div> | ||
| 61 | - <div class="og-list-item"> | ||
| 62 | - <div> | ||
| 63 | - <div>{{ $t('dashboard.memoryUsage') }}</div> | ||
| 64 | - <div class="og-list-item--number">{{ (!data || data.memory == undefined) ? '--' : formatter(data.memory, '%') }}</div> | ||
| 65 | - </div> | ||
| 66 | - <svg-icon name="memory" /> | ||
| 67 | - </div> | ||
| 68 | - <div class="og-list-item"> | ||
| 69 | - <div> | ||
| 70 | - <div>{{ $t('dashboard.diskReadRate') }}</div> | ||
| 71 | - <div class="og-list-item--number">{{ (!data || data.disk_read == undefined) ? '--' : formatter(data.disk_read, 'KB/s') }}</div> | ||
| 72 | - </div> | ||
| 73 | - <svg-icon name="disk" /> | ||
| 74 | - </div> | ||
| 75 | - <div class="og-list-item"> | ||
| 76 | - <div> | ||
| 77 | - <div>{{ $t('dashboard.diskWriteRate') }}</div> | ||
| 78 | - <div class="og-list-item--number">{{ (!data || data.disk_written == undefined) ? '--' : formatter(data.disk_written, 'KB/s') }}</div> | ||
| 79 | - </div> | ||
| 80 | - <svg-icon name="disk" /> | ||
| 81 | - </div> | ||
| 82 | - <div class="og-list-item"> | ||
| 83 | - <div> | ||
| 84 | - <div>{{ $t('dashboard.uploadRate') }} </div> | ||
| 85 | - <div class="og-list-item--number">{{ (!data || data.network_transmit == undefined) ? '--' : formatter(data.network_transmit, 'MB/s') }}</div> | ||
| 86 | - </div> | ||
| 87 | - <svg-icon name="speed_up" /> | ||
| 88 | - </div> | ||
| 89 | - <div class="og-list-item"> | ||
| 90 | - <div> | ||
| 91 | - <div>{{ $t('dashboard.downloadRate') }}</div> | ||
| 92 | - <div class="og-list-item--number">{{ (!data || data.network_receive == undefined) ? '--' : formatter(data.network_receive, 'MB/s') }}</div> | ||
| 93 | - </div> | ||
| 94 | - <svg-icon name="speed_down" /> | ||
| 95 | - </div> | ||
| 96 | - </div> | ||
| 97 | -</template> | ||
| 98 | - | ||
| 99 | -<style scoped lang="scss"> | ||
| 100 | - .og-list { | ||
| 101 | - margin-bottom: 16px; | ||
| 102 | - display: flex; | ||
| 103 | - justify-content: center; | ||
| 104 | - align-items: center; | ||
| 105 | - gap: 10px; | ||
| 106 | - height: 82px; | ||
| 107 | - background: var(--el-bg-color-og); | ||
| 108 | - border: 1px solid var(--el-og-border-color); | ||
| 109 | - border-radius: 8px; | ||
| 110 | - align-self: stretch; | ||
| 111 | - &-item { | ||
| 112 | - height: 66px; | ||
| 113 | - display: flex; | ||
| 114 | - justify-content: center; | ||
| 115 | - align-items: center; | ||
| 116 | - gap: 38px; | ||
| 117 | - flex: 1; | ||
| 118 | - min-width: 0; | ||
| 119 | - border-right: 1px solid var(--el-og-border-color); | ||
| 120 | - &:last-of-type { | ||
| 121 | - border-right: none; | ||
| 122 | - } | ||
| 123 | - svg { | ||
| 124 | - width: 28px; | ||
| 125 | - height: 28px; | ||
| 126 | - fill: $og-svg-fill-color; | ||
| 127 | - } | ||
| 128 | - &--number { | ||
| 129 | - color: $og-sub-text-color; | ||
| 130 | - font-size: 16px; | ||
| 131 | - line-height: 24px; | ||
| 132 | - font-weight: 700; | ||
| 133 | - } | ||
| 134 | - } | ||
| 135 | - } | ||
| 136 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/system_configuration/Index.vue+0-354
| @@ -1,354 +0,0 @@ | |||
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { useRequest } from "vue-request"; | ||
| 3 | -import restRequest from "../../../request/restful"; | ||
| 4 | -import { useI18n } from "vue-i18n"; | ||
| 5 | -import { View, Guide } from "@element-plus/icons-vue"; | ||
| 6 | -import Password from "./password.vue"; | ||
| 7 | -import { FormRules, FormInstance, ElMessage } from 'element-plus' | ||
| 8 | - | ||
| 9 | -const { t } = useI18n(); | ||
| 10 | - | ||
| 11 | -const errorInfo = ref<string | Error>(); | ||
| 12 | - | ||
| 13 | -const props = withDefaults( | ||
| 14 | - defineProps<{ | ||
| 15 | - instanceId?: string; | ||
| 16 | - }>(), | ||
| 17 | - { | ||
| 18 | - instanceId: "", | ||
| 19 | - } | ||
| 20 | -); | ||
| 21 | - | ||
| 22 | -// nodeId sync | ||
| 23 | -const emit = defineEmits(["nodeIdChanged"]); | ||
| 24 | -const clusterComponent = ref(null); | ||
| 25 | -const culsterLoaded = ref<boolean>(false); | ||
| 26 | -const initNodeId = ref<string>(""); | ||
| 27 | -const syncNodeId = (syncNodeIdVal: string) => { | ||
| 28 | - if (syncNodeIdVal === null || syncNodeIdVal === "") return; | ||
| 29 | - if (!culsterLoaded.value) initNodeId.value = syncNodeIdVal; | ||
| 30 | - else { | ||
| 31 | - clusterComponent.value.setNodeId(syncNodeIdVal); | ||
| 32 | - nextTick(() => { | ||
| 33 | - refreshData(""); | ||
| 34 | - }); | ||
| 35 | - } | ||
| 36 | -}; | ||
| 37 | -defineExpose({ | ||
| 38 | - syncNodeId, | ||
| 39 | -}); | ||
| 40 | - | ||
| 41 | -const nodeId = ref<string>(""); | ||
| 42 | -const data = reactive<{ | ||
| 43 | - dbParamData: Array<Record<string, string>>; | ||
| 44 | - osParamData: Array<Record<string, string>>; | ||
| 45 | -}>({ | ||
| 46 | - dbParamData: [], | ||
| 47 | - osParamData: [], | ||
| 48 | -}); | ||
| 49 | - | ||
| 50 | -// password dialog | ||
| 51 | -const snapshotManageShown = ref(false); | ||
| 52 | -const showSnapshotManage = () => { | ||
| 53 | - snapshotManageShown.value = true; | ||
| 54 | -}; | ||
| 55 | -const changeModalSnapshotManage = (val: boolean) => { | ||
| 56 | - snapshotManageShown.value = val; | ||
| 57 | -}; | ||
| 58 | - | ||
| 59 | -// cluster component | ||
| 60 | -const handleClusterValue = (val: any) => { | ||
| 61 | - nodeId.value = val.length > 1 ? val[1] : ""; | ||
| 62 | - emit("nodeIdChanged", nodeId.value); | ||
| 63 | -}; | ||
| 64 | -const clusterLoaded = (val: any) => { | ||
| 65 | - culsterLoaded.value = true; | ||
| 66 | - if (initNodeId.value) { | ||
| 67 | - clusterComponent.value.setNodeId(initNodeId.value); | ||
| 68 | - nextTick(() => { | ||
| 69 | - refreshData(""); | ||
| 70 | - }); | ||
| 71 | - } | ||
| 72 | -}; | ||
| 73 | - | ||
| 74 | -const handleQuery = () => { | ||
| 75 | - if(!nodeId.value) { | ||
| 76 | - ElMessage({ | ||
| 77 | - showClose: true, | ||
| 78 | - message: t('configParam.queryValidInfo'), | ||
| 79 | - type: 'warning', | ||
| 80 | - }) | ||
| 81 | - return | ||
| 82 | - } | ||
| 83 | - showSnapshotManage(); | ||
| 84 | -}; | ||
| 85 | -const refreshData = (password: string,isRefresh: string) => { | ||
| 86 | - // requestDBData(password); | ||
| 87 | - // requestOSData(password); | ||
| 88 | - if(!nodeId.value) { | ||
| 89 | - ElMessage({ | ||
| 90 | - showClose: true, | ||
| 91 | - message: t('configParam.queryValidInfo'), | ||
| 92 | - type: 'warning', | ||
| 93 | - }) | ||
| 94 | - return | ||
| 95 | - } | ||
| 96 | - requestData(password,isRefresh) | ||
| 97 | -}; | ||
| 98 | -const {data: res, | ||
| 99 | - run: requestData, | ||
| 100 | - loading: loadingDBData, | ||
| 101 | -} = useRequest((password,isRefresh = "0") => { | ||
| 102 | - return restRequest | ||
| 103 | - .get("/observability/v1/param/paramInfo", { | ||
| 104 | - paramName: "", | ||
| 105 | - nodeId: nodeId.value, | ||
| 106 | - dbName: null, | ||
| 107 | - password, | ||
| 108 | - paramType: "", | ||
| 109 | - isRefresh | ||
| 110 | - }) | ||
| 111 | - .then(function (res) { | ||
| 112 | - return res; | ||
| 113 | - }) | ||
| 114 | - .catch(function (res) { | ||
| 115 | - data.dbParamData = []; | ||
| 116 | - data.osParamData = []; | ||
| 117 | - }); | ||
| 118 | -},{manual: true}); | ||
| 119 | -watch(res, (res) => { | ||
| 120 | - if(res && res.length > 0) { | ||
| 121 | - data.dbParamData = res.filter(item => item.paramType === 'DB'); | ||
| 122 | - data.osParamData = res.filter(item => item.paramType === 'OS'); | ||
| 123 | - } | ||
| 124 | - | ||
| 125 | -}); | ||
| 126 | -// const { | ||
| 127 | -// data: res, | ||
| 128 | -// run: requestDBData, | ||
| 129 | -// loading: loadingDBData, | ||
| 130 | -// } = useRequest( | ||
| 131 | -// (password) => { | ||
| 132 | -// return restRequest | ||
| 133 | -// .get("/observability/v1/param/databaseParamInfo", { | ||
| 134 | -// nodeId: nodeId.value, | ||
| 135 | -// }) | ||
| 136 | -// .then(function (res) { | ||
| 137 | -// return res; | ||
| 138 | -// }) | ||
| 139 | -// .catch(function (res) { | ||
| 140 | -// data.dbParamData = []; | ||
| 141 | -// }); | ||
| 142 | -// }, | ||
| 143 | -// { manual: true } | ||
| 144 | -// ); | ||
| 145 | -// watch(res, (res) => { | ||
| 146 | -// data.dbParamData = res; | ||
| 147 | -// }); | ||
| 148 | - | ||
| 149 | -// const { | ||
| 150 | -// data: resOS, | ||
| 151 | -// run: requestOSData, | ||
| 152 | -// loading: loadingOSData, | ||
| 153 | -// } = useRequest( | ||
| 154 | -// (password) => { | ||
| 155 | -// return restRequest | ||
| 156 | -// .get("/observability/v1/param/osParamInfo", { | ||
| 157 | -// paramName: "", | ||
| 158 | -// nodeId: nodeId.value, | ||
| 159 | -// dbName: null, | ||
| 160 | -// password, | ||
| 161 | -// isRefresh: null, | ||
| 162 | -// paramType: "", | ||
| 163 | -// }) | ||
| 164 | -// .then(function (res) { | ||
| 165 | -// return res; | ||
| 166 | -// }) | ||
| 167 | -// .catch(function (res) { | ||
| 168 | -// data.osParamData = null; | ||
| 169 | -// }); | ||
| 170 | -// }, | ||
| 171 | -// { manual: true } | ||
| 172 | -// ); | ||
| 173 | -// watch(resOS, (resOS) => { | ||
| 174 | -// data.osParamData = resOS; | ||
| 175 | -// }); | ||
| 176 | -const color = computed(() => { | ||
| 177 | - if (localStorage.getItem("theme") === "dark") return "#fcef92"; | ||
| 178 | - else return "#E41D1D"; | ||
| 179 | -}); | ||
| 180 | -onMounted(() => { | ||
| 181 | - | ||
| 182 | - // @ts-ignore | ||
| 183 | - const wujie = window.$wujie; | ||
| 184 | - // Judge whether it is a plug-in environment or a local environment through wujie | ||
| 185 | - if (wujie) { | ||
| 186 | - // Monitoring platform language change | ||
| 187 | - wujie?.bus.$on('opengauss-locale-change', (val: string) => { | ||
| 188 | - console.log('log-search catch locale change'); | ||
| 189 | - nextTick(() => { | ||
| 190 | - if(nodeId.value) { | ||
| 191 | - refreshData("","0"); | ||
| 192 | - } | ||
| 193 | - }); | ||
| 194 | - }); | ||
| 195 | - } | ||
| 196 | -}); | ||
| 197 | -</script> | ||
| 198 | - | ||
| 199 | -<template> | ||
| 200 | - <div class="" style="padding: 0px 15px"> | ||
| 201 | - <div class="search-form head"> | ||
| 202 | - <div class="filter title" style="margin-right: auto">{{ $t("configParam.tabTitle") }}</div> | ||
| 203 | - | ||
| 204 | - <div class="filter"> | ||
| 205 | - <ClusterCascader notClearable ref="clusterComponent" @loaded="clusterLoaded" :title="$t('datasource.cluterTitle')" @getCluster="handleClusterValue" /> | ||
| 206 | - </div> | ||
| 207 | - <div class="query filter"> | ||
| 208 | - <el-button @click="handleQuery">{{ $t("app.refresh") }}</el-button> | ||
| 209 | - <el-button type="primary" @click="refreshData('')">{{ $t("app.query") }}</el-button> | ||
| 210 | - </div> | ||
| 211 | - </div> | ||
| 212 | - <div class="list" v-loading="loadingDBData"> | ||
| 213 | - <div class="list-item"> | ||
| 214 | - <div class="item-title">{{ $t("configParam.systemConfig") }}</div> | ||
| 215 | - <div> | ||
| 216 | - <div class="item-list" v-for="item in data.osParamData" :key="item.seqNo"> | ||
| 217 | - <div class="item-list-left"> | ||
| 218 | - <div class="item-name">{{ item.paramName }}</div> | ||
| 219 | - <el-popover placement="top-start" :title="$t('configParam.paramDesc')" :width="200" trigger="hover" :content="item.paramDetail"> | ||
| 220 | - <template #reference> | ||
| 221 | - <el-icon class="detail-btn" :color="'#7d7d7d'" size="18px"> | ||
| 222 | - <View /> | ||
| 223 | - </el-icon> | ||
| 224 | - </template> | ||
| 225 | - </el-popover> | ||
| 226 | - </div> | ||
| 227 | - <div class="item-list-right"> | ||
| 228 | - <div class="item-value">{{ item.actualValue === undefined || item.actualValue === null ? "--" : item.actualValue }}</div> | ||
| 229 | - <div class="suggest-btn-container"> | ||
| 230 | - <el-popover placement="top-start" :title="$t('configParam.paramTuning')" :width="300" trigger="hover" v-if="item.suggestValue != undefined && item.suggestValue != null && item.suggestValue != '' && item.suggestValue != item.actualValue"> | ||
| 231 | - <template #reference> | ||
| 232 | - <el-icon class="suggest-btn" :color="color" size="18px" v-if="item.actualValue != item.suggestValue"> | ||
| 233 | - <Guide /> | ||
| 234 | - </el-icon> | ||
| 235 | - </template> | ||
| 236 | - <template #default> | ||
| 237 | - <div class="demo-rich-conent" style="display: flex; gap: 16px; flex-direction: column"> | ||
| 238 | - <div> | ||
| 239 | - <p class="demo-rich-content__name" style="margin: 0; font-weight: 500">{{ $t("configParam.suggestValue") }}{{ item.suggestValue }}</p> | ||
| 240 | - <p class="demo-rich-content__mention" style="margin: 0; font-size: 14px" v-if="item.suggestExplain">{{ $t("configParam.suggestReason") }}</p> | ||
| 241 | - <p class="demo-rich-content__mention" style="margin: 0; font-size: 14px" v-if="item.suggestExplain">{{ item.suggestExplain }}</p> | ||
| 242 | - </div> | ||
| 243 | - </div> | ||
| 244 | - </template> | ||
| 245 | - </el-popover> | ||
| 246 | - </div> | ||
| 247 | - </div> | ||
| 248 | - </div> | ||
| 249 | - </div> | ||
| 250 | - </div> | ||
| 251 | - <div class="list-item"> | ||
| 252 | - <div class="item-title">{{ $t("configParam.databaseConfig") }}</div> | ||
| 253 | - <div> | ||
| 254 | - <div class="item-list" v-for="item in data.dbParamData" :key="item.seqNo"> | ||
| 255 | - <div class="item-list-left"> | ||
| 256 | - <div class="item-name">{{ item.paramName }}</div> | ||
| 257 | - <el-popover placement="top-start" :title="$t('configParam.paramDesc')" :width="200" trigger="hover" :content="item.paramDetail"> | ||
| 258 | - <template #reference> | ||
| 259 | - <el-icon class="detail-btn" :color="'#7d7d7d'" size="18px"> | ||
| 260 | - <View /> | ||
| 261 | - </el-icon> | ||
| 262 | - </template> | ||
| 263 | - </el-popover> | ||
| 264 | - </div> | ||
| 265 | - <div class="item-list-right"> | ||
| 266 | - <div class="item-value">{{ item.actualValue === undefined || item.actualValue === null ? "--" : item.actualValue }}</div> | ||
| 267 | - <div class="suggest-btn-container"> | ||
| 268 | - <el-popover placement="top-start" :title="$t('configParam.paramTuning')" :width="300" trigger="hover" v-if="item.suggestValue != undefined && item.suggestValue != null && item.suggestValue != '' && item.suggestValue != item.actualValue"> | ||
| 269 | - <template #reference> | ||
| 270 | - <el-icon class="suggest-btn" :color="color" size="18px" v-if="item.actualValue != item.suggestValue"> | ||
| 271 | - <Guide /> | ||
| 272 | - </el-icon> | ||
| 273 | - </template> | ||
| 274 | - <template #default> | ||
| 275 | - <div class="demo-rich-conent" style="display: flex; gap: 16px; flex-direction: column"> | ||
| 276 | - <div> | ||
| 277 | - <p class="demo-rich-content__name" style="margin: 0; font-weight: 500">{{ $t("configParam.suggestValue") }}{{ item.suggestValue }}</p> | ||
| 278 | - <p class="demo-rich-content__mention" style="margin: 0; font-size: 14px" v-if="item.suggestExplain">{{ $t("configParam.suggestReason") }}</p> | ||
| 279 | - <p class="demo-rich-content__mention" style="margin: 0; font-size: 14px" v-if="item.suggestExplain">{{ item.suggestExplain }}</p> | ||
| 280 | - </div> | ||
| 281 | - </div> | ||
| 282 | - </template> | ||
| 283 | - </el-popover> | ||
| 284 | - </div> | ||
| 285 | - </div> | ||
| 286 | - </div> | ||
| 287 | - </div> | ||
| 288 | - </div> | ||
| 289 | - </div> | ||
| 290 | - <my-message v-if="errorInfo" type="error" :tip="errorInfo" defaultTip="" /> | ||
| 291 | - <Password :show="snapshotManageShown" @changeModal="changeModalSnapshotManage" @confirm="refreshData" /> | ||
| 292 | - </div> | ||
| 293 | -</template> | ||
| 294 | - | ||
| 295 | -<style scoped lang="scss"> | ||
| 296 | -@import "../../../assets/style/style1.scss"; | ||
| 297 | -.head { | ||
| 298 | - display: flex; | ||
| 299 | - align-items: center; | ||
| 300 | - margin-bottom: 15px; | ||
| 301 | - .title { | ||
| 302 | - font-size: 16px; | ||
| 303 | - font-weight: bold; | ||
| 304 | - } | ||
| 305 | -} | ||
| 306 | -.list { | ||
| 307 | - display: flex; | ||
| 308 | - flex-direction: row; | ||
| 309 | - .list-item { | ||
| 310 | - width: 50%; | ||
| 311 | - .item-title { | ||
| 312 | - font-size: 14px; | ||
| 313 | - font-weight: bold; | ||
| 314 | - margin-bottom: 5px; | ||
| 315 | - } | ||
| 316 | - .item-list { | ||
| 317 | - display: flex; | ||
| 318 | - margin: 5px 0px; | ||
| 319 | - .item-list-left { | ||
| 320 | - width: 55%; | ||
| 321 | - display: flex; | ||
| 322 | - align-items: center; | ||
| 323 | - flex-shrink: 0; | ||
| 324 | - .detail-btn { | ||
| 325 | - margin-left: 10px; | ||
| 326 | - } | ||
| 327 | - } | ||
| 328 | - .item-list-right { | ||
| 329 | - width: 40%; | ||
| 330 | - display: flex; | ||
| 331 | - align-items: center; | ||
| 332 | - overflow: hidden; | ||
| 333 | - padding-right: 20px; | ||
| 334 | - padding-left: 20px; | ||
| 335 | - vertical-align: middle; | ||
| 336 | - .item-value { | ||
| 337 | - display: inline-block; | ||
| 338 | - white-space: nowrap; | ||
| 339 | - overflow: hidden; | ||
| 340 | - text-overflow: ellipsis; | ||
| 341 | - text-align: left; | ||
| 342 | - } | ||
| 343 | - .suggest-btn-container { | ||
| 344 | - width: 20px; | ||
| 345 | - display: flex; | ||
| 346 | - } | ||
| 347 | - .suggest-btn { | ||
| 348 | - margin-left: 5px; | ||
| 349 | - } | ||
| 350 | - } | ||
| 351 | - } | ||
| 352 | - } | ||
| 353 | -} | ||
| 354 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/system_configuration/password.vue+0-78
| @@ -1,78 +0,0 @@ | |||
| 1 | -<template> | ||
| 2 | - <div class="dialog"> | ||
| 3 | - <el-dialog width="400px" :title="$t('configParam.rootPWDTitle')" v-model="visible" :close-on-click-modal="false" draggable @close="closeDialog"> | ||
| 4 | - <div class="dialog-content"> | ||
| 5 | - <el-form :model="formData" :rules="connectionFormRules" ref="connectionFormRef"> | ||
| 6 | - <el-form-item :label="t('configParam.rootPWD')" prop="rootPassword"> | ||
| 7 | - <el-input v-model="formData.rootPassword" show-password style="width: 200px; margin: 0 4px" /> | ||
| 8 | - </el-form-item> | ||
| 9 | - </el-form> | ||
| 10 | - </div> | ||
| 11 | - | ||
| 12 | - <template #footer> | ||
| 13 | - <el-button style="padding: 5px 20px" type="primary" @click="handleconfirmModel">{{ $t("app.confirm") }}</el-button> | ||
| 14 | - <el-button style="padding: 5px 20px" @click="handleCancelModel">{{ $t("app.cancel") }}</el-button> | ||
| 15 | - </template> | ||
| 16 | - </el-dialog> | ||
| 17 | - </div> | ||
| 18 | -</template> | ||
| 19 | - | ||
| 20 | -<script lang="ts" setup> | ||
| 21 | -import { cloneDeep } from "lodash-es"; | ||
| 22 | -import { FormRules, FormInstance } from "element-plus"; | ||
| 23 | -import { useI18n } from "vue-i18n"; | ||
| 24 | -import { encryptPassword } from "../../../utils/jsencrypt"; | ||
| 25 | -const { t } = useI18n(); | ||
| 26 | - | ||
| 27 | -const visible = ref(false); | ||
| 28 | -const props = withDefaults( | ||
| 29 | - defineProps<{ | ||
| 30 | - show: boolean; | ||
| 31 | - }>(), | ||
| 32 | - {} | ||
| 33 | -); | ||
| 34 | -watch( | ||
| 35 | - () => props.show, | ||
| 36 | - (newValue) => { | ||
| 37 | - visible.value = newValue; | ||
| 38 | - }, | ||
| 39 | - { immediate: true } | ||
| 40 | -); | ||
| 41 | - | ||
| 42 | -// form data | ||
| 43 | -const initFormData = { | ||
| 44 | - rootPassword: "", | ||
| 45 | -}; | ||
| 46 | -const formData = reactive(cloneDeep(initFormData)); | ||
| 47 | - | ||
| 48 | -// build | ||
| 49 | -const emit = defineEmits(["changeModal", "confirm"]); | ||
| 50 | -async function handleconfirmModel() { | ||
| 51 | - let result = await connectionFormRef.value?.validate(); | ||
| 52 | - if (!result) return; | ||
| 53 | - const encryptPwd = await encryptPassword(formData.rootPassword); | ||
| 54 | - const isRefresh = "1"; | ||
| 55 | - emit("confirm", encryptPwd,isRefresh); | ||
| 56 | - visible.value = false; | ||
| 57 | - formData.rootPassword = '' | ||
| 58 | - emit("changeModal", visible.value); | ||
| 59 | -} | ||
| 60 | -const connectionFormRef = ref<FormInstance>(); | ||
| 61 | -const connectionFormRules = reactive<FormRules>({ | ||
| 62 | - rootPassword: [{ required: true, message: t("configParam.rootPWDTitle"), trigger: "blur" }], | ||
| 63 | -}); | ||
| 64 | - | ||
| 65 | -const handleCancelModel = () => { | ||
| 66 | - visible.value = false; | ||
| 67 | - formData.rootPassword = '' | ||
| 68 | - emit("changeModal", visible.value); | ||
| 69 | -}; | ||
| 70 | -const closeDialog = () => { | ||
| 71 | - visible.value = false; | ||
| 72 | - formData.rootPassword = '' | ||
| 73 | - emit("changeModal", visible.value); | ||
| 74 | -}; | ||
| 75 | -</script> | ||
| 76 | -<style lang="scss" scoped> | ||
| 77 | -@import "../../../assets/style/style1.scss"; | ||
| 78 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/top_sql/Index.vue+0-206
| @@ -1,206 +0,0 @@ | |||
| 1 | -<template> | ||
| 2 | - <div class="top-sql"> | ||
| 3 | - <el-tabs v-model="typeTab"> | ||
| 4 | - <el-tab-pane label="DB_TIME" name="db_time" /> | ||
| 5 | - <el-tab-pane label="CPU_TIME" name="cpu_time" /> | ||
| 6 | - <el-tab-pane label="EXEC_TIME" name="execution_time" /> | ||
| 7 | - </el-tabs> | ||
| 8 | - <div class="top-sql-table" v-if="!errorInfo" v-loading="loading"> | ||
| 9 | - <el-table :data="data.tableData" border> | ||
| 10 | - <el-table-column label="SQLID"> | ||
| 11 | - <template #default="scope"> | ||
| 12 | - <a class="top-sql-table-id" @click="gotoTopsqlDetail(scope.row.debug_query_id)"> | ||
| 13 | - {{ scope.row.debug_query_id }} | ||
| 14 | - </a> | ||
| 15 | - </template> | ||
| 16 | - </el-table-column> | ||
| 17 | - <el-table-column :label="$t('sql.dbName')" prop="db_name"></el-table-column> | ||
| 18 | - <el-table-column :label="$t('sql.schemaName')" prop="schema_name"></el-table-column> | ||
| 19 | - <el-table-column :label="$t('sql.userName')" prop="user_name"></el-table-column> | ||
| 20 | - <el-table-column :label="$t('sql.applicationName')" prop="application_name"></el-table-column> | ||
| 21 | - <el-table-column | ||
| 22 | - :label="$t('sql.startTime')" | ||
| 23 | - :formatter="(r: any) => moment(r.start_time).format('YYYY-MM-DD HH:mm:ss')" | ||
| 24 | - width="120" | ||
| 25 | - /> | ||
| 26 | - <el-table-column | ||
| 27 | - :label="$t('sql.finishTime')" | ||
| 28 | - :formatter="(r: any) => moment(r.finish_time).format('YYYY-MM-DD HH:mm:ss')" | ||
| 29 | - width="120" | ||
| 30 | - /> | ||
| 31 | - <el-table-column :label="$t('sql.dbTime')" prop="db_time" width="110"></el-table-column> | ||
| 32 | - <el-table-column :label="$t('sql.cpuTime')" prop="cpu_time" width="115"></el-table-column> | ||
| 33 | - <el-table-column | ||
| 34 | - :label="$t('sql.excutionTime')" | ||
| 35 | - prop="execution_time" | ||
| 36 | - :width="i18n.global.locale.value === 'en' ? 150 : 105" | ||
| 37 | - ></el-table-column> | ||
| 38 | - </el-table> | ||
| 39 | - </div> | ||
| 40 | - <my-message v-if="errorInfo" type="error" :tip="errorInfo" defaultTip="" /> | ||
| 41 | - </div> | ||
| 42 | -</template> | ||
| 43 | - | ||
| 44 | -<script setup lang="ts"> | ||
| 45 | -import { useRequest } from 'vue-request' | ||
| 46 | -import moment from 'moment' | ||
| 47 | -import { useIntervalTime } from '../../../hooks/time' | ||
| 48 | -import { useMonitorStore } from '../../../store/monitor' | ||
| 49 | -import { storeToRefs } from 'pinia' | ||
| 50 | -import ogRequest from '../../../request' | ||
| 51 | -import router from '../../../router' | ||
| 52 | -import { i18n } from '../../../i18n' | ||
| 53 | -import { useI18n } from 'vue-i18n' | ||
| 54 | - | ||
| 55 | -const { t } = useI18n() | ||
| 56 | - | ||
| 57 | -const typeTab = ref('db_time') | ||
| 58 | -const errorInfo = ref<string | Error>() | ||
| 59 | - | ||
| 60 | -const props = withDefaults( | ||
| 61 | - defineProps<{ | ||
| 62 | - instanceId?: string | ||
| 63 | - }>(), | ||
| 64 | - { | ||
| 65 | - instanceId: '', | ||
| 66 | - } | ||
| 67 | -) | ||
| 68 | - | ||
| 69 | -const data = reactive<{ | ||
| 70 | - tableData: Array<Record<string, string>> | ||
| 71 | -}>({ | ||
| 72 | - tableData: [], | ||
| 73 | -}) | ||
| 74 | - | ||
| 75 | -const curFilter = reactive({ | ||
| 76 | - dbid: '', | ||
| 77 | - startTime: '2022-09-24 00:00:00', | ||
| 78 | - finishTime: '2022-10-30 00:00:00', | ||
| 79 | -}) | ||
| 80 | - | ||
| 81 | -const { tab, time, refreshTime, autoRefresh, rangeTime } = storeToRefs(useMonitorStore()) | ||
| 82 | - | ||
| 83 | -const { run: requestData, loading } = useRequest( | ||
| 84 | - (query) => { | ||
| 85 | - if (tab.value !== 1) { | ||
| 86 | - return new Promise(() => {}) | ||
| 87 | - } | ||
| 88 | - const res = new Promise((resolve, reject) => { | ||
| 89 | - const result = ogRequest.getNative( | ||
| 90 | - `/observability/v1/topsql/list?id=${query.dbid}&startTime=${query.startTime}&finishTime=${query.finishTime}&orderField=${typeTab.value}` | ||
| 91 | - ) | ||
| 92 | - result ? resolve(result) : reject(result) | ||
| 93 | - }) | ||
| 94 | - .then((r: any) => { | ||
| 95 | - const code = r?.data.code | ||
| 96 | - const list = r?.data.data | ||
| 97 | - if (code === '602') { | ||
| 98 | - errorInfo.value = t('dashboard.topsqlListTip') | ||
| 99 | - } else if (code === '200' && Array.isArray(list)) { | ||
| 100 | - data.tableData = list | ||
| 101 | - } | ||
| 102 | - }) | ||
| 103 | - .catch((e) => { | ||
| 104 | - if (!props.instanceId) { | ||
| 105 | - errorInfo.value = t('dashboard.pleaseChooseinstanceId') | ||
| 106 | - } else { | ||
| 107 | - errorInfo.value = e | ||
| 108 | - } | ||
| 109 | - }) | ||
| 110 | - return res | ||
| 111 | - }, | ||
| 112 | - { manual: true } | ||
| 113 | -) | ||
| 114 | - | ||
| 115 | -useIntervalTime( | ||
| 116 | - () => { | ||
| 117 | - requestData(curFilter) | ||
| 118 | - }, | ||
| 119 | - computed(() => refreshTime.value * 1000) | ||
| 120 | -) | ||
| 121 | - | ||
| 122 | -const gotoTopsqlDetail = (id: string) => { | ||
| 123 | - const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 124 | - if (curMode === 'wujie') { | ||
| 125 | - // @ts-ignore plug-in components | ||
| 126 | - window.$wujie?.props.methods.jump({ | ||
| 127 | - name: `Static-pluginObservability-instanceVemSql_detail`, | ||
| 128 | - query: { | ||
| 129 | - dbid: curFilter.dbid, | ||
| 130 | - id, | ||
| 131 | - }, | ||
| 132 | - }) | ||
| 133 | - } else { | ||
| 134 | - // local | ||
| 135 | - window.sessionStorage.setItem('sqlId', id) | ||
| 136 | - router.push(`/vem/sql_detail/${curFilter.dbid}/${id}`) | ||
| 137 | - } | ||
| 138 | -} | ||
| 139 | - | ||
| 140 | -const setQueryTime = (range: number, curTime: [Date, Date] | null) => { | ||
| 141 | - if (range === -1 && curTime != null) { | ||
| 142 | - curFilter.startTime = moment(curTime[0]).format('YYYY-MM-DD HH:mm:ss') | ||
| 143 | - curFilter.finishTime = moment(curTime[1]).format('YYYY-MM-DD HH:mm:ss') | ||
| 144 | - return | ||
| 145 | - } | ||
| 146 | - if (range > 0) { | ||
| 147 | - const finishTimeStamp = new Date().getTime() | ||
| 148 | - const startTimeStamp = finishTimeStamp - range * 60 * 60 * 1000 | ||
| 149 | - curFilter.startTime = moment(startTimeStamp).format('YYYY-MM-DD HH:mm:ss') | ||
| 150 | - curFilter.finishTime = moment(finishTimeStamp).format('YYYY-MM-DD HH:mm:ss') | ||
| 151 | - } | ||
| 152 | -} | ||
| 153 | - | ||
| 154 | -setQueryTime(rangeTime.value, time.value) | ||
| 155 | - | ||
| 156 | -onMounted(() => { | ||
| 157 | - if (props.instanceId != null && props.instanceId !== '') { | ||
| 158 | - curFilter.dbid = props.instanceId | ||
| 159 | - } | ||
| 160 | - requestData(curFilter) | ||
| 161 | -}) | ||
| 162 | - | ||
| 163 | -watch( | ||
| 164 | - () => props.instanceId, | ||
| 165 | - (res) => { | ||
| 166 | - if (typeof res === 'string') { | ||
| 167 | - curFilter.dbid = res | ||
| 168 | - } | ||
| 169 | - } | ||
| 170 | -) | ||
| 171 | - | ||
| 172 | -watch(typeTab, () => { | ||
| 173 | - requestData(curFilter) | ||
| 174 | -}) | ||
| 175 | - | ||
| 176 | -watch(time, (curTime) => { | ||
| 177 | - setQueryTime(-1, curTime) | ||
| 178 | - requestData(curFilter) | ||
| 179 | -}) | ||
| 180 | - | ||
| 181 | -watch(rangeTime, (r) => { | ||
| 182 | - if (r === -1) { | ||
| 183 | - time.value = null | ||
| 184 | - return | ||
| 185 | - } | ||
| 186 | - setQueryTime(r, null) | ||
| 187 | - requestData(curFilter) | ||
| 188 | -}) | ||
| 189 | - | ||
| 190 | -watch(autoRefresh, () => { | ||
| 191 | - requestData(curFilter) | ||
| 192 | -}) | ||
| 193 | -</script> | ||
| 194 | - | ||
| 195 | -<style scoped lang="scss"> | ||
| 196 | -.top-sql { | ||
| 197 | - &:deep(.el-tabs__header) { | ||
| 198 | - width: 100%; | ||
| 199 | - } | ||
| 200 | - | ||
| 201 | - &-table-id { | ||
| 202 | - color: #0093ff; | ||
| 203 | - cursor: pointer; | ||
| 204 | - } | ||
| 205 | -} | ||
| 206 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/wdr/Index.vue+0-299
| @@ -1,299 +0,0 @@ | |||
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { useRequest } from "vue-request"; | ||
| 3 | -import moment from "moment"; | ||
| 4 | -import restRequest from "../../../request/restful"; | ||
| 5 | -import BuildWdr from "./build_wdr.vue"; | ||
| 6 | -import SnapshotManage from "./snapshot_manage.vue"; | ||
| 7 | -import { cloneDeep } from "lodash-es"; | ||
| 8 | -import { useI18n } from "vue-i18n"; | ||
| 9 | -const { t } = useI18n(); | ||
| 10 | - | ||
| 11 | -const shortcutsConfig = ref<any[]>( | ||
| 12 | - [{ text: t('dashboard.last1H'), value: 1 }, { text: t('dashboard.last3H'), value: 3 }, { text: t('dashboard.last6H'), value: 6 }] | ||
| 13 | -); | ||
| 14 | - | ||
| 15 | -const errorInfo = ref<string | Error>(); | ||
| 16 | - | ||
| 17 | -const props = withDefaults( | ||
| 18 | - defineProps<{ | ||
| 19 | - instanceId?: string; | ||
| 20 | - }>(), | ||
| 21 | - { | ||
| 22 | - instanceId: "", | ||
| 23 | - } | ||
| 24 | -); | ||
| 25 | - | ||
| 26 | -// nodeId sync | ||
| 27 | -const emit = defineEmits(["nodeIdChanged"]); | ||
| 28 | -const clusterComponent = ref(null); | ||
| 29 | -const culsterLoaded = ref<boolean>(false); | ||
| 30 | -const initNodeId = ref<string>(""); | ||
| 31 | -const syncNodeId = (syncNodeIdVal: string) => { | ||
| 32 | - if (syncNodeIdVal === null || syncNodeIdVal === "") return; | ||
| 33 | - if (!culsterLoaded.value) initNodeId.value = syncNodeIdVal; | ||
| 34 | - else { | ||
| 35 | - clusterComponent.value.setNodeId(syncNodeIdVal); | ||
| 36 | - if (syncNodeIdVal !== cluster.value[1]) { | ||
| 37 | - Object.assign(page, { pageSize: page.pageSize, total: 0, currentPage: 1 }); | ||
| 38 | - nextTick(() => { | ||
| 39 | - requestData(); | ||
| 40 | - }); | ||
| 41 | - } | ||
| 42 | - } | ||
| 43 | -}; | ||
| 44 | -defineExpose({ | ||
| 45 | - syncNodeId, | ||
| 46 | -}); | ||
| 47 | - | ||
| 48 | -const initFormData = { | ||
| 49 | - reportRange: "CLUSTER", | ||
| 50 | - reportType: "DETAIL", | ||
| 51 | - dateValue: [moment(new Date()).format("YYYY-MM-DD") + " 00:00:00", moment(new Date()).format("YYYY-MM-DD") + " 23:59:59"], | ||
| 52 | -}; | ||
| 53 | -const formData = reactive(cloneDeep(initFormData)); | ||
| 54 | -const tableData = ref<Array<any>>([]); | ||
| 55 | - | ||
| 56 | -const page = reactive({ | ||
| 57 | - currentPage: 1, | ||
| 58 | - pageSize: 10, | ||
| 59 | - total: 10, | ||
| 60 | -}); | ||
| 61 | -const snapshotManageShown = ref(false); | ||
| 62 | -const buildWDRShown = ref(false); | ||
| 63 | -const showSnapshotManage = () => { | ||
| 64 | - snapshotManageShown.value = true; | ||
| 65 | -}; | ||
| 66 | -const changeModalSnapshotManage = (val: boolean) => { | ||
| 67 | - snapshotManageShown.value = val; | ||
| 68 | -}; | ||
| 69 | -const showBuildWDR = () => { | ||
| 70 | - buildWDRShown.value = true; | ||
| 71 | -}; | ||
| 72 | -const changeModalBuildWDR = (val: boolean) => { | ||
| 73 | - buildWDRShown.value = val; | ||
| 74 | -}; | ||
| 75 | -const bandleCoveyBuildWDR = (code: number) => { | ||
| 76 | - requestData(); | ||
| 77 | -}; | ||
| 78 | -const handleQuery = () => { | ||
| 79 | - requestData(); | ||
| 80 | -}; | ||
| 81 | -const handleReset = () => { | ||
| 82 | - formData.reportRange = initFormData.reportRange; | ||
| 83 | - formData.reportType = initFormData.reportType; | ||
| 84 | - formData.dateValue = initFormData.dateValue; | ||
| 85 | - requestData(); | ||
| 86 | -}; | ||
| 87 | - | ||
| 88 | -const cluster = ref<Array<any>>([]); | ||
| 89 | -const handleClusterValue = (val: any) => { | ||
| 90 | - cluster.value = val; | ||
| 91 | - emit("nodeIdChanged", cluster.value[1]); | ||
| 92 | -}; | ||
| 93 | -const clusterLoaded = (val: any) => { | ||
| 94 | - culsterLoaded.value = true; | ||
| 95 | - if (initNodeId.value) { | ||
| 96 | - clusterComponent.value.setNodeId(initNodeId.value); | ||
| 97 | - nextTick(() => { | ||
| 98 | - requestData(); | ||
| 99 | - }); | ||
| 100 | - } | ||
| 101 | -}; | ||
| 102 | -const { | ||
| 103 | - data: res, | ||
| 104 | - run: requestData, | ||
| 105 | - loading, | ||
| 106 | -} = useRequest( | ||
| 107 | - () => { | ||
| 108 | - const clusterId = cluster.value.length ? cluster.value[0] : ""; | ||
| 109 | - return restRequest | ||
| 110 | - .get("/wdr/list", { | ||
| 111 | - clusterId, | ||
| 112 | - wdrScope: formData.reportRange, | ||
| 113 | - wdrType: formData.reportType, | ||
| 114 | - start: formData.dateValue && formData.dateValue.length > 0 ? formData.dateValue[0] : null, | ||
| 115 | - end: formData.dateValue && formData.dateValue.length > 1 ? formData.dateValue[1] : null, | ||
| 116 | - pageSize: page.pageSize, | ||
| 117 | - pageNum: page.currentPage, | ||
| 118 | - }) | ||
| 119 | - .then(function (res) { | ||
| 120 | - return res; | ||
| 121 | - }) | ||
| 122 | - .catch(function (res) { | ||
| 123 | - tableData.value = []; | ||
| 124 | - Object.assign(page, { pageSize: page.pageSize, total: 0, currentPage: 1 }); | ||
| 125 | - }); | ||
| 126 | - }, | ||
| 127 | - { manual: true } | ||
| 128 | -); | ||
| 129 | -type Res = | ||
| 130 | - | { | ||
| 131 | - records: string[]; | ||
| 132 | - pageNum: number; | ||
| 133 | - total: number; | ||
| 134 | - } | ||
| 135 | - | undefined; | ||
| 136 | -watch(res, (res: Res) => { | ||
| 137 | - if (res && res.records && res.records.length) { | ||
| 138 | - const { total } = res; | ||
| 139 | - tableData.value = res.records; | ||
| 140 | - Object.assign(page, { pageSize: page.pageSize, total }); | ||
| 141 | - } else { | ||
| 142 | - tableData.value = []; | ||
| 143 | - } | ||
| 144 | -}); | ||
| 145 | -const handleSizeChange = (val: number) => { | ||
| 146 | - page.currentPage = 1; | ||
| 147 | - page.pageSize = val; | ||
| 148 | - changePageCurrent(page.currentPage); | ||
| 149 | -}; | ||
| 150 | -const handleCurrentChange = (val: number) => { | ||
| 151 | - page.currentPage = val; | ||
| 152 | - changePageCurrent(page.currentPage); | ||
| 153 | -}; | ||
| 154 | -const changePageCurrent = (data: number) => { | ||
| 155 | - Object.assign(page, data); | ||
| 156 | - requestData(); | ||
| 157 | -}; | ||
| 158 | - | ||
| 159 | -// view WDR | ||
| 160 | -type Row = { | ||
| 161 | - wdrId: string; | ||
| 162 | - reportName: string; | ||
| 163 | -}; | ||
| 164 | -const { run: handleView, loading: viewing } = useRequest( | ||
| 165 | - (row: Row) => { | ||
| 166 | - return restRequest | ||
| 167 | - .get("/wdr/downloadWdr", { | ||
| 168 | - wdrId: row?.wdrId, | ||
| 169 | - }) | ||
| 170 | - .then(function (res) { | ||
| 171 | - const newWindow = window.open(row.reportName, "_blank"); | ||
| 172 | - newWindow?.document.write(res); | ||
| 173 | - }) | ||
| 174 | - .catch(function (res) {}); | ||
| 175 | - }, | ||
| 176 | - { manual: true } | ||
| 177 | -); | ||
| 178 | - | ||
| 179 | -// download WDR | ||
| 180 | -const { run: handleDownload, loading: downloading } = useRequest( | ||
| 181 | - (row: Row) => { | ||
| 182 | - return restRequest | ||
| 183 | - .get("/wdr/downloadWdr", { | ||
| 184 | - wdrId: row?.wdrId, | ||
| 185 | - }) | ||
| 186 | - .then(function (res) { | ||
| 187 | - if (res) { | ||
| 188 | - const blob = new Blob([res], { | ||
| 189 | - type: "text/plain", | ||
| 190 | - }); | ||
| 191 | - const a = document.createElement("a"); | ||
| 192 | - const URL = window.URL || window.webkitURL; | ||
| 193 | - const herf = URL.createObjectURL(blob); | ||
| 194 | - a.href = herf; | ||
| 195 | - a.download = row.reportName; | ||
| 196 | - document.body.appendChild(a); | ||
| 197 | - a.click(); | ||
| 198 | - document.body.removeChild(a); | ||
| 199 | - window.URL.revokeObjectURL(herf); | ||
| 200 | - } | ||
| 201 | - }) | ||
| 202 | - .catch(function (res) { | ||
| 203 | - tableData.value = []; | ||
| 204 | - Object.assign(page, { pageSize: page.pageSize, total: 0, currentPage: 1 }); | ||
| 205 | - }); | ||
| 206 | - }, | ||
| 207 | - { manual: true } | ||
| 208 | -); | ||
| 209 | - | ||
| 210 | -// delete row | ||
| 211 | -const { run: hanleDelete, loading: deleting } = useRequest( | ||
| 212 | - (row: Row) => { | ||
| 213 | - return restRequest | ||
| 214 | - .delete(`/wdr/del/${row.wdrId}`) | ||
| 215 | - .then(function (res) { | ||
| 216 | - requestData(); | ||
| 217 | - }) | ||
| 218 | - .catch(function (res) {}); | ||
| 219 | - }, | ||
| 220 | - { manual: true } | ||
| 221 | -); | ||
| 222 | -</script> | ||
| 223 | - | ||
| 224 | -<template> | ||
| 225 | - <div class="top-sql"> | ||
| 226 | - <div class="tab-wrapper-container"> | ||
| 227 | - <div class="search-form-multirow"> | ||
| 228 | - <div class="row"> | ||
| 229 | - <div class="filter"> | ||
| 230 | - <ClusterCascader ref="clusterComponent" @loaded="clusterLoaded" notClearable :title="$t('dashboard.wdrReports.clusterName')" @getCluster="handleClusterValue" /> | ||
| 231 | - </div> | ||
| 232 | - <div class="filter"> | ||
| 233 | - <span>{{ $t("dashboard.wdrReports.reportRange") }} </span> | ||
| 234 | - <el-select v-model="formData.reportRange" style="width: 160px; margin: 0 4px"> | ||
| 235 | - <el-option value="CLUSTER" :label="$t('dashboard.wdrReports.reportRangeSelect[0]')" /> | ||
| 236 | - <el-option value="NODE" :label="$t('dashboard.wdrReports.reportRangeSelect[1]')" /> | ||
| 237 | - </el-select> | ||
| 238 | - </div> | ||
| 239 | - <div class="filter"> | ||
| 240 | - <span>{{ $t("dashboard.wdrReports.reportType") }} </span> | ||
| 241 | - <el-select v-model="formData.reportType" style="width: 160px; margin: 0 4px"> | ||
| 242 | - <el-option value="DETAIL" :label="$t('dashboard.wdrReports.reportTypeSelect[0]')" /> | ||
| 243 | - <el-option value="SUMMARY" :label="$t('dashboard.wdrReports.reportTypeSelect[1]')" /> | ||
| 244 | - <el-option value="ALL" :label="$t('dashboard.wdrReports.reportTypeSelect[2]')" /> | ||
| 245 | - </el-select> | ||
| 246 | - </div> | ||
| 247 | - | ||
| 248 | - <div class="filter"> | ||
| 249 | - <span>{{ $t("dashboard.wdrReports.buildTime") }} </span> | ||
| 250 | - <MyDatePicker v-model="formData.dateValue" :teleported="true" :start-placeholder="$t('app.startDate')" :end-placeholder="$t('app.endDate')" :shortcutsConfig="shortcutsConfig" type="datetimerange" style="width: 300px" /> | ||
| 251 | - </div> | ||
| 252 | - </div> | ||
| 253 | - | ||
| 254 | - <div class="row"> | ||
| 255 | - <div class="filter"> | ||
| 256 | - <el-button @click="handleQuery">{{ $t("app.query") }}</el-button> | ||
| 257 | - <el-button @click="handleReset">{{ $t("app.reset") }}</el-button> | ||
| 258 | - <el-button type="primary" @click="showSnapshotManage">{{ $t("dashboard.wdrReports.snapshotManage") }}</el-button> | ||
| 259 | - <el-button type="primary" @click="showBuildWDR">{{ $t("dashboard.wdrReports.buildWDR") }}</el-button> | ||
| 260 | - </div> | ||
| 261 | - </div> | ||
| 262 | - </div> | ||
| 263 | - </div> | ||
| 264 | - | ||
| 265 | - <div class="page-container"> | ||
| 266 | - <div class="table-wrapper" v-loading="loading || viewing || downloading || deleting"> | ||
| 267 | - <el-table class="normal-table" :data="tableData" :header-cell-style="{ 'text-align': 'center' }" style="width: 100%" :default-sort="{ prop: 'date', order: 'descending' }"> | ||
| 268 | - <el-table-column prop="scope" :label="$t('dashboard.wdrReports.reportRange')" min-width="10%" align="center" /> | ||
| 269 | - <el-table-column prop="reportAt" :label="$t('dashboard.wdrReports.list.buildTime')" min-width="20%" align="center" /> | ||
| 270 | - <el-table-column prop="reportType" :label="$t('dashboard.wdrReports.reportType')" min-width="10%" align="center" /> | ||
| 271 | - <el-table-column prop="reportName" :label="$t('dashboard.wdrReports.list.reportName')" align="center" min-width="40%"/> | ||
| 272 | - <el-table-column :label="$t('app.operate')" align="center" fixed="right" min-width="20%"> | ||
| 273 | - <template #default="scope"> | ||
| 274 | - <div class="operate-btns"> | ||
| 275 | - <el-link size="small" type="primary" @click="handleView(scope.row)">{{ $t("app.view") }}</el-link> | ||
| 276 | - <el-link size="small" type="primary" @click="handleDownload(scope.row)">{{ $t("app.download") }}</el-link> | ||
| 277 | - <el-popconfirm title="Are you sure to delete this?" @confirm="hanleDelete(scope.row)"> | ||
| 278 | - <template #reference> | ||
| 279 | - <el-link size="small" type="primary">{{ $t("app.delete") }}</el-link> | ||
| 280 | - </template> | ||
| 281 | - </el-popconfirm> | ||
| 282 | - </div> | ||
| 283 | - </template> | ||
| 284 | - </el-table-column> | ||
| 285 | - </el-table> | ||
| 286 | - </div> | ||
| 287 | - </div> | ||
| 288 | - <el-pagination :currentPage="page.currentPage" :pageSize="page.pageSize" :total="page.total" :page-sizes="[10, 20, 30, 40]" class="pagination" layout="total,sizes,prev,pager,next" background small @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 289 | - | ||
| 290 | - <SnapshotManage :show="snapshotManageShown" @changeModal="changeModalSnapshotManage" /> | ||
| 291 | - <BuildWdr :show="buildWDRShown" @changeModal="changeModalBuildWDR" @conveyFlag="bandleCoveyBuildWDR" /> | ||
| 292 | - | ||
| 293 | - <my-message v-if="errorInfo" type="error" :tip="errorInfo" defaultTip="" /> | ||
| 294 | - </div> | ||
| 295 | -</template> | ||
| 296 | - | ||
| 297 | -<style scoped lang="scss"> | ||
| 298 | -@import "../../../assets/style/style1.scss"; | ||
| 299 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/wdr/build_wdr.vue+0-236
| @@ -1,236 +0,0 @@ | |||
| 1 | -<template> | ||
| 2 | - <div class="dialog"> | ||
| 3 | - <el-dialog | ||
| 4 | - width="400px" | ||
| 5 | - :title="$t('dashboard.wdrReports.buildWDR')" | ||
| 6 | - v-model="visible" | ||
| 7 | - :close-on-click-modal="false" | ||
| 8 | - draggable | ||
| 9 | - @close="taskClose" | ||
| 10 | - > | ||
| 11 | - <div class="dialog-content" v-loading="generating"> | ||
| 12 | - <el-form :model="formData" :rules="connectionFormRules" ref="connectionFormRef"> | ||
| 13 | - <el-form-item :label="$t('datasource.cluterTitle')" prop="hostId"> | ||
| 14 | - <ClusterCascader | ||
| 15 | - ref="clusterComponent" | ||
| 16 | - width="200" | ||
| 17 | - instanceValueKey="hostId" | ||
| 18 | - @loaded="loaded" | ||
| 19 | - @getCluster="handleClusterValue" | ||
| 20 | - notClearable | ||
| 21 | - /> | ||
| 22 | - </el-form-item> | ||
| 23 | - <el-form-item :label="$t('dashboard.wdrReports.reportRange')" prop="reportRange"> | ||
| 24 | - <el-select v-model="formData.scope" style="width: 200px; margin: 0 4px"> | ||
| 25 | - <el-option value="CLUSTER" :label="$t('dashboard.wdrReports.reportRangeSelect[0]')" /> | ||
| 26 | - <el-option value="NODE" :label="$t('dashboard.wdrReports.reportRangeSelect[1]')" /> | ||
| 27 | - </el-select> | ||
| 28 | - </el-form-item> | ||
| 29 | - <el-form-item :label="$t('dashboard.wdrReports.reportType')" prop="reportType"> | ||
| 30 | - <el-select v-model="formData.type" style="width: 200px; margin: 0 4px"> | ||
| 31 | - <el-option value="DETAIL" :label="$t('dashboard.wdrReports.reportTypeSelect[0]')" /> | ||
| 32 | - <el-option value="SUMMARY" :label="$t('dashboard.wdrReports.reportTypeSelect[1]')" /> | ||
| 33 | - <el-option value="ALL" :label="$t('dashboard.wdrReports.reportTypeSelect[2]')" /> | ||
| 34 | - </el-select> | ||
| 35 | - </el-form-item> | ||
| 36 | - <el-form-item :label="$t('dashboard.wdrReports.buildWDRDialog.startSnapshot')" prop="startId"> | ||
| 37 | - <el-select v-model="formData.startId" style="width: 200px; margin: 0 4px"> | ||
| 38 | - <el-option | ||
| 39 | - v-for="item in tableData" | ||
| 40 | - :key="item.snapshotId" | ||
| 41 | - :label="item.snapshotId" | ||
| 42 | - :value="item.snapshotId" | ||
| 43 | - :disabled="parseInt(item.snapshotId) >= parseInt(formData.endId)" | ||
| 44 | - /> | ||
| 45 | - </el-select> | ||
| 46 | - </el-form-item> | ||
| 47 | - <el-form-item :label="$t('dashboard.wdrReports.buildWDRDialog.endSnapshot')" prop="endId"> | ||
| 48 | - <el-select v-model="formData.endId" style="width: 200px; margin: 0 4px"> | ||
| 49 | - <el-option | ||
| 50 | - v-for="item in tableData" | ||
| 51 | - :key="item.snapshotId" | ||
| 52 | - :label="item.snapshotId" | ||
| 53 | - :value="item.snapshotId" | ||
| 54 | - :disabled="parseInt(item.snapshotId) <= parseInt(formData.startId)" | ||
| 55 | - /> | ||
| 56 | - </el-select> | ||
| 57 | - </el-form-item> | ||
| 58 | - </el-form> | ||
| 59 | - </div> | ||
| 60 | - | ||
| 61 | - <template #footer> | ||
| 62 | - <el-button style="padding: 5px 20px" :loading="generating" type="primary" @click="handleconfirmModel">{{ | ||
| 63 | - $t('dashboard.wdrReports.buildWDRDialog.build') | ||
| 64 | - }}</el-button> | ||
| 65 | - <el-button style="padding: 5px 20px" @click="handleCancelModel">{{ $t('app.cancel') }}</el-button> | ||
| 66 | - </template> | ||
| 67 | - </el-dialog> | ||
| 68 | - </div> | ||
| 69 | -</template> | ||
| 70 | - | ||
| 71 | -<script lang="ts" setup> | ||
| 72 | -import { cloneDeep } from 'lodash-es' | ||
| 73 | -import { useRequest } from 'vue-request' | ||
| 74 | -import { FormRules, FormInstance, ElMessage } from 'element-plus' | ||
| 75 | -import { useI18n } from 'vue-i18n' | ||
| 76 | -import restRequest from '@/request/restful' | ||
| 77 | -import { useMonitorStore } from '@/store/monitor' | ||
| 78 | -const { t } = useI18n() | ||
| 79 | - | ||
| 80 | -const visible = ref(true) | ||
| 81 | -const props = withDefaults(defineProps<{ tabId: string }>(), {}) | ||
| 82 | - | ||
| 83 | -const clusterComponent = ref<any>(null) | ||
| 84 | -const loaded = () => { | ||
| 85 | - let instanceId = useMonitorStore(props.tabId).instanceId | ||
| 86 | - if (instanceId && clusterComponent.value != null) { | ||
| 87 | - clusterComponent.value.setNodeId(instanceId) | ||
| 88 | - nextTick(() => { | ||
| 89 | - requestData() | ||
| 90 | - }) | ||
| 91 | - } | ||
| 92 | -} | ||
| 93 | - | ||
| 94 | -// form data | ||
| 95 | -const initFormData = { | ||
| 96 | - clusterId: '', | ||
| 97 | - endId: '', | ||
| 98 | - hostId: '', | ||
| 99 | - scope: 'CLUSTER', | ||
| 100 | - startId: '', | ||
| 101 | - type: 'DETAIL', | ||
| 102 | -} | ||
| 103 | -const formData = reactive(cloneDeep(initFormData)) | ||
| 104 | - | ||
| 105 | -// cluster component | ||
| 106 | -const handleClusterValue = (val: any) => { | ||
| 107 | - formData.clusterId = val.length ? val[0] : '' | ||
| 108 | - formData.hostId = val.length > 1 ? val[1] : '' | ||
| 109 | - if (formData.hostId) requestData() | ||
| 110 | -} | ||
| 111 | - | ||
| 112 | -// snapshotList | ||
| 113 | -const tableData = ref<Array<any>>([]) | ||
| 114 | -const { data: res, run: requestData } = useRequest( | ||
| 115 | - () => { | ||
| 116 | - return restRequest | ||
| 117 | - .get('/wdr/listSnapshot', { | ||
| 118 | - clusterId: formData.clusterId, | ||
| 119 | - hostId: formData.hostId, | ||
| 120 | - orderby: 'snapshot_id desc', | ||
| 121 | - pageSize: 20, | ||
| 122 | - pageNum: 1, | ||
| 123 | - }) | ||
| 124 | - .then(function (res) { | ||
| 125 | - return res | ||
| 126 | - }) | ||
| 127 | - .catch(function (res) { | ||
| 128 | - tableData.value = [] | ||
| 129 | - }) | ||
| 130 | - }, | ||
| 131 | - { manual: true } | ||
| 132 | -) | ||
| 133 | -watch(res, (res) => { | ||
| 134 | - if (res && res.records && res.records.length) { | ||
| 135 | - tableData.value = res.records | ||
| 136 | - if (tableData.value.length > 0) { | ||
| 137 | - formData.startId = tableData.value[tableData.value.length - 1].snapshotId | ||
| 138 | - formData.endId = tableData.value[0].snapshotId | ||
| 139 | - } | ||
| 140 | - } else { | ||
| 141 | - tableData.value = [] | ||
| 142 | - } | ||
| 143 | -}) | ||
| 144 | - | ||
| 145 | -// build | ||
| 146 | -const connectionFormRef = ref<FormInstance>() | ||
| 147 | -async function handleconfirmModel() { | ||
| 148 | - try { | ||
| 149 | - let result = await connectionFormRef.value?.validate() | ||
| 150 | - if (result) { | ||
| 151 | - buildWDR() | ||
| 152 | - } | ||
| 153 | - } catch (error) {} | ||
| 154 | -} | ||
| 155 | -const validateStartId = (rule: any, value: any, callback: any) => { | ||
| 156 | - if (!value || !formData.endId) { | ||
| 157 | - callback() | ||
| 158 | - } else { | ||
| 159 | - if (parseInt(value) >= parseInt(formData.endId)) { | ||
| 160 | - callback(new Error(t('datasource.trackFormRules[5]'))) | ||
| 161 | - return | ||
| 162 | - } | ||
| 163 | - callback() | ||
| 164 | - } | ||
| 165 | -} | ||
| 166 | -const validateEndId = (rule: any, value: any, callback: any) => { | ||
| 167 | - if (!value || !formData.startId) { | ||
| 168 | - callback() | ||
| 169 | - } else { | ||
| 170 | - if (parseInt(value) <= parseInt(formData.startId)) { | ||
| 171 | - callback(new Error(t('datasource.trackFormRules[6]'))) | ||
| 172 | - } | ||
| 173 | - callback() | ||
| 174 | - } | ||
| 175 | -} | ||
| 176 | -const connectionFormRules = reactive<FormRules>({ | ||
| 177 | - hostId: [{ required: true, message: t('datasource.trackFormRules[0]'), trigger: 'blur' }], | ||
| 178 | - startId: [ | ||
| 179 | - { required: true, message: t('datasource.trackFormRules[4]'), trigger: 'blur' }, | ||
| 180 | - { validator: validateStartId, trigger: 'blur' }, | ||
| 181 | - ], | ||
| 182 | - endId: [ | ||
| 183 | - { required: true, message: t('datasource.trackFormRules[4]'), trigger: 'blur' }, | ||
| 184 | - { validator: validateEndId, trigger: 'blur' }, | ||
| 185 | - ], | ||
| 186 | -}) | ||
| 187 | -const { | ||
| 188 | - data: rez, | ||
| 189 | - run: buildWDR, | ||
| 190 | - loading: generating, | ||
| 191 | -} = useRequest( | ||
| 192 | - () => { | ||
| 193 | - return restRequest.post('/wdr/generate', formData).then(function (res) { | ||
| 194 | - return res | ||
| 195 | - }) | ||
| 196 | - }, | ||
| 197 | - { | ||
| 198 | - manual: true, | ||
| 199 | - onSuccess: (res) => { | ||
| 200 | - if (res && res.code === 200) { | ||
| 201 | - const msg = t('dashboard.wdrReports.buildWDRDialog.buildSuccess') | ||
| 202 | - ElMessage({ | ||
| 203 | - showClose: true, | ||
| 204 | - message: msg, | ||
| 205 | - type: 'success', | ||
| 206 | - }) | ||
| 207 | - } else { | ||
| 208 | - const msg = t('dashboard.wdrReports.buildWDRDialog.buildFail') | ||
| 209 | - ElMessage({ | ||
| 210 | - showClose: true, | ||
| 211 | - message: msg, | ||
| 212 | - type: 'error', | ||
| 213 | - }) | ||
| 214 | - } | ||
| 215 | - }, | ||
| 216 | - } | ||
| 217 | -) | ||
| 218 | -watch(rez, (rez) => { | ||
| 219 | - emit('conveyFlag') | ||
| 220 | - visible.value = false | ||
| 221 | - emit('changeModal', visible.value) | ||
| 222 | -}) | ||
| 223 | - | ||
| 224 | -const emit = defineEmits(['changeModal', 'conveyFlag']) | ||
| 225 | -const taskClose = () => { | ||
| 226 | - visible.value = false | ||
| 227 | - emit('changeModal', visible.value) | ||
| 228 | -} | ||
| 229 | -const handleCancelModel = () => { | ||
| 230 | - visible.value = false | ||
| 231 | - emit('changeModal', visible.value) | ||
| 232 | -} | ||
| 233 | -</script> | ||
| 234 | -<style lang="scss" scoped> | ||
| 235 | -@import '@/assets/style/style1.scss'; | ||
| 236 | -</style> | ||
Dplugins/observability-instance/web-ui/src/pages/dashboard/wdr/snapshot_manage.vue+0-170
| @@ -1,170 +0,0 @@ | |||
| 1 | -<template> | ||
| 2 | - <div class="task-dialog"> | ||
| 3 | - <el-dialog width="800px" :title="$t('dashboard.wdrReports.snapshotManageDialog.dialogName')" v-model="show" :close-on-click-modal="false" draggable @close="taskClose"> | ||
| 4 | - <div class="dialog-content" v-loading="creatingSnapshot || reading"> | ||
| 5 | - <div class="search-form"> | ||
| 6 | - <div class="filter" style="margin-right: auto"> | ||
| 7 | - <el-button type="primary" @click="handelBuild">{{ $t("dashboard.wdrReports.snapshotManageDialog.createSnapshot") }}</el-button> | ||
| 8 | - </div> | ||
| 9 | - <div class="filter"> | ||
| 10 | - <div class="cluster-container-title">{{ $t("datasource.cluterTitle") }} </div> | ||
| 11 | - <ClusterCascader instanceValueKey="hostId" @loaded="requestData" @getCluster="handleClusterValue" autoSelectFirst :options="clusterList" notClearable /> | ||
| 12 | - </div> | ||
| 13 | - <div class="filter"> | ||
| 14 | - <el-button type="primary" @click="handleQuery">{{ $t("app.query") }}</el-button> | ||
| 15 | - </div> | ||
| 16 | - </div> | ||
| 17 | - | ||
| 18 | - <div class="table-wrapper"> | ||
| 19 | - <el-table :data="tableData" :header-cell-style="{ 'text-align': 'left' }" style="width: 100%" :default-sort="{ prop: 'date', order: 'descending' }"> | ||
| 20 | - <el-table-column prop="snapshotId" width="300" :label="$t('dashboard.wdrReports.snapshotManageDialog.snapshotID')" align="left" /> | ||
| 21 | - <el-table-column prop="endTs" :label="$t('dashboard.wdrReports.snapshotManageDialog.captureTime')" align="left" /> | ||
| 22 | - </el-table> | ||
| 23 | - <el-pagination :currentPage="page.currentPage" :pageSize="page.pageSize" :total="page.total" :page-sizes="[10, 20, 30, 40]" class="pagination" layout="total,sizes,prev,pager,next" background small @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 24 | - </div> | ||
| 25 | - </div> | ||
| 26 | - </el-dialog> | ||
| 27 | - </div> | ||
| 28 | -</template> | ||
| 29 | - | ||
| 30 | -<script lang="ts" setup> | ||
| 31 | -import { useRequest } from "vue-request"; | ||
| 32 | -import restRequest from "../../../request/restful"; | ||
| 33 | -import { FormRules, FormInstance, ElMessage } from 'element-plus' | ||
| 34 | - | ||
| 35 | -// const visible = ref(false); | ||
| 36 | -const props = withDefaults( | ||
| 37 | - defineProps<{ | ||
| 38 | - show: boolean; | ||
| 39 | - }>(), | ||
| 40 | - {} | ||
| 41 | -); | ||
| 42 | -const page = reactive({ | ||
| 43 | - pageSize: 10, | ||
| 44 | - currentPage: 1, | ||
| 45 | - total: 30, | ||
| 46 | -}); | ||
| 47 | -const handleSizeChange = (val: number) => { | ||
| 48 | - page.currentPage = 1; | ||
| 49 | - page.pageSize = val; | ||
| 50 | - changePageCurrent(page.currentPage); | ||
| 51 | -}; | ||
| 52 | -const handleCurrentChange = (val: number) => { | ||
| 53 | - page.currentPage = val; | ||
| 54 | - changePageCurrent(page.currentPage); | ||
| 55 | -}; | ||
| 56 | -const changePageCurrent = (data: number) => { | ||
| 57 | - Object.assign(page, data); | ||
| 58 | - requestData(); | ||
| 59 | -}; | ||
| 60 | -// watch( | ||
| 61 | -// () => props.show, | ||
| 62 | -// (newValue) => { | ||
| 63 | -// visible.value = newValue; | ||
| 64 | -// }, | ||
| 65 | -// { immediate: true } | ||
| 66 | -// ); | ||
| 67 | - | ||
| 68 | -const cluster = ref<Array<any>>([]); | ||
| 69 | -const handleClusterValue = (val: any) => { | ||
| 70 | - cluster.value = val; | ||
| 71 | -}; | ||
| 72 | - | ||
| 73 | -const handleQuery = () => { | ||
| 74 | - requestData(); | ||
| 75 | -}; | ||
| 76 | - | ||
| 77 | -const handelBuild = () => { | ||
| 78 | - createSnapshot() | ||
| 79 | - | ||
| 80 | -}; | ||
| 81 | -const { data:createRes, run: createSnapshot, loading: creatingSnapshot } = useRequest( | ||
| 82 | - () => { | ||
| 83 | - return restRequest | ||
| 84 | - .get("/wdr/createSnapshot", { | ||
| 85 | - clusterId: cluster.value.length ? cluster.value[0] : "", | ||
| 86 | - hostId: cluster.value.length > 1 ? cluster.value[1] : "", | ||
| 87 | - }) | ||
| 88 | - .then(function (res) { | ||
| 89 | - return res; | ||
| 90 | - }) | ||
| 91 | - .catch(function (res) {}); | ||
| 92 | - }, | ||
| 93 | - { manual: true, | ||
| 94 | - onSuccess: res => { | ||
| 95 | - if(res && res.code === 200) { | ||
| 96 | - ElMessage({ | ||
| 97 | - showClose: true, | ||
| 98 | - message: "创建成功!快照列表异步写入可能存在滞后,请手动刷新列表!", | ||
| 99 | - type: 'success', | ||
| 100 | - }) | ||
| 101 | - } | ||
| 102 | - reading.value=false | ||
| 103 | - // setTimeout(() => { | ||
| 104 | - // requestData(); | ||
| 105 | - // },800) | ||
| 106 | - }, | ||
| 107 | - } | ||
| 108 | -); | ||
| 109 | - | ||
| 110 | -// watch(createRes,(createRes) => { | ||
| 111 | -// if(createRes && createRes.code === 200) { | ||
| 112 | -// reading.value=true | ||
| 113 | -// setTimeout(() => { | ||
| 114 | -// requestData(); | ||
| 115 | -// },800) | ||
| 116 | -// } | ||
| 117 | -// }) | ||
| 118 | - | ||
| 119 | -// list Data | ||
| 120 | -const tableData = ref<Array<any>>([]); | ||
| 121 | -const { | ||
| 122 | - data: res, | ||
| 123 | - run: requestData, | ||
| 124 | - loading: reading, | ||
| 125 | -} = useRequest( | ||
| 126 | - () => { | ||
| 127 | - return restRequest | ||
| 128 | - .get("/wdr/listSnapshot", { | ||
| 129 | - clusterId: cluster.value.length ? cluster.value[0] : "", | ||
| 130 | - hostId: cluster.value.length > 1 ? cluster.value[1] : "", | ||
| 131 | - orderby: "snapshot_id desc", | ||
| 132 | - pageSize: page.pageSize, | ||
| 133 | - pageNum: page.currentPage, | ||
| 134 | - }) | ||
| 135 | - .then(function (res) { | ||
| 136 | - return res; | ||
| 137 | - }) | ||
| 138 | - .catch(function (res) { | ||
| 139 | - tableData.value = []; | ||
| 140 | - Object.assign(page, { pageSize: page.pageSize, total: 0, currentPage: 1 }); | ||
| 141 | - }); | ||
| 142 | - }, | ||
| 143 | - { manual: true } | ||
| 144 | -); | ||
| 145 | -type Res = | ||
| 146 | - | { | ||
| 147 | - records: string[]; | ||
| 148 | - pageNum: number; | ||
| 149 | - total: number; | ||
| 150 | - } | ||
| 151 | - | undefined; | ||
| 152 | -watch(res, (res: Res) => { | ||
| 153 | - if (res && res.records && res.records.length) { | ||
| 154 | - const { total } = res | ||
| 155 | - tableData.value = res.records; | ||
| 156 | - Object.assign(page, { pageSize: page.pageSize, total }) | ||
| 157 | - } else { | ||
| 158 | - tableData.value = []; | ||
| 159 | - } | ||
| 160 | -}); | ||
| 161 | - | ||
| 162 | -const emits = defineEmits(['changeModal']); | ||
| 163 | -const taskClose = () => { | ||
| 164 | - emits('changeModal',false) | ||
| 165 | -} | ||
| 166 | -</script> | ||
| 167 | - | ||
| 168 | -<style lang="scss" scoped> | ||
| 169 | -@import "../../../assets/style/style1.scss"; | ||
| 170 | -</style> | ||
| @@ -13,6 +13,40 @@ | |||
| 13 | <div class="cluster-title">{{ $t('instanceMonitor.clusterTitle') }}</div> | 13 | <div class="cluster-title">{{ $t('instanceMonitor.clusterTitle') }}</div> |
| 14 | 14 | ||
| 15 | <el-cascader v-model="clusterNodeId" :options="clusterList" /> | 15 | <el-cascader v-model="clusterNodeId" :options="clusterList" /> |
| 16 | + <svg-icon class="info-hollow" name="info-hollow" style="margin-left: 4px" @click="showInfo" /> | ||
| 17 | + <div style="position: relative" v-if="visible"> | ||
| 18 | + <div class="instance-info"> | ||
| 19 | + <div class="title-row"> | ||
| 20 | + <div class="title">{{ $t('instanceMonitor.nodeInfo.instanceInfo') }}</div> | ||
| 21 | + <svg-icon class="close" name="close" style="margin-left: 4px" @click="visible = false" /> | ||
| 22 | + </div> | ||
| 23 | + <div class="text" v-loading="loading"> | ||
| 24 | + <div>{{ $t('instanceMonitor.nodeInfo.databaseVersion') }}{{ nodeInfoData?.version }}</div> | ||
| 25 | + <div> | ||
| 26 | + {{ $t('instanceMonitor.nodeInfo.databaseStartTime') | ||
| 27 | + }}{{ moment(nodeInfoData?.time).format('YYYY-MM-DD HH:mm:ss') as string }} | ||
| 28 | + </div> | ||
| 29 | + <div>{{ $t('instanceMonitor.nodeInfo.databaseDataDirectory') }}{{ nodeInfoData?.dbDataPath }}</div> | ||
| 30 | + <div>{{ $t('instanceMonitor.nodeInfo.databaseLogDirectory') }}{{ nodeInfoData?.dbLogPath }}</div> | ||
| 31 | + <div> | ||
| 32 | + {{ $t('instanceMonitor.nodeInfo.enableArchiving') | ||
| 33 | + }}{{ | ||
| 34 | + nodeInfoData?.archiveMode === 'on' | ||
| 35 | + ? $t('instanceMonitor.nodeInfo.yes') | ||
| 36 | + : $t('instanceMonitor.nodeInfo.no') | ||
| 37 | + }} | ||
| 38 | + </div> | ||
| 39 | + <div>{{ $t('instanceMonitor.nodeInfo.operatingSystemVersion') }}{{ nodeInfoData?.osVersion }}</div> | ||
| 40 | + <div>{{ $t('instanceMonitor.nodeInfo.serverCPUManufacturer') }}{{ nodeInfoData?.CPUmanufacturer }}</div> | ||
| 41 | + <div>{{ $t('instanceMonitor.nodeInfo.serverCPUModel') }}{{ nodeInfoData?.CPUmodel }}</div> | ||
| 42 | + <div> | ||
| 43 | + {{ $t('instanceMonitor.nodeInfo.serverCPUCoreCount') }}{{ nodeInfoData?.CPUcores | ||
| 44 | + }}{{ $t('instanceMonitor.nodeInfo.cores') }} | ||
| 45 | + </div> | ||
| 46 | + <div>{{ $t('instanceMonitor.nodeInfo.totalMemorySize') }}{{ nodeInfoData?.TotalMemory }}</div> | ||
| 47 | + </div> | ||
| 48 | + </div> | ||
| 49 | + </div> | ||
| 16 | </div> | 50 | </div> |
| 17 | <div style="position: absolute; left: 0px; top: 5px; z-index: 9999" @click="toggleCollapse"> | 51 | <div style="position: absolute; left: 0px; top: 5px; z-index: 9999" @click="toggleCollapse"> |
| 18 | <el-icon v-if="!isCollapse" size="20px"><Fold /></el-icon> | 52 | <el-icon v-if="!isCollapse" size="20px"><Fold /></el-icon> |
| @@ -36,6 +70,7 @@ | |||
| 36 | <resource-monitor | 70 | <resource-monitor |
| 37 | ref="refResourceMonitor" | 71 | ref="refResourceMonitor" |
| 38 | @goto="goto" | 72 | @goto="goto" |
| 73 | + @changeCluster="toChangeCluster" | ||
| 39 | :tabId="tabId" | 74 | :tabId="tabId" |
| 40 | v-if="tabKeyLoaded.indexOf(tabKeys.ResourceMonitor) >= 0 || dashboardTabKey === tabKeys.ResourceMonitor" | 75 | v-if="tabKeyLoaded.indexOf(tabKeys.ResourceMonitor) >= 0 || dashboardTabKey === tabKeys.ResourceMonitor" |
| 41 | /> | 76 | /> |
| @@ -75,6 +110,15 @@ | |||
| 75 | :instanceId="instanceId" | 110 | :instanceId="instanceId" |
| 76 | /> | 111 | /> |
| 77 | </el-tab-pane> | 112 | </el-tab-pane> |
| 113 | + <el-tab-pane class="min-height" :label="'ASP'" :name="tabKeys.ASP"> | ||
| 114 | + <asp | ||
| 115 | + :tabId="tabId" | ||
| 116 | + @goto="goto" | ||
| 117 | + ref="aspComponent" | ||
| 118 | + v-if="tabKeyLoaded.indexOf(tabKeys.ASP) >= 0 || dashboardTabKey === tabKeys.ASP" | ||
| 119 | + :instanceId="instanceId" | ||
| 120 | + /> | ||
| 121 | + </el-tab-pane> | ||
| 78 | <el-tab-pane class="min-height" :label="$t('dashboard.systemConfig.tabName')" :name="tabKeys.SystemConfig"> | 122 | <el-tab-pane class="min-height" :label="$t('dashboard.systemConfig.tabName')" :name="tabKeys.SystemConfig"> |
| 79 | <systemConfiguration | 123 | <systemConfiguration |
| 80 | :tabId="tabId" | 124 | :tabId="tabId" |
| @@ -100,12 +144,15 @@ import ResourceMonitor from '@/pages/dashboardV2/resourceMonitor/Index.vue' | |||
| 100 | import InstanceMetrics from '@/pages/dashboardV2/instanceMonitor/instanceMetrics/Index.vue' | 144 | import InstanceMetrics from '@/pages/dashboardV2/instanceMonitor/instanceMetrics/Index.vue' |
| 101 | import TOPSQL from '@/pages/dashboardV2/instanceMonitor/topSQL/Index.vue' | 145 | import TOPSQL from '@/pages/dashboardV2/instanceMonitor/topSQL/Index.vue' |
| 102 | import Wdr from '@/pages/dashboardV2/wdr/Index.vue' | 146 | import Wdr from '@/pages/dashboardV2/wdr/Index.vue' |
| 147 | +import Asp from '@/pages/dashboardV2/asp/Index.vue' | ||
| 103 | import ogRequest from '@/request' | 148 | import ogRequest from '@/request' |
| 104 | import { useRequest } from 'vue-request' | 149 | import { useRequest } from 'vue-request' |
| 105 | import Install from '@/pages/dashboard/install/Index.vue' | 150 | import Install from '@/pages/dashboard/install/Index.vue' |
| 106 | import SystemConfiguration from '@/pages/dashboardV2/systemConfiguration/Index.vue' | 151 | import SystemConfiguration from '@/pages/dashboardV2/systemConfiguration/Index.vue' |
| 107 | import { tabKeys } from '@/pages/dashboardV2/common' | 152 | import { tabKeys } from '@/pages/dashboardV2/common' |
| 108 | import { uuid } from '@/shared' | 153 | import { uuid } from '@/shared' |
| 154 | +import { getNodeInfo } from '@/api/observability' | ||
| 155 | +import moment from 'moment' | ||
| 109 | 156 | ||
| 110 | type Res = | 157 | type Res = |
| 111 | | [ | 158 | | [ |
| @@ -119,7 +166,7 @@ const clusterNodeId = ref() | |||
| 119 | const clusterList = ref<Array<any>>([]) | 166 | const clusterList = ref<Array<any>>([]) |
| 120 | const nodeVersion = ref<string>('') | 167 | const nodeVersion = ref<string>('') |
| 121 | const lastNodeId = ref<string>('') | 168 | const lastNodeId = ref<string>('') |
| 122 | -const wdrComponent = ref(null) | 169 | +const wdrComponent = ref<InstanceType<typeof Wdr>>() |
| 123 | const paramConfigComponent = ref(null) | 170 | const paramConfigComponent = ref(null) |
| 124 | const performanceLoadRef = ref<InstanceType<typeof PerformanceLoad>>() | 171 | const performanceLoadRef = ref<InstanceType<typeof PerformanceLoad>>() |
| 125 | const refResourceMonitor = ref<InstanceType<typeof ResourceMonitor>>() | 172 | const refResourceMonitor = ref<InstanceType<typeof ResourceMonitor>>() |
| @@ -129,11 +176,37 @@ const dashboardTabKey = ref<string>('') | |||
| 129 | const tabId = uuid() | 176 | const tabId = uuid() |
| 130 | const { instanceId } = storeToRefs(useMonitorStore(tabId)) | 177 | const { instanceId } = storeToRefs(useMonitorStore(tabId)) |
| 131 | 178 | ||
| 179 | +const router = useRouter() | ||
| 132 | const tabKeyLoaded = ref<Array<string>>([]) | 180 | const tabKeyLoaded = ref<Array<string>>([]) |
| 133 | - | 181 | +const visible = ref(false) |
| 134 | onMounted(() => { | 182 | onMounted(() => { |
| 135 | dashboardTabKey.value = tabKeys.Home | 183 | dashboardTabKey.value = tabKeys.Home |
| 136 | }) | 184 | }) |
| 185 | +const toChangeCluster = (publicIp: string, port: string) => { | ||
| 186 | + for (let p1 = 0; p1 < clusterList.value.length; p1++) { | ||
| 187 | + const clusterTemp = clusterList.value[p1] | ||
| 188 | + for (let p2 = 0; p2 < clusterTemp.children.length; p2++) { | ||
| 189 | + const node = clusterTemp.children[p2] | ||
| 190 | + if (node.obj.publicIp === publicIp && node.obj.dbPort.toString() === port.toString()) { | ||
| 191 | + clusterNodeId.value = [clusterTemp.value, node.value] | ||
| 192 | + return | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + } | ||
| 196 | +} | ||
| 197 | +const toChangeClusterByNodeId = (nodeId: string) => { | ||
| 198 | + for (let p1 = 0; p1 < clusterList.value.length; p1++) { | ||
| 199 | + const clusterTemp = clusterList.value[p1] | ||
| 200 | + for (let p2 = 0; p2 < clusterTemp.children.length; p2++) { | ||
| 201 | + const node = clusterTemp.children[p2] | ||
| 202 | + if (node.obj.nodeId === nodeId) { | ||
| 203 | + clusterNodeId.value = [clusterTemp.value, node.value] | ||
| 204 | + return | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | +} | ||
| 209 | + | ||
| 137 | // tab render only once | 210 | // tab render only once |
| 138 | watch(dashboardTabKey, (v) => { | 211 | watch(dashboardTabKey, (v) => { |
| 139 | if (tabKeyLoaded.value.indexOf(v) < 0) tabKeyLoaded.value.push(v) | 212 | if (tabKeyLoaded.value.indexOf(v) < 0) tabKeyLoaded.value.push(v) |
| @@ -145,11 +218,19 @@ const { data: opsClusterData } = useRequest(() => ogRequest.get('/observability/ | |||
| 145 | watch(opsClusterData, (res: Res) => { | 218 | watch(opsClusterData, (res: Res) => { |
| 146 | if (res && Object.keys(res).length) { | 219 | if (res && Object.keys(res).length) { |
| 147 | clusterList.value = treeTransform(res) | 220 | clusterList.value = treeTransform(res) |
| 221 | + | ||
| 222 | + nextTick(() => { | ||
| 223 | + let paramsId = router.currentRoute.value.query.nodeId as string | ||
| 224 | + let nodeId = window.$wujie?.props.data.nodeId as string | ||
| 225 | + if (nodeId) toChangeClusterByNodeId(nodeId) | ||
| 226 | + else toChangeClusterByNodeId(paramsId) | ||
| 227 | + }) | ||
| 148 | } | 228 | } |
| 149 | }) | 229 | }) |
| 150 | 230 | ||
| 151 | // cluster changed | 231 | // cluster changed |
| 152 | watch(clusterNodeId, (res) => { | 232 | watch(clusterNodeId, (res) => { |
| 233 | + visible.value = false | ||
| 153 | // getInstanceId | 234 | // getInstanceId |
| 154 | let curInstanceId = instanceId.value | 235 | let curInstanceId = instanceId.value |
| 155 | if (typeof res === 'string') { | 236 | if (typeof res === 'string') { |
| @@ -165,17 +246,19 @@ watch(clusterNodeId, (res) => { | |||
| 165 | 246 | ||
| 166 | // find clusterId | 247 | // find clusterId |
| 167 | let clusterId = '' | 248 | let clusterId = '' |
| 249 | + let obj = {} | ||
| 168 | for (let p1 = 0; p1 < clusterList.value.length; p1++) { | 250 | for (let p1 = 0; p1 < clusterList.value.length; p1++) { |
| 169 | const clusterTemp = clusterList.value[p1] | 251 | const clusterTemp = clusterList.value[p1] |
| 170 | for (let p2 = 0; p2 < clusterTemp.children.length; p2++) { | 252 | for (let p2 = 0; p2 < clusterTemp.children.length; p2++) { |
| 171 | const node = clusterTemp.children[p2] | 253 | const node = clusterTemp.children[p2] |
| 172 | if (node.value === curInstanceId) { | 254 | if (node.value === curInstanceId) { |
| 173 | clusterId = clusterTemp.value | 255 | clusterId = clusterTemp.value |
| 256 | + obj = node.obj | ||
| 174 | break | 257 | break |
| 175 | } | 258 | } |
| 176 | } | 259 | } |
| 177 | } | 260 | } |
| 178 | - useMonitorStore(tabId).updateInstanceAndClusterId(curInstanceId, clusterId) | 261 | + useMonitorStore(tabId).updateInstanceAndClusterId(curInstanceId, clusterId, obj) |
| 179 | }) | 262 | }) |
| 180 | 263 | ||
| 181 | const isCollapse = ref(true) | 264 | const isCollapse = ref(true) |
| @@ -199,6 +282,11 @@ const goto = (key: string, param: object) => { | |||
| 199 | nextTick(() => { | 282 | nextTick(() => { |
| 200 | refResourceMonitor.value!.outsideGoto(key) | 283 | refResourceMonitor.value!.outsideGoto(key) |
| 201 | }) | 284 | }) |
| 285 | + } else if (key === tabKeys.WDR) { | ||
| 286 | + dashboardTabKey.value = tabKeys.WDR | ||
| 287 | + nextTick(() => { | ||
| 288 | + wdrComponent.value!.outsideGoto(param) | ||
| 289 | + }) | ||
| 202 | } | 290 | } |
| 203 | } | 291 | } |
| 204 | 292 | ||
| @@ -219,12 +307,20 @@ const treeTransform = (arr: any) => { | |||
| 219 | item.dbPort + | 307 | item.dbPort + |
| 220 | (item.clusterRole ? '(' + item.clusterRole + ')' : ''), | 308 | (item.clusterRole ? '(' + item.clusterRole + ')' : ''), |
| 221 | value: item.clusterId ? item.clusterId : item.nodeId, | 309 | value: item.clusterId ? item.clusterId : item.nodeId, |
| 310 | + obj: item, | ||
| 222 | children: treeTransform(item.clusterNodes), | 311 | children: treeTransform(item.clusterNodes), |
| 223 | }) | 312 | }) |
| 224 | }) | 313 | }) |
| 225 | } | 314 | } |
| 226 | return obj | 315 | return obj |
| 227 | } | 316 | } |
| 317 | +const showInfo = () => { | ||
| 318 | + if (!clusterNodeId.value) return | ||
| 319 | + visible.value = !visible.value | ||
| 320 | + loadNodeInfo(tabId) | ||
| 321 | +} | ||
| 322 | +const { data: nodeInfoData, run: loadNodeInfo, loading } = useRequest(getNodeInfo, { manual: true }) | ||
| 323 | +watch(nodeInfoData, () => {}, { deep: true }) | ||
| 228 | </script> | 324 | </script> |
| 229 | 325 | ||
| 230 | <style scoped lang="scss"> | 326 | <style scoped lang="scss"> |
| @@ -238,4 +334,48 @@ const treeTransform = (arr: any) => { | |||
| 238 | .min-height { | 334 | .min-height { |
| 239 | min-height: 500px !important; | 335 | min-height: 500px !important; |
| 240 | } | 336 | } |
| 337 | + | ||
| 338 | +.instance-info { | ||
| 339 | + position: absolute; | ||
| 340 | + z-index: 900; | ||
| 341 | + top: -18px; | ||
| 342 | + left: 0px; | ||
| 343 | + width: 406px; | ||
| 344 | + border-radius: 4px; | ||
| 345 | + background: #fff; | ||
| 346 | + box-shadow: 0px 8px 20px 0px rgba(0, 0, 0, 0.2); | ||
| 347 | + .title-row { | ||
| 348 | + display: flex; | ||
| 349 | + flex-direction: row; | ||
| 350 | + align-items: center; | ||
| 351 | + width: 406px; | ||
| 352 | + height: 36px; | ||
| 353 | + flex-shrink: 0; | ||
| 354 | + border-radius: 2px 2px 0px 0px; | ||
| 355 | + border-bottom: 1px solid var(--unnamed, #d9d9d9); | ||
| 356 | + background: var(--fill, #f7f7f7); | ||
| 357 | + .title { | ||
| 358 | + font-size: 14px; | ||
| 359 | + font-weight: 500; | ||
| 360 | + line-height: 24px; | ||
| 361 | + flex-grow: 1; | ||
| 362 | + text-align: left; | ||
| 363 | + padding-left: 24px; | ||
| 364 | + } | ||
| 365 | + .close { | ||
| 366 | + width: 16px; | ||
| 367 | + height: 16px; | ||
| 368 | + flex-shrink: 0; | ||
| 369 | + margin-right: 10px; | ||
| 370 | + } | ||
| 371 | + } | ||
| 372 | + | ||
| 373 | + .text { | ||
| 374 | + font-size: 12px; | ||
| 375 | + font-style: normal; | ||
| 376 | + font-weight: 400; | ||
| 377 | + line-height: 29px; | ||
| 378 | + padding: 12px 24px; | ||
| 379 | + } | ||
| 380 | +} | ||
| 241 | </style> | 381 | </style> |
| @@ -0,0 +1,528 @@ | |||
| 1 | +<template> | ||
| 2 | + <IndexBar :tabId="props.tabId"></IndexBar> | ||
| 3 | + <div style="margin-bottom: 38px"></div> | ||
| 4 | + <my-card :title="$t('instanceMonitor.asp.sampleActiveSessionCount')" height="200" :bodyPadding="false"> | ||
| 5 | + <LazyLine | ||
| 6 | + :rangeSelect="true" | ||
| 7 | + :tabId="props.tabId" | ||
| 8 | + :formatter="toFixed" | ||
| 9 | + :data="metricsData.sessionCount" | ||
| 10 | + :xData="metricsData.time" | ||
| 11 | + /> | ||
| 12 | + </my-card> | ||
| 13 | + | ||
| 14 | + <div class="gap-row"></div> | ||
| 15 | + | ||
| 16 | + <my-card :title="$t('instanceMonitor.asp.aspAnalysis')" height="300" :bodyPadding="false"> | ||
| 17 | + <div class="asp-row"> | ||
| 18 | + <div class="title">{{ $t('instanceMonitor.asp.analysisMetrics') }}</div> | ||
| 19 | + <el-select class="category" v-model="optionValue" @change="selectChange"> | ||
| 20 | + <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> | ||
| 21 | + </el-select> | ||
| 22 | + <div class="title">{{ $t('instanceMonitor.asp.filterConditions') }}</div> | ||
| 23 | + <div class="filter"> | ||
| 24 | + <div class="item" v-for="item in filter" :key="item"> | ||
| 25 | + {{ item.label }}={{ item.value }} | ||
| 26 | + <svg-icon class="close" name="close" style="margin-left: 4px" @click="removeFilter(item)" /> | ||
| 27 | + </div> | ||
| 28 | + </div> | ||
| 29 | + <div style="flex-grow: 1"></div> | ||
| 30 | + <div class="line-tips"> | ||
| 31 | + <div><svg-icon name="info" />{{ $t('instanceMonitor.asp.clickLegendToAddFilter') }}</div> | ||
| 32 | + </div> | ||
| 33 | + </div> | ||
| 34 | + <div style="height: 200px"> | ||
| 35 | + <LazyLine | ||
| 36 | + :tabId="props.tabId" | ||
| 37 | + :formatter="toFixed" | ||
| 38 | + :data="analyzeData.data" | ||
| 39 | + :xData="analyzeData.time" | ||
| 40 | + @legendSelected="legendSelected" | ||
| 41 | + :bar="true" | ||
| 42 | + /> | ||
| 43 | + </div> | ||
| 44 | + </my-card> | ||
| 45 | + | ||
| 46 | + <div class="gap-row"></div> | ||
| 47 | + | ||
| 48 | + <el-row :gutter="12" style="min-height: 420px;"> | ||
| 49 | + <el-col :span="12"> | ||
| 50 | + <div class="table-column"> | ||
| 51 | + <div class="header"> | ||
| 52 | + <el-select class="category" v-model="tableOption1" @change="selectChangeTable1"> | ||
| 53 | + <el-option v-for="item in tableOptions" :key="item.value" :label="item.label" :value="item.value" /> | ||
| 54 | + </el-select> | ||
| 55 | + </div> | ||
| 56 | + <el-table class="table" :table-layout="'auto'" :data="table1" style="width: 100%" :border="true"> | ||
| 57 | + <el-table-column :label="tableOptions.find((item) => item.value == tableOption1)?.label" width="150"> | ||
| 58 | + <template #default="scope"> | ||
| 59 | + <el-link type="primary" @click="gotoTopsqlDetail(scope.row.key)"> | ||
| 60 | + {{ scope.row.key }} | ||
| 61 | + </el-link> | ||
| 62 | + </template> | ||
| 63 | + </el-table-column> | ||
| 64 | + <el-table-column :label="$t('instanceMonitor.asp.sampleCount')"> | ||
| 65 | + <template #default="scope"> | ||
| 66 | + <div | ||
| 67 | + style=" | ||
| 68 | + width: 100%; | ||
| 69 | + display: flex; | ||
| 70 | + flex-direction: row; | ||
| 71 | + align-items: center; | ||
| 72 | + justify-content: flex-start; | ||
| 73 | + " | ||
| 74 | + > | ||
| 75 | + <div class="persent-row"> | ||
| 76 | + <div | ||
| 77 | + class="persent" | ||
| 78 | + :style="{ width: scope.row.persent ? scope.row.persent * 100 * 0.8 + '%' : 'auto' }" | ||
| 79 | + ></div> | ||
| 80 | + <div class="persent-text"> | ||
| 81 | + {{ scope.row.count }}({{ Number(scope.row.persent * 100).toFixed(2) }}%) | ||
| 82 | + </div> | ||
| 83 | + </div> | ||
| 84 | + </div> | ||
| 85 | + </template> | ||
| 86 | + </el-table-column> | ||
| 87 | + </el-table> | ||
| 88 | + </div> | ||
| 89 | + </el-col> | ||
| 90 | + <el-col :span="12"> | ||
| 91 | + <div class="table-column"> | ||
| 92 | + <div class="header"> | ||
| 93 | + <el-select class="category" v-model="tableOption2" @change="selectChangeTable2"> | ||
| 94 | + <el-option v-for="item in tableOptions" :key="item.value" :label="item.label" :value="item.value" /> | ||
| 95 | + </el-select> | ||
| 96 | + </div> | ||
| 97 | + <el-table class="table" :table-layout="'auto'" :data="table2" style="width: 100%" :border="true"> | ||
| 98 | + <el-table-column :label="tableOptions.find((item) => item.value == tableOption2)?.label" width="150"> | ||
| 99 | + <template #default="scope"> | ||
| 100 | + <el-link v-if="tableOption2 == 'sessionid'" type="primary" @click="gotoSessionDetail(scope.row.key)"> | ||
| 101 | + {{ scope.row.key }} | ||
| 102 | + </el-link> | ||
| 103 | + <el-link v-if="tableOption2 == 'queryId'" type="primary" @click="gotoTopsqlDetail(scope.row.key)"> | ||
| 104 | + {{ scope.row.key }} | ||
| 105 | + </el-link> | ||
| 106 | + </template> | ||
| 107 | + </el-table-column> | ||
| 108 | + <el-table-column :label="$t('instanceMonitor.asp.sampleCount')"> | ||
| 109 | + <template #default="scope"> | ||
| 110 | + <div | ||
| 111 | + style=" | ||
| 112 | + width: 100%; | ||
| 113 | + display: flex; | ||
| 114 | + flex-direction: row; | ||
| 115 | + align-items: center; | ||
| 116 | + justify-content: flex-start; | ||
| 117 | + " | ||
| 118 | + > | ||
| 119 | + <div class="persent-row"> | ||
| 120 | + <div | ||
| 121 | + class="persent" | ||
| 122 | + :style="{ width: scope.row.persent ? scope.row.persent * 100 * 0.8 + '%' : 'auto' }" | ||
| 123 | + ></div> | ||
| 124 | + <div class="persent-text"> | ||
| 125 | + {{ scope.row.count }}({{ Number(scope.row.persent * 100).toFixed(2) }}%) | ||
| 126 | + </div> | ||
| 127 | + </div> | ||
| 128 | + </div> | ||
| 129 | + </template> | ||
| 130 | + </el-table-column> | ||
| 131 | + </el-table> | ||
| 132 | + </div> | ||
| 133 | + </el-col> | ||
| 134 | + </el-row> | ||
| 135 | +</template> | ||
| 136 | + | ||
| 137 | +<script setup lang="ts"> | ||
| 138 | +import { useI18n } from 'vue-i18n' | ||
| 139 | +import LazyLine from '@/components/echarts/LazyLine.vue' | ||
| 140 | +import { useMonitorStore } from '@/store/monitor' | ||
| 141 | +import { toFixed } from '@/shared' | ||
| 142 | +import { storeToRefs } from 'pinia' | ||
| 143 | +import { getAspCount, getAspAnalysis } from '@/api/asp' | ||
| 144 | +import { useIntervalTime } from '@/hooks/time' | ||
| 145 | +import { tabKeys } from '@/pages/dashboardV2/common' | ||
| 146 | +import { useRequest } from 'vue-request' | ||
| 147 | +import router from '@/router' | ||
| 148 | + | ||
| 149 | +const { t } = useI18n() | ||
| 150 | + | ||
| 151 | +const props = withDefaults(defineProps<{ tabId: string }>(), {}) | ||
| 152 | + | ||
| 153 | +const optionValue = ref('applicationName') | ||
| 154 | +const options = [ | ||
| 155 | + { | ||
| 156 | + value: 'waitStatus', | ||
| 157 | + label: 'Wait Status', | ||
| 158 | + }, | ||
| 159 | + { | ||
| 160 | + value: 'event', | ||
| 161 | + label: 'Event', | ||
| 162 | + }, | ||
| 163 | + { | ||
| 164 | + value: 'databaseid', | ||
| 165 | + label: 'Database ID', | ||
| 166 | + }, | ||
| 167 | + { | ||
| 168 | + value: 'applicationName', | ||
| 169 | + label: 'Application Name', | ||
| 170 | + }, | ||
| 171 | +] | ||
| 172 | +const tableOption1 = ref('queryId') | ||
| 173 | +const tableOption2 = ref('sessionid') | ||
| 174 | +const tableOptions = [ | ||
| 175 | + { | ||
| 176 | + value: 'queryId', | ||
| 177 | + label: 'SQL ID', | ||
| 178 | + }, | ||
| 179 | + { | ||
| 180 | + value: 'sessionid', | ||
| 181 | + label: 'Session ID', | ||
| 182 | + }, | ||
| 183 | +] | ||
| 184 | + | ||
| 185 | +interface LineData { | ||
| 186 | + name: string | ||
| 187 | + data: any[] | ||
| 188 | + [other: string]: any | ||
| 189 | +} | ||
| 190 | +interface ActiveSessionData { | ||
| 191 | + sessionCount: LineData[] | ||
| 192 | + time: string[] | ||
| 193 | +} | ||
| 194 | +const metricsData = ref<ActiveSessionData>({ | ||
| 195 | + sessionCount: [], | ||
| 196 | + time: [], | ||
| 197 | +}) | ||
| 198 | +interface AnalyzeData { | ||
| 199 | + data: LineData[] | ||
| 200 | + time: string[] | ||
| 201 | +} | ||
| 202 | +const analyzeData = ref<AnalyzeData>({ | ||
| 203 | + data: [], | ||
| 204 | + time: [], | ||
| 205 | +}) | ||
| 206 | +const filter = ref<any[]>([]) | ||
| 207 | +const filterValue = ref<string[]>([]) | ||
| 208 | +const table1 = ref<any[]>([]) | ||
| 209 | +const table2 = ref<any[]>([]) | ||
| 210 | + | ||
| 211 | +const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId } = storeToRefs(useMonitorStore(props.tabId)) | ||
| 212 | + | ||
| 213 | +// same for every page in index | ||
| 214 | +const timer = ref<number>() | ||
| 215 | +onMounted(() => { | ||
| 216 | + load() | ||
| 217 | +}) | ||
| 218 | +watch( | ||
| 219 | + updateCounter, | ||
| 220 | + () => { | ||
| 221 | + clearInterval(timer.value) | ||
| 222 | + if (tabNow.value === tabKeys.ASP) { | ||
| 223 | + if (updateCounter.value.source === sourceType.value.INSTANCE) { | ||
| 224 | + load() | ||
| 225 | + } | ||
| 226 | + if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() | ||
| 227 | + if (updateCounter.value.source === sourceType.value.TIMETYPE) load() | ||
| 228 | + if (updateCounter.value.source === sourceType.value.TIMERANGE) load() | ||
| 229 | + if (updateCounter.value.source === sourceType.value.TABCHANGE) load() | ||
| 230 | + const time = autoRefreshTime.value | ||
| 231 | + timer.value = useIntervalTime( | ||
| 232 | + () => { | ||
| 233 | + load() | ||
| 234 | + }, | ||
| 235 | + computed(() => time * 1000) | ||
| 236 | + ) | ||
| 237 | + } | ||
| 238 | + }, | ||
| 239 | + { immediate: false } | ||
| 240 | +) | ||
| 241 | +const load = (checkTab?: boolean, checkRange?: boolean) => { | ||
| 242 | + if (!instanceId.value) return | ||
| 243 | + requestData(props.tabId) | ||
| 244 | + requestData2(props.tabId) | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +// load data | ||
| 248 | +const legendSelected = (key: string) => { | ||
| 249 | + if (!filter.value.some((item) => item.category === optionValue.value)) { | ||
| 250 | + filter.value.push({ | ||
| 251 | + category: optionValue.value, | ||
| 252 | + label: options.find((item) => item.value === optionValue.value)?.label, | ||
| 253 | + value: key, | ||
| 254 | + }) | ||
| 255 | + } | ||
| 256 | + filterValue.value = [] | ||
| 257 | + filter.value.forEach((filterItem) => { | ||
| 258 | + filterValue.value.push(filterItem.label + '=' + filterItem.value) | ||
| 259 | + }) | ||
| 260 | + analyzeData.value = getAnalyzeData() | ||
| 261 | +} | ||
| 262 | +const removeFilter = (item: any) => { | ||
| 263 | + let index = filter.value.indexOf(item) | ||
| 264 | + if (index >= 0) { | ||
| 265 | + filter.value.splice(index, 1) | ||
| 266 | + filterValue.value.splice(index, 1) | ||
| 267 | + } | ||
| 268 | + analyzeData.value = getAnalyzeData() | ||
| 269 | +} | ||
| 270 | +const { data: indexData, run: requestData } = useRequest(getAspCount, { manual: true }) | ||
| 271 | +watch( | ||
| 272 | + indexData, | ||
| 273 | + () => { | ||
| 274 | + // clear data | ||
| 275 | + metricsData.value.sessionCount = [] | ||
| 276 | + const baseData = indexData.value | ||
| 277 | + if (!baseData) return | ||
| 278 | + | ||
| 279 | + // TPS | ||
| 280 | + if (baseData) { | ||
| 281 | + metricsData.value.sessionCount.push({ | ||
| 282 | + data: baseData.sessionCount, | ||
| 283 | + name: t('instanceMonitor.asp.activeSessionCount'), | ||
| 284 | + }) | ||
| 285 | + metricsData.value.time = baseData.sampleTime | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + // time | ||
| 289 | + }, | ||
| 290 | + { deep: true } | ||
| 291 | +) | ||
| 292 | +const selectChange = () => { | ||
| 293 | + analyzeData.value = getAnalyzeData() | ||
| 294 | +} | ||
| 295 | +const selectChangeTable1 = () => { | ||
| 296 | + table1.value = getTopData(tableOption1.value) | ||
| 297 | +} | ||
| 298 | +const selectChangeTable2 = () => { | ||
| 299 | + table2.value = getTopData(tableOption2.value) | ||
| 300 | +} | ||
| 301 | +const { data: indexData2, run: requestData2 } = useRequest(getAspAnalysis, { manual: true }) | ||
| 302 | +watch( | ||
| 303 | + indexData2, | ||
| 304 | + () => { | ||
| 305 | + analyzeData.value = getAnalyzeData() | ||
| 306 | + // time | ||
| 307 | + }, | ||
| 308 | + { deep: true } | ||
| 309 | +) | ||
| 310 | +const getAnalyzeData = () => { | ||
| 311 | + analyzeData.value = { | ||
| 312 | + data: [], | ||
| 313 | + time: [], | ||
| 314 | + } | ||
| 315 | + // clear data | ||
| 316 | + let dataTemp: any[] = [] | ||
| 317 | + let timeTemp: Set<any> = new Set() | ||
| 318 | + if (indexData2.value) { | ||
| 319 | + table1.value = getTopData(tableOption1.value) | ||
| 320 | + table2.value = getTopData(tableOption2.value) | ||
| 321 | + | ||
| 322 | + let data = indexData2.value | ||
| 323 | + | ||
| 324 | + let categoryField = optionValue.value | ||
| 325 | + | ||
| 326 | + // output sampleTime Array | ||
| 327 | + timeTemp = new Set(data.map((obj) => obj.sampleTime)) | ||
| 328 | + | ||
| 329 | + let filterData = data.filter((obj) => { | ||
| 330 | + let match = true | ||
| 331 | + filter.value.forEach((filterItem) => { | ||
| 332 | + if (obj[filterItem.category] !== filterItem.value) match = false | ||
| 333 | + }) | ||
| 334 | + return match | ||
| 335 | + }) | ||
| 336 | + | ||
| 337 | + // Count the number of categoryField | ||
| 338 | + const categorySet = new Set(filterData.map((obj) => obj[categoryField])) | ||
| 339 | + | ||
| 340 | + dataTemp.push({ data: [], name: 'Total', type: 'line', step: 'middle' }) | ||
| 341 | + categorySet.forEach((categoryItem) => { | ||
| 342 | + dataTemp.push({ data: [], name: categoryItem, stack: 'Total', areaStyle: {} }) | ||
| 343 | + }) | ||
| 344 | + | ||
| 345 | + let lastDate = '' | ||
| 346 | + let indexData = -1 | ||
| 347 | + for (let index = 0; index < data.length; index++) { | ||
| 348 | + const element = data[index] | ||
| 349 | + if (element.sampleTime !== lastDate) { | ||
| 350 | + dataTemp.forEach((obj) => { | ||
| 351 | + obj.data.push(0) | ||
| 352 | + }) | ||
| 353 | + indexData++ | ||
| 354 | + lastDate = element.sampleTime | ||
| 355 | + } | ||
| 356 | + | ||
| 357 | + let match = true | ||
| 358 | + filter.value.forEach((filterItem) => { | ||
| 359 | + if (element[filterItem.category] !== filterItem.value) match = false | ||
| 360 | + }) | ||
| 361 | + if (match) { | ||
| 362 | + dataTemp.forEach((dateItem) => { | ||
| 363 | + if (dateItem.name === element[categoryField]) { | ||
| 364 | + dateItem.data[indexData]++ | ||
| 365 | + } | ||
| 366 | + }) | ||
| 367 | + } | ||
| 368 | + dataTemp[0].data[indexData]++ | ||
| 369 | + } | ||
| 370 | + } | ||
| 371 | + | ||
| 372 | + // time | ||
| 373 | + return { | ||
| 374 | + data: dataTemp, | ||
| 375 | + time: [...timeTemp], | ||
| 376 | + } | ||
| 377 | +} | ||
| 378 | +const getTopData = (analyzeField: any) => { | ||
| 379 | + let data = indexData2.value | ||
| 380 | + if (!data) return [] | ||
| 381 | + | ||
| 382 | + let filterData = data.filter((obj) => { | ||
| 383 | + let match = true | ||
| 384 | + filter.value.forEach((filterItem) => { | ||
| 385 | + if (obj[filterItem.category] !== filterItem.value) match = false | ||
| 386 | + }) | ||
| 387 | + return match | ||
| 388 | + }) | ||
| 389 | + | ||
| 390 | + const sum = filterData.reduce((accumulator: number) => accumulator + 1, 0) | ||
| 391 | + | ||
| 392 | + // Using the reduce method for grouping and counting. | ||
| 393 | + const countByQueryId = filterData.reduce((result, obj) => { | ||
| 394 | + const analyzeFiledValue = obj[analyzeField] | ||
| 395 | + result[analyzeFiledValue] = (result[analyzeFiledValue] || 0) + 1 | ||
| 396 | + return result | ||
| 397 | + }, {}) | ||
| 398 | + | ||
| 399 | + // Convert to an array and sort by occurrence count. | ||
| 400 | + const sortedArray = Object.entries(countByQueryId) | ||
| 401 | + .map(([key, count]) => ({ key, count, persent: ((count as number) / sum).toFixed(2) })) | ||
| 402 | + .sort((a, b) => (b.count as number) - (a.count as number)) | ||
| 403 | + | ||
| 404 | + return sortedArray.slice(0, 10) | ||
| 405 | +} | ||
| 406 | + | ||
| 407 | +const getParam = () => { | ||
| 408 | + return { | ||
| 409 | + dbid: instanceId, | ||
| 410 | + } | ||
| 411 | +} | ||
| 412 | +const gotoTopsqlDetail = (id: string) => { | ||
| 413 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 414 | + if (curMode === 'wujie') { | ||
| 415 | + // @ts-ignore plug-in components | ||
| 416 | + window.$wujie?.props.methods.jump({ | ||
| 417 | + name: `Static-pluginObservability-instanceVemSql_detail`, | ||
| 418 | + query: { | ||
| 419 | + dbid: getParam().dbid.value, | ||
| 420 | + id, | ||
| 421 | + }, | ||
| 422 | + }) | ||
| 423 | + } else { | ||
| 424 | + // local | ||
| 425 | + window.sessionStorage.setItem('sqlId', id) | ||
| 426 | + router.push(`/vem/sql_detail/${getParam().dbid.value}/${id}`) | ||
| 427 | + } | ||
| 428 | +} | ||
| 429 | +const gotoSessionDetail = (id: string) => { | ||
| 430 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 431 | + if (curMode === 'wujie') { | ||
| 432 | + // @ts-ignore plug-in components | ||
| 433 | + window.$wujie?.props.methods.jump({ | ||
| 434 | + name: `Static-pluginObservability-instanceVemSessionDetail`, | ||
| 435 | + query: { | ||
| 436 | + dbid: instanceId.value, | ||
| 437 | + id, | ||
| 438 | + }, | ||
| 439 | + }) | ||
| 440 | + } else { | ||
| 441 | + // local | ||
| 442 | + window.sessionStorage.setItem('sqlId', id) | ||
| 443 | + router.push(`/vem/sessionDetail/${instanceId.value}/${id}`) | ||
| 444 | + } | ||
| 445 | +} | ||
| 446 | +</script> | ||
| 447 | + | ||
| 448 | +<style scoped lang="scss"> | ||
| 449 | +.asp-row { | ||
| 450 | + font-size: 12px; | ||
| 451 | + display: flex; | ||
| 452 | + flex-direction: row; | ||
| 453 | + align-items: center; | ||
| 454 | + padding: 16px 16px 0px 16px; | ||
| 455 | + .title { | ||
| 456 | + flex-shrink: 0; | ||
| 457 | + margin-right: 6px; | ||
| 458 | + &:not(:first-child) { | ||
| 459 | + margin-left: 16px; | ||
| 460 | + } | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + .category { | ||
| 464 | + width: 150px; | ||
| 465 | + flex-shrink: 0; | ||
| 466 | + } | ||
| 467 | + .filter { | ||
| 468 | + min-width: 200px; | ||
| 469 | + padding: 0px 4px; | ||
| 470 | + height: 30px; | ||
| 471 | + align-items: center; | ||
| 472 | + border-radius: 2px; | ||
| 473 | + border: 1px solid var(--unnamed, #d9d9d9); | ||
| 474 | + display: flex; | ||
| 475 | + flex-direction: row; | ||
| 476 | + gap: 4px; | ||
| 477 | + overflow-x: auto; | ||
| 478 | + .item { | ||
| 479 | + height: 20px; | ||
| 480 | + padding: 0px 4px 0px 8px; | ||
| 481 | + border-radius: 2px; | ||
| 482 | + border: 1px solid var(--unnamed, #d9d9d9); | ||
| 483 | + background: var(--fill, #f7f7f7); | ||
| 484 | + flex-shrink: 0; | ||
| 485 | + } | ||
| 486 | + } | ||
| 487 | + .line-tips { | ||
| 488 | + position: inherit; | ||
| 489 | + margin-left: 16px; | ||
| 490 | + flex-shrink: 0; | ||
| 491 | + } | ||
| 492 | +} | ||
| 493 | +::-webkit-scrollbar { | ||
| 494 | + width: 1px; | ||
| 495 | + height: 5px; | ||
| 496 | + background-color: skyblue; | ||
| 497 | +} | ||
| 498 | +::-webkit-scrollbar-thumb { | ||
| 499 | + background-color: orange; | ||
| 500 | +} | ||
| 501 | +.table-column { | ||
| 502 | + .header { | ||
| 503 | + display: flex; | ||
| 504 | + padding: 4px; | ||
| 505 | + align-items: center; | ||
| 506 | + border-top: 1px solid var(--dividers, #f0f0f0); | ||
| 507 | + border-right: 1px solid var(--dividers, #f0f0f0); | ||
| 508 | + background: var(--fill, #f7f7f7); | ||
| 509 | + } | ||
| 510 | +} | ||
| 511 | + | ||
| 512 | +.persent-row { | ||
| 513 | + flex-grow: 1; | ||
| 514 | + position: relative; | ||
| 515 | + display: flex; | ||
| 516 | + flex-direction: row; | ||
| 517 | + align-items: center; | ||
| 518 | + .persent { | ||
| 519 | + min-width: 2px; | ||
| 520 | + height: 8px; | ||
| 521 | + border-radius: 1px; | ||
| 522 | + background: #246cff; | ||
| 523 | + } | ||
| 524 | + .persent-text { | ||
| 525 | + margin-left: 2px; | ||
| 526 | + } | ||
| 527 | +} | ||
| 528 | +</style> | ||
| @@ -3,37 +3,41 @@ | |||
| 3 | /// | 3 | /// |
| 4 | 4 | ||
| 5 | export type keyObject = { | 5 | export type keyObject = { |
| 6 | - Home: string | 6 | + Home: string |
| 7 | - WDR: string | 7 | + WDR: string |
| 8 | - SystemConfig: string | 8 | + ASP: string |
| 9 | - ResourceMonitor: string | 9 | + SystemConfig: string |
| 10 | - ResourceMonitorCPU: string | 10 | + ResourceMonitor: string |
| 11 | - ResourceMonitorMemory: string | 11 | + ResourceMonitorCPU: string |
| 12 | - ResourceMonitorIO: string | 12 | + ResourceMonitorMemory: string |
| 13 | - ResourceMonitorNetwork: string | 13 | + ResourceMonitorIO: string |
| 14 | - InstanceMonitor: string | 14 | + ResourceMonitorNetwork: string |
| 15 | - InstanceMonitorInstance: string | 15 | + InstanceMonitor: string |
| 16 | - InstanceMonitorSession: string | 16 | + InstanceMonitorInstance: string |
| 17 | - InstanceMonitorTOPSQL: string | 17 | + InstanceMonitorSession: string |
| 18 | - InstanceMonitorTOPSQLDBTime: string | 18 | + InstanceMonitorTOPSQL: string |
| 19 | - InstanceMonitorTOPSQLCPUTime: string | 19 | + InstanceMonitorTOPSQLDBTime: string |
| 20 | - InstanceMonitorTOPSQLEXECTime: string | 20 | + InstanceMonitorTOPSQLCPUTime: string |
| 21 | + InstanceMonitorTOPSQLEXECTime: string | ||
| 22 | + InstanceMonitorTOPSQLIOTime: string | ||
| 21 | } | 23 | } |
| 22 | 24 | ||
| 23 | export const tabKeys: keyObject = { | 25 | export const tabKeys: keyObject = { |
| 24 | - Home: 'Home', | 26 | + Home: 'Home', |
| 25 | - WDR: 'WDR', | 27 | + WDR: 'WDR', |
| 26 | - SystemConfig: 'SystemConfig', | 28 | + ASP: 'ASP', |
| 27 | - ResourceMonitor: 'ResourceMonitor', | 29 | + SystemConfig: 'SystemConfig', |
| 28 | - ResourceMonitorCPU: 'ResourceMonitorCPU', | 30 | + ResourceMonitor: 'ResourceMonitor', |
| 29 | - ResourceMonitorMemory: 'ResourceMonitorMemory', | 31 | + ResourceMonitorCPU: 'ResourceMonitorCPU', |
| 30 | - ResourceMonitorIO: 'ResourceMonitorIO', | 32 | + ResourceMonitorMemory: 'ResourceMonitorMemory', |
| 31 | - ResourceMonitorNetwork: 'ResourceMonitorNetwork', | 33 | + ResourceMonitorIO: 'ResourceMonitorIO', |
| 32 | - InstanceMonitor: 'InstanceMonitor', | 34 | + ResourceMonitorNetwork: 'ResourceMonitorNetwork', |
| 33 | - InstanceMonitorInstance: 'InstanceMonitorInstance', | 35 | + InstanceMonitor: 'InstanceMonitor', |
| 34 | - InstanceMonitorSession: 'InstanceMonitorSession', | 36 | + InstanceMonitorInstance: 'InstanceMonitorInstance', |
| 35 | - InstanceMonitorTOPSQL: 'InstanceMonitorTOPSQL', | 37 | + InstanceMonitorSession: 'InstanceMonitorSession', |
| 36 | - InstanceMonitorTOPSQLDBTime: 'InstanceMonitorTOPSQLDBTime', | 38 | + InstanceMonitorTOPSQL: 'InstanceMonitorTOPSQL', |
| 37 | - InstanceMonitorTOPSQLCPUTime: 'InstanceMonitorTOPSQLCPUTime', | 39 | + InstanceMonitorTOPSQLDBTime: 'InstanceMonitorTOPSQLDBTime', |
| 38 | - InstanceMonitorTOPSQLEXECTime: 'InstanceMonitorTOPSQLEXECTime', | 40 | + InstanceMonitorTOPSQLCPUTime: 'InstanceMonitorTOPSQLCPUTime', |
| 41 | + InstanceMonitorTOPSQLEXECTime: 'InstanceMonitorTOPSQLEXECTime', | ||
| 42 | + InstanceMonitorTOPSQLIOTime: 'InstanceMonitorTOPSQLIOTime', | ||
| 39 | } | 43 | } |
Mplugins/observability-instance/web-ui/src/pages/dashboardV2/instanceMonitor/sessionMonitor/Detail.vue+428-492
| @@ -1,407 +1,343 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | - <div class="tab-wrapper"> | 2 | + <div class="tab-wrapper"> |
| 3 | - <el-container> | 3 | + <el-container> |
| 4 | - <el-main style="position: relative; padding-top: 0px"> | 4 | + <el-main style="position: relative; padding-top: 0px"> |
| 5 | - <div class="page-header"> | 5 | + <div class="page-header"> |
| 6 | - <div class="icon"></div> | 6 | + <div class="icon"></div> |
| 7 | - <div class="title"> | 7 | + <div class="title"> |
| 8 | - {{ $t('session.detail.tabTitle') }}({{ $t('session.detail.sessionID') }}{{ sessionId }}) | 8 | + {{ $t('session.detail.tabTitle') }}({{ $t('session.detail.sessionID') }}{{ sessionId }}) |
| 9 | + </div> | ||
| 10 | + </div> | ||
| 11 | + <div style="position: relative"> | ||
| 12 | + <div | ||
| 13 | + style=" | ||
| 14 | + position: absolute; | ||
| 15 | + right: 0px; | ||
| 16 | + top: 2px; | ||
| 17 | + z-index: 1; | ||
| 18 | + display: flex; | ||
| 19 | + flex-direction: row; | ||
| 20 | + align-items: center; | ||
| 21 | + font-size: 12px; | ||
| 22 | + " | ||
| 23 | + > | ||
| 24 | + <div style="margin-right: 12px">{{ $t('app.refreshOn') }} {{ innerRefreshDoneTime }}</div> | ||
| 25 | + | ||
| 26 | + <div>{{ $t('app.autoRefreshFor') }}</div> | ||
| 27 | + <el-select v-model="innerRefreshTime" style="width: 100px; margin: 0 4px" @change="updateTimerInner"> | ||
| 28 | + <el-option :value="99999999" label="NO-AUTO" /> | ||
| 29 | + <el-option :value="1" label="1s" /> | ||
| 30 | + <el-option :value="15" label="15s" /> | ||
| 31 | + <el-option :value="30" label="30s" /> | ||
| 32 | + <el-option :value="60" label="60s" /> | ||
| 33 | + </el-select> | ||
| 34 | + <el-button | ||
| 35 | + class="refresh-button" | ||
| 36 | + type="primary" | ||
| 37 | + :icon="Refresh" | ||
| 38 | + style="margin-left: 8px" | ||
| 39 | + @click="loadSessionData(instanceId, sessionId)" | ||
| 40 | + /> | ||
| 41 | + </div> | ||
| 42 | + <el-tabs v-model="dashboardTabKey" class="tab2"> | ||
| 43 | + <el-tab-pane :label="$t('session.detail.info.tabTitle')" :name="tabKeys[0]"> | ||
| 44 | + <div class="line-tips center" v-if="tips"> | ||
| 45 | + <div class=""><svg-icon name="info" />{{ tips }}</div> | ||
| 46 | + </div> | ||
| 47 | + <el-row v-if="!tips" :gutter="12"> | ||
| 48 | + <el-col :span="12"> | ||
| 49 | + <my-card | ||
| 50 | + :title="$t('session.detail.info.server')" | ||
| 51 | + height="210" | ||
| 52 | + :bodyPadding="false" | ||
| 53 | + class="card-margin-bottom" | ||
| 54 | + > | ||
| 55 | + <div class="text-in-card"> | ||
| 56 | + <div class="text-row"> | ||
| 57 | + <div class="label">{{ $t('session.detail.info.sessionStatus') }}</div> | ||
| 58 | + <div class="value">{{ sessionData.general.state }}</div> | ||
| 59 | + </div> | ||
| 60 | + <div class="text-row"> | ||
| 61 | + <div class="label">{{ $t('session.detail.info.sessionID') }}</div> | ||
| 62 | + <div class="value">{{ sessionData.general.sessionid }}</div> | ||
| 63 | + </div> | ||
| 64 | + <div class="text-row"> | ||
| 65 | + <div class="label">{{ $t('session.detail.info.osThreadID') }}</div> | ||
| 66 | + <div class="value">{{ sessionData.general.lwtid }}</div> | ||
| 67 | + </div> | ||
| 68 | + <div class="text-row"> | ||
| 69 | + <div class="label">{{ $t('session.detail.info.dbUserName') }}</div> | ||
| 70 | + <div class="value">{{ sessionData.general.usename }}</div> | ||
| 71 | + </div> | ||
| 72 | + <div class="text-row"> | ||
| 73 | + <div class="label">{{ $t('session.detail.info.loginTime') }}</div> | ||
| 74 | + <div class="value">{{ sessionData.general.backend_start }}</div> | ||
| 75 | + </div> | ||
| 76 | + <div class="text-row"> | ||
| 77 | + <div class="label">{{ $t('session.detail.info.loginDuration') }}</div> | ||
| 78 | + <div class="value">{{ sessionData.general.backend_runtime }}</div> | ||
| 79 | + </div> | ||
| 80 | + | ||
| 81 | + <div class="text-row"> | ||
| 82 | + <div class="label">{{ $t('session.detail.info.resourcePool') }}</div> | ||
| 83 | + <div class="value">{{ sessionData.general.resource_pool }}</div> | ||
| 84 | + </div> | ||
| 9 | </div> | 85 | </div> |
| 10 | - </div> | 86 | + </my-card> |
| 11 | - <div style="position: relative"> | 87 | + </el-col> |
| 12 | - <div | 88 | + <el-col :span="12"> |
| 13 | - style=" | 89 | + <my-card :title="$t('session.detail.client.tabTitle')" height="210" :bodyPadding="false"> |
| 14 | - position: absolute; | 90 | + <div class="text-in-card"> |
| 15 | - right: 0px; | 91 | + <div class="text-row"> |
| 16 | - top: 2px; | 92 | + <div class="label">{{ $t('session.detail.client.clientIP') }}</div> |
| 17 | - z-index: 1; | 93 | + <div class="value">{{ sessionData.general.client_addr }}</div> |
| 18 | - display: flex; | 94 | + </div> |
| 19 | - flex-direction: row; | 95 | + <div class="text-row"> |
| 20 | - align-items: center; | 96 | + <div class="label"> |
| 21 | - font-size: 12px; | 97 | + {{ $t('session.detail.client.clientHostName') }} |
| 22 | - " | 98 | + </div> |
| 99 | + <div class="value">{{ sessionData.general.client_hostname }}</div> | ||
| 100 | + </div> | ||
| 101 | + <div class="text-row"> | ||
| 102 | + <div class="label">{{ $t('session.detail.client.clientTCPPort') }}</div> | ||
| 103 | + <div class="value">{{ sessionData.general.client_port }}</div> | ||
| 104 | + </div> | ||
| 105 | + <div class="text-row"> | ||
| 106 | + <div class="label">{{ $t('session.detail.client.appName') }}</div> | ||
| 107 | + <div class="value">{{ sessionData.general.application_name }}</div> | ||
| 108 | + </div> | ||
| 109 | + <div class="text-row"> | ||
| 110 | + <div class="label">{{ $t('session.detail.client.connectDBName') }}</div> | ||
| 111 | + <div class="value">{{ sessionData.general.datname }}</div> | ||
| 112 | + </div> | ||
| 113 | + <div class="text-row"> | ||
| 114 | + <div class="label">{{ $t('session.detail.client.txStartTime') }}</div> | ||
| 115 | + <div class="value">{{ sessionData.general.xact_start }}</div> | ||
| 116 | + </div> | ||
| 117 | + <div class="text-row"> | ||
| 118 | + <div class="label"> | ||
| 119 | + {{ $t('session.detail.client.queryStartTime') }} | ||
| 120 | + </div> | ||
| 121 | + <div class="value">{{ sessionData.general.query_start }}</div> | ||
| 122 | + </div> | ||
| 123 | + <div class="text-row"> | ||
| 124 | + <div class="label">{{ $t('session.detail.client.queryID') }}</div> | ||
| 125 | + <div class="value">{{ sessionData.general.query_id }}</div> | ||
| 126 | + </div> | ||
| 127 | + </div> | ||
| 128 | + </my-card> | ||
| 129 | + </el-col> | ||
| 130 | + </el-row> | ||
| 131 | + <el-row v-if="!tips" :gutter="12"> | ||
| 132 | + <el-col :span="12"> | ||
| 133 | + <my-card | ||
| 134 | + :title="$t('session.detail.block.tabTitle')" | ||
| 135 | + height="160" | ||
| 136 | + :bodyPadding="false" | ||
| 137 | + class="card-margin-bottom" | ||
| 138 | + > | ||
| 139 | + <div class="text-in-card"> | ||
| 140 | + <div class="text-row"> | ||
| 141 | + <div class="label" style="width: 90px"> | ||
| 142 | + {{ $t('session.detail.block.blockedSessionID') }} | ||
| 143 | + </div> | ||
| 144 | + <div class="value">{{ sessionData.general.block_sessionid }}</div> | ||
| 145 | + </div> | ||
| 146 | + <div class="text-row"> | ||
| 147 | + <div class="label" style="width: 90px"> | ||
| 148 | + {{ $t('session.detail.block.file') }} | ||
| 149 | + </div> | ||
| 150 | + <div class="value">{{ sessionData.general.filepath }}</div> | ||
| 151 | + </div> | ||
| 152 | + <div class="text-row"> | ||
| 153 | + <div class="label" style="width: 90px"> | ||
| 154 | + {{ $t('session.detail.block.pageNumber') }} | ||
| 155 | + </div> | ||
| 156 | + <div class="value">{{ sessionData.general.page }}</div> | ||
| 157 | + </div> | ||
| 158 | + <div class="text-row"> | ||
| 159 | + <div class="label" style="width: 90px"> | ||
| 160 | + {{ $t('session.detail.block.lineNumber') }} | ||
| 161 | + </div> | ||
| 162 | + <div class="value">{{ sessionData.general.tuple }}</div> | ||
| 163 | + </div> | ||
| 164 | + <div class="text-row"> | ||
| 165 | + <div class="label" style="width: 90px"> | ||
| 166 | + {{ $t('session.detail.block.bucketNumber') }} | ||
| 167 | + </div> | ||
| 168 | + <div class="value">{{ sessionData.general.bucket }}</div> | ||
| 169 | + </div> | ||
| 170 | + </div> | ||
| 171 | + </my-card> | ||
| 172 | + </el-col> | ||
| 173 | + <el-col :span="12"> | ||
| 174 | + <my-card :title="$t('session.detail.wait.tabTitle')" height="160" :bodyPadding="false"> | ||
| 175 | + <div class="text-in-card"> | ||
| 176 | + <div class="text-row"> | ||
| 177 | + <div class="label" style="width: 130px"> | ||
| 178 | + {{ $t('session.detail.wait.waitState') }} | ||
| 179 | + </div> | ||
| 180 | + <div class="value">{{ sessionData.general.wait_status }}</div> | ||
| 181 | + </div> | ||
| 182 | + <div class="text-row"> | ||
| 183 | + <div class="label" style="width: 130px"> | ||
| 184 | + {{ $t('session.detail.wait.waitEventType') }} | ||
| 185 | + </div> | ||
| 186 | + <div class="value">{{ sessionData.general.wait_event }}</div> | ||
| 187 | + </div> | ||
| 188 | + <div class="text-row"> | ||
| 189 | + <div class="label" style="width: 130px"> | ||
| 190 | + {{ $t('session.detail.wait.waitLockMode') }} | ||
| 191 | + </div> | ||
| 192 | + <div class="value">{{ sessionData.general.lockmode }}</div> | ||
| 193 | + </div> | ||
| 194 | + <div class="text-row"> | ||
| 195 | + <div class="label" style="width: 130px"> | ||
| 196 | + {{ $t('session.detail.wait.waitObject') }} | ||
| 197 | + </div> | ||
| 198 | + <div class="value">{{ sessionData.general.namespace_relation }}</div> | ||
| 199 | + </div> | ||
| 200 | + </div> | ||
| 201 | + </my-card> | ||
| 202 | + </el-col> | ||
| 203 | + </el-row> | ||
| 204 | + <el-row v-if="!tips" :gutter="12"> | ||
| 205 | + <el-col :span="24"> | ||
| 206 | + <my-card :title="$t('session.detail.currentQuerySQL')" height="200" :bodyPadding="false"> | ||
| 207 | + <div class="text-in-card"> | ||
| 208 | + <div class="text-row"> | ||
| 209 | + <div class="value">{{ sessionData.general.query }}</div> | ||
| 210 | + </div> | ||
| 211 | + </div> | ||
| 212 | + </my-card> | ||
| 213 | + </el-col> | ||
| 214 | + </el-row> | ||
| 215 | + </el-tab-pane> | ||
| 216 | + <el-tab-pane :label="$t('session.detail.statistic.tabTitle')" :name="tabKeys[1]"> | ||
| 217 | + <div class="line-tips center" v-if="tips"> | ||
| 218 | + <div class=""><svg-icon name="info" />{{ tips }}</div> | ||
| 219 | + </div> | ||
| 220 | + <el-row v-if="!tips" :gutter="12"> | ||
| 221 | + <el-col :span="12"> | ||
| 222 | + <my-card | ||
| 223 | + :title="$t('session.detail.statistic.sessionStatusStatistics')" | ||
| 224 | + height="600" | ||
| 225 | + :bodyPadding="false" | ||
| 226 | + skipBodyHeight | ||
| 227 | + > | ||
| 228 | + <el-table | ||
| 229 | + :data="sessionData.statisticStatus" | ||
| 230 | + style="width: 100%; height: 560px" | ||
| 231 | + border | ||
| 232 | + :header-cell-class-name=" | ||
| 233 | + () => { | ||
| 234 | + return 'grid-header' | ||
| 235 | + } | ||
| 236 | + " | ||
| 23 | > | 237 | > |
| 24 | - <div style="margin-right: 12px">{{ $t('app.refreshOn') }} {{ innerRefreshDoneTime }}</div> | 238 | + <el-table-column prop="name" :label="$t('session.detail.statistic.name')" /> |
| 25 | - | 239 | + <el-table-column prop="value" :label="$t('session.detail.statistic.value')" /> |
| 26 | - <div>{{ $t('app.autoRefreshFor') }}</div> | 240 | + </el-table> |
| 27 | - <el-select | 241 | + </my-card> |
| 28 | - v-model="innerRefreshTime" | 242 | + </el-col> |
| 29 | - style="width: 60px; margin: 0 4px" | 243 | + <el-col :span="12"> |
| 30 | - @change="updateTimerInner" | 244 | + <my-card |
| 31 | - > | 245 | + :title="$t('session.detail.statistic.sessionRuntimeInformation')" |
| 32 | - <el-option :value="1" label="1s" /> | 246 | + height="600" |
| 33 | - <el-option :value="15" label="15s" /> | 247 | + :bodyPadding="false" |
| 34 | - <el-option :value="30" label="30s" /> | 248 | + skipBodyHeight |
| 35 | - <el-option :value="60" label="60s" /> | 249 | + > |
| 36 | - </el-select> | 250 | + <el-table |
| 37 | - <el-button | 251 | + :data="sessionData.statisticRuntime" |
| 38 | - class="refresh-button" | 252 | + style="width: 100%; height: 560px" |
| 39 | - type="primary" | 253 | + border |
| 40 | - :icon="Refresh" | 254 | + :header-cell-class-name=" |
| 41 | - style="margin-left: 8px" | 255 | + () => { |
| 42 | - @click="loadSessionData(instanceId, sessionId)" | 256 | + return 'grid-header' |
| 43 | - /> | 257 | + } |
| 44 | - </div> | 258 | + " |
| 45 | - <el-tabs v-model="dashboardTabKey" class="tab2"> | 259 | + > |
| 46 | - <el-tab-pane :label="$t('session.detail.info.tabTitle')" :name="tabKeys[0]"> | 260 | + <el-table-column prop="name" :label="$t('session.detail.statistic.name')" /> |
| 47 | - <div class="line-tips center" v-if="tips"> | 261 | + <el-table-column prop="value" :label="$t('session.detail.statistic.value')" /> |
| 48 | - <div class=""><svg-icon name="info" />{{ tips }}</div> | 262 | + </el-table> |
| 49 | - </div> | 263 | + </my-card> |
| 50 | - <el-row v-if="!tips" :gutter="12"> | 264 | + </el-col> |
| 51 | - <el-col :span="12"> | 265 | + </el-row> |
| 52 | - <my-card | 266 | + </el-tab-pane> |
| 53 | - :title="$t('session.detail.info.server')" | 267 | + <el-tab-pane :label="$t('session.detail.blockTree.tabTitle')" :name="tabKeys[2]"> |
| 54 | - height="210" | 268 | + <div class="line-tips center" v-if="tips"> |
| 55 | - :bodyPadding="false" | 269 | + <div class=""><svg-icon name="info" />{{ tips }}</div> |
| 56 | - class="card-margin-bottom" | 270 | + </div> |
| 57 | - > | 271 | + <el-table |
| 58 | - <div class="text-in-card"> | 272 | + v-if="!tips" |
| 59 | - <div class="text-row"> | 273 | + :table-layout="'auto'" |
| 60 | - <div class="label">{{ $t('session.detail.info.sessionStatus') }}</div> | 274 | + :data="sessionData.blockTree" |
| 61 | - <div class="value">{{ sessionData.general.state }}</div> | 275 | + style="width: 100%" |
| 62 | - </div> | 276 | + border |
| 63 | - <div class="text-row"> | 277 | + :header-cell-class-name=" |
| 64 | - <div class="label">{{ $t('session.detail.info.sessionID') }}</div> | 278 | + () => { |
| 65 | - <div class="value">{{ sessionData.general.sessionid }}</div> | 279 | + return 'grid-header' |
| 66 | - </div> | 280 | + } |
| 67 | - <div class="text-row"> | 281 | + " |
| 68 | - <div class="label">{{ $t('session.detail.info.osThreadID') }}</div> | 282 | + row-key="id" |
| 69 | - <div class="value">{{ sessionData.general.lwtid }}</div> | 283 | + default-expand-all |
| 70 | - </div> | 284 | + > |
| 71 | - <div class="text-row"> | 285 | + <el-table-column :label="$t('session.detail.blockTree.sessionID')" width="120"> |
| 72 | - <div class="label">{{ $t('session.detail.info.dbUserName') }}</div> | 286 | + <template #default="scope"> |
| 73 | - <div class="value">{{ sessionData.general.usename }}</div> | 287 | + <el-link type="primary" @click="gotoSessionDetail(scope.row.id)"> |
| 74 | - </div> | 288 | + {{ scope.row.id === '0' ? '' : scope.row.id }} |
| 75 | - <div class="text-row"> | 289 | + </el-link> |
| 76 | - <div class="label">{{ $t('session.detail.info.loginTime') }}</div> | 290 | + </template> |
| 77 | - <div class="value">{{ sessionData.general.backend_start }}</div> | 291 | + </el-table-column> |
| 78 | - </div> | 292 | + <el-table-column :label="$t('session.detail.blockTree.blockedSessionID')" width="100"> |
| 79 | - <div class="text-row"> | 293 | + <template #default="scope"> |
| 80 | - <div class="label">{{ $t('session.detail.info.loginDuration') }}</div> | 294 | + <el-link type="primary" @click="gotoSessionDetail(scope.row.parentid)"> |
| 81 | - <div class="value">{{ sessionData.general.backend_runtime }}</div> | 295 | + {{ scope.row.parentid === '0' ? '' : scope.row.parentid }} |
| 82 | - </div> | 296 | + </el-link> |
| 83 | - | 297 | + </template> |
| 84 | - <div class="text-row"> | 298 | + </el-table-column> |
| 85 | - <div class="label">{{ $t('session.detail.info.resourcePool') }}</div> | 299 | + <el-table-column |
| 86 | - <div class="value">{{ sessionData.general.resource_pool }}</div> | 300 | + prop="backend_start" |
| 87 | - </div> | 301 | + :label="$t('session.detail.blockTree.sessionStartTime')" |
| 88 | - </div> | 302 | + :formatter="(r) => dateFormat(r.backend_start, 'MM-DD HH:mm:ss')" |
| 89 | - </my-card> | 303 | + width="110" |
| 90 | - </el-col> | 304 | + /> |
| 91 | - <el-col :span="12"> | 305 | + <el-table-column prop="wait_status" :label="$t('session.detail.blockTree.waitState')" width="100" /> |
| 92 | - <my-card | 306 | + <el-table-column prop="wait_event" :label="$t('session.detail.blockTree.waitEvent')" width="100" /> |
| 93 | - :title="$t('session.detail.client.tabTitle')" | 307 | + <el-table-column prop="lockmode" :label="$t('session.detail.blockTree.waitLockMode')" width="120" /> |
| 94 | - height="210" | 308 | + <el-table-column prop="datname" :label="$t('session.detail.blockTree.dbName')" width="110" /> |
| 95 | - :bodyPadding="false" | 309 | + <el-table-column prop="usename" :label="$t('session.detail.blockTree.userName')" width="90" /> |
| 96 | - > | 310 | + <el-table-column prop="client_addr" :label="$t('session.detail.blockTree.clientIP')" width="120" /> |
| 97 | - <div class="text-in-card"> | 311 | + <el-table-column prop="application_name" :label="$t('session.detail.blockTree.appName')" /> |
| 98 | - <div class="text-row"> | 312 | + </el-table> |
| 99 | - <div class="label">{{ $t('session.detail.client.clientIP') }}</div> | 313 | + </el-tab-pane> |
| 100 | - <div class="value">{{ sessionData.general.client_addr }}</div> | 314 | + <el-tab-pane :label="$t('session.detail.waitRecord.tabTitle')" :name="tabKeys[3]"> |
| 101 | - </div> | 315 | + <div class="line-tips center" v-if="tips"> |
| 102 | - <div class="text-row"> | 316 | + <div class=""><svg-icon name="info" />{{ tips }}</div> |
| 103 | - <div class="label"> | 317 | + </div> |
| 104 | - {{ $t('session.detail.client.clientHostName') }} | 318 | + <el-table |
| 105 | - </div> | 319 | + v-if="!tips" |
| 106 | - <div class="value">{{ sessionData.general.client_hostname }}</div> | 320 | + :data="sessionData.waiting" |
| 107 | - </div> | 321 | + style="width: 100%; height: 560px" |
| 108 | - <div class="text-row"> | 322 | + border |
| 109 | - <div class="label">{{ $t('session.detail.client.clientTCPPort') }}</div> | 323 | + :header-cell-class-name=" |
| 110 | - <div class="value">{{ sessionData.general.client_port }}</div> | 324 | + () => { |
| 111 | - </div> | 325 | + return 'grid-header' |
| 112 | - <div class="text-row"> | 326 | + } |
| 113 | - <div class="label">{{ $t('session.detail.client.appName') }}</div> | 327 | + " |
| 114 | - <div class="value">{{ sessionData.general.application_name }}</div> | 328 | + > |
| 115 | - </div> | 329 | + <el-table-column prop="sample_time" :label="$t('session.detail.waitRecord.sampleTime')" width="140" /> |
| 116 | - <div class="text-row"> | 330 | + <el-table-column prop="wait_status" :label="$t('session.detail.waitRecord.waitState')" width="120" /> |
| 117 | - <div class="label">{{ $t('session.detail.client.connectDBName') }}</div> | 331 | + <el-table-column prop="event" :label="$t('session.detail.waitRecord.waitEvent')" width="120" /> |
| 118 | - <div class="value">{{ sessionData.general.datname }}</div> | 332 | + <el-table-column prop="lockmode" :label="$t('session.detail.waitRecord.waitLockMode')" width="160" /> |
| 119 | - </div> | 333 | + <el-table-column prop="locktag" :label="$t('session.detail.waitRecord.lockInfo')" /> |
| 120 | - <div class="text-row"> | 334 | + </el-table> |
| 121 | - <div class="label">{{ $t('session.detail.client.txStartTime') }}</div> | 335 | + </el-tab-pane> |
| 122 | - <div class="value">{{ sessionData.general.xact_start }}</div> | 336 | + </el-tabs> |
| 123 | - </div> | 337 | + </div> |
| 124 | - <div class="text-row"> | 338 | + </el-main> |
| 125 | - <div class="label"> | 339 | + </el-container> |
| 126 | - {{ $t('session.detail.client.queryStartTime') }} | 340 | + </div> |
| 127 | - </div> | ||
| 128 | - <div class="value">{{ sessionData.general.query_start }}</div> | ||
| 129 | - </div> | ||
| 130 | - <div class="text-row"> | ||
| 131 | - <div class="label">{{ $t('session.detail.client.queryID') }}</div> | ||
| 132 | - <div class="value">{{ sessionData.general.query_id }}</div> | ||
| 133 | - </div> | ||
| 134 | - </div> | ||
| 135 | - </my-card> | ||
| 136 | - </el-col> | ||
| 137 | - </el-row> | ||
| 138 | - <el-row v-if="!tips" :gutter="12"> | ||
| 139 | - <el-col :span="12"> | ||
| 140 | - <my-card | ||
| 141 | - :title="$t('session.detail.block.tabTitle')" | ||
| 142 | - height="160" | ||
| 143 | - :bodyPadding="false" | ||
| 144 | - class="card-margin-bottom" | ||
| 145 | - > | ||
| 146 | - <div class="text-in-card"> | ||
| 147 | - <div class="text-row"> | ||
| 148 | - <div class="label" style="width: 90px"> | ||
| 149 | - {{ $t('session.detail.block.blockedSessionID') }} | ||
| 150 | - </div> | ||
| 151 | - <div class="value">{{ sessionData.general.block_sessionid }}</div> | ||
| 152 | - </div> | ||
| 153 | - <div class="text-row"> | ||
| 154 | - <div class="label" style="width: 90px"> | ||
| 155 | - {{ $t('session.detail.block.file') }} | ||
| 156 | - </div> | ||
| 157 | - <div class="value">{{ sessionData.general.filepath }}</div> | ||
| 158 | - </div> | ||
| 159 | - <div class="text-row"> | ||
| 160 | - <div class="label" style="width: 90px"> | ||
| 161 | - {{ $t('session.detail.block.pageNumber') }} | ||
| 162 | - </div> | ||
| 163 | - <div class="value">{{ sessionData.general.page }}</div> | ||
| 164 | - </div> | ||
| 165 | - <div class="text-row"> | ||
| 166 | - <div class="label" style="width: 90px"> | ||
| 167 | - {{ $t('session.detail.block.lineNumber') }} | ||
| 168 | - </div> | ||
| 169 | - <div class="value">{{ sessionData.general.tuple }}</div> | ||
| 170 | - </div> | ||
| 171 | - <div class="text-row"> | ||
| 172 | - <div class="label" style="width: 90px"> | ||
| 173 | - {{ $t('session.detail.block.bucketNumber') }} | ||
| 174 | - </div> | ||
| 175 | - <div class="value">{{ sessionData.general.bucket }}</div> | ||
| 176 | - </div> | ||
| 177 | - </div> | ||
| 178 | - </my-card> | ||
| 179 | - </el-col> | ||
| 180 | - <el-col :span="12"> | ||
| 181 | - <my-card | ||
| 182 | - :title="$t('session.detail.wait.tabTitle')" | ||
| 183 | - height="160" | ||
| 184 | - :bodyPadding="false" | ||
| 185 | - > | ||
| 186 | - <div class="text-in-card"> | ||
| 187 | - <div class="text-row"> | ||
| 188 | - <div class="label" style="width: 130px"> | ||
| 189 | - {{ $t('session.detail.wait.waitState') }} | ||
| 190 | - </div> | ||
| 191 | - <div class="value">{{ sessionData.general.wait_status }}</div> | ||
| 192 | - </div> | ||
| 193 | - <div class="text-row"> | ||
| 194 | - <div class="label" style="width: 130px"> | ||
| 195 | - {{ $t('session.detail.wait.waitEventType') }} | ||
| 196 | - </div> | ||
| 197 | - <div class="value">{{ sessionData.general.wait_event }}</div> | ||
| 198 | - </div> | ||
| 199 | - <div class="text-row"> | ||
| 200 | - <div class="label" style="width: 130px"> | ||
| 201 | - {{ $t('session.detail.wait.waitLockMode') }} | ||
| 202 | - </div> | ||
| 203 | - <div class="value">{{ sessionData.general.lockmode }}</div> | ||
| 204 | - </div> | ||
| 205 | - <div class="text-row"> | ||
| 206 | - <div class="label" style="width: 130px"> | ||
| 207 | - {{ $t('session.detail.wait.waitObject') }} | ||
| 208 | - </div> | ||
| 209 | - <div class="value">{{ sessionData.general.namespace_relation }}</div> | ||
| 210 | - </div> | ||
| 211 | - </div> | ||
| 212 | - </my-card> | ||
| 213 | - </el-col> | ||
| 214 | - </el-row> | ||
| 215 | - <el-row v-if="!tips" :gutter="12"> | ||
| 216 | - <el-col :span="24"> | ||
| 217 | - <my-card | ||
| 218 | - :title="$t('session.detail.currentQuerySQL')" | ||
| 219 | - height="200" | ||
| 220 | - :bodyPadding="false" | ||
| 221 | - > | ||
| 222 | - <div class="text-in-card"> | ||
| 223 | - <div class="text-row"> | ||
| 224 | - <div class="value">{{ sessionData.general.query }}</div> | ||
| 225 | - </div> | ||
| 226 | - </div> | ||
| 227 | - </my-card> | ||
| 228 | - </el-col> | ||
| 229 | - </el-row> | ||
| 230 | - </el-tab-pane> | ||
| 231 | - <el-tab-pane :label="$t('session.detail.statistic.tabTitle')" :name="tabKeys[1]"> | ||
| 232 | - <div class="line-tips center" v-if="tips"> | ||
| 233 | - <div class=""><svg-icon name="info" />{{ tips }}</div> | ||
| 234 | - </div> | ||
| 235 | - <el-row v-if="!tips" :gutter="12"> | ||
| 236 | - <el-col :span="12"> | ||
| 237 | - <my-card | ||
| 238 | - :title="$t('session.detail.statistic.sessionStatusStatistics')" | ||
| 239 | - height="600" | ||
| 240 | - :bodyPadding="false" | ||
| 241 | - skipBodyHeight | ||
| 242 | - > | ||
| 243 | - <el-table | ||
| 244 | - :data="sessionData.statisticStatus" | ||
| 245 | - style="width: 100%; height: 560px" | ||
| 246 | - border | ||
| 247 | - :header-cell-class-name=" | ||
| 248 | - () => { | ||
| 249 | - return 'grid-header' | ||
| 250 | - } | ||
| 251 | - " | ||
| 252 | - > | ||
| 253 | - <el-table-column prop="name" :label="$t('session.detail.statistic.name')" /> | ||
| 254 | - <el-table-column | ||
| 255 | - prop="value" | ||
| 256 | - :label="$t('session.detail.statistic.value')" | ||
| 257 | - /> | ||
| 258 | - </el-table> | ||
| 259 | - </my-card> | ||
| 260 | - </el-col> | ||
| 261 | - <el-col :span="12"> | ||
| 262 | - <my-card | ||
| 263 | - :title="$t('session.detail.statistic.sessionRuntimeInformation')" | ||
| 264 | - height="600" | ||
| 265 | - :bodyPadding="false" | ||
| 266 | - skipBodyHeight | ||
| 267 | - > | ||
| 268 | - <el-table | ||
| 269 | - :data="sessionData.statisticRuntime" | ||
| 270 | - style="width: 100%; height: 560px" | ||
| 271 | - border | ||
| 272 | - :header-cell-class-name=" | ||
| 273 | - () => { | ||
| 274 | - return 'grid-header' | ||
| 275 | - } | ||
| 276 | - " | ||
| 277 | - > | ||
| 278 | - <el-table-column prop="name" :label="$t('session.detail.statistic.name')" /> | ||
| 279 | - <el-table-column | ||
| 280 | - prop="value" | ||
| 281 | - :label="$t('session.detail.statistic.value')" | ||
| 282 | - /> | ||
| 283 | - </el-table> | ||
| 284 | - </my-card> | ||
| 285 | - </el-col> | ||
| 286 | - </el-row> | ||
| 287 | - </el-tab-pane> | ||
| 288 | - <el-tab-pane :label="$t('session.detail.blockTree.tabTitle')" :name="tabKeys[2]"> | ||
| 289 | - <div class="line-tips center" v-if="tips"> | ||
| 290 | - <div class=""><svg-icon name="info" />{{ tips }}</div> | ||
| 291 | - </div> | ||
| 292 | - <el-table | ||
| 293 | - v-if="!tips" | ||
| 294 | - :table-layout="'auto'" | ||
| 295 | - :data="sessionData.blockTree" | ||
| 296 | - style="width: 100%" | ||
| 297 | - border | ||
| 298 | - :header-cell-class-name=" | ||
| 299 | - () => { | ||
| 300 | - return 'grid-header' | ||
| 301 | - } | ||
| 302 | - " | ||
| 303 | - row-key="id" | ||
| 304 | - default-expand-all | ||
| 305 | - > | ||
| 306 | - <el-table-column :label="$t('session.detail.blockTree.sessionID')" width="120"> | ||
| 307 | - <template #default="scope"> | ||
| 308 | - <el-link type="primary" @click="gotoSessionDetail(scope.row.id)"> | ||
| 309 | - {{ scope.row.id === '0' ? '' : scope.row.id }} | ||
| 310 | - </el-link> | ||
| 311 | - </template> | ||
| 312 | - </el-table-column> | ||
| 313 | - <el-table-column :label="$t('session.detail.blockTree.blockedSessionID')" width="100"> | ||
| 314 | - <template #default="scope"> | ||
| 315 | - <el-link type="primary" @click="gotoSessionDetail(scope.row.parentid)"> | ||
| 316 | - {{ scope.row.parentid === '0' ? '' : scope.row.parentid }} | ||
| 317 | - </el-link> | ||
| 318 | - </template> | ||
| 319 | - </el-table-column> | ||
| 320 | - <el-table-column | ||
| 321 | - prop="backend_start" | ||
| 322 | - :label="$t('session.detail.blockTree.sessionStartTime')" | ||
| 323 | - :formatter="(r) => dateFormat(r.backend_start, 'MM-DD HH:mm:ss')" | ||
| 324 | - width="110" | ||
| 325 | - /> | ||
| 326 | - <el-table-column | ||
| 327 | - prop="wait_status" | ||
| 328 | - :label="$t('session.detail.blockTree.waitState')" | ||
| 329 | - width="100" | ||
| 330 | - /> | ||
| 331 | - <el-table-column | ||
| 332 | - prop="wait_event" | ||
| 333 | - :label="$t('session.detail.blockTree.waitEvent')" | ||
| 334 | - width="100" | ||
| 335 | - /> | ||
| 336 | - <el-table-column | ||
| 337 | - prop="lockmode" | ||
| 338 | - :label="$t('session.detail.blockTree.waitLockMode')" | ||
| 339 | - width="120" | ||
| 340 | - /> | ||
| 341 | - <el-table-column | ||
| 342 | - prop="datname" | ||
| 343 | - :label="$t('session.detail.blockTree.dbName')" | ||
| 344 | - width="110" | ||
| 345 | - /> | ||
| 346 | - <el-table-column | ||
| 347 | - prop="usename" | ||
| 348 | - :label="$t('session.detail.blockTree.userName')" | ||
| 349 | - width="90" | ||
| 350 | - /> | ||
| 351 | - <el-table-column | ||
| 352 | - prop="client_addr" | ||
| 353 | - :label="$t('session.detail.blockTree.clientIP')" | ||
| 354 | - width="120" | ||
| 355 | - /> | ||
| 356 | - <el-table-column | ||
| 357 | - prop="application_name" | ||
| 358 | - :label="$t('session.detail.blockTree.appName')" | ||
| 359 | - /> | ||
| 360 | - </el-table> | ||
| 361 | - </el-tab-pane> | ||
| 362 | - <el-tab-pane :label="$t('session.detail.waitRecord.tabTitle')" :name="tabKeys[3]"> | ||
| 363 | - <div class="line-tips center" v-if="tips"> | ||
| 364 | - <div class=""><svg-icon name="info" />{{ tips }}</div> | ||
| 365 | - </div> | ||
| 366 | - <el-table | ||
| 367 | - v-if="!tips" | ||
| 368 | - :data="sessionData.waiting" | ||
| 369 | - style="width: 100%; height: 560px" | ||
| 370 | - border | ||
| 371 | - :header-cell-class-name=" | ||
| 372 | - () => { | ||
| 373 | - return 'grid-header' | ||
| 374 | - } | ||
| 375 | - " | ||
| 376 | - > | ||
| 377 | - <el-table-column | ||
| 378 | - prop="sample_time" | ||
| 379 | - :label="$t('session.detail.waitRecord.sampleTime')" | ||
| 380 | - width="140" | ||
| 381 | - /> | ||
| 382 | - <el-table-column | ||
| 383 | - prop="wait_status" | ||
| 384 | - :label="$t('session.detail.waitRecord.waitState')" | ||
| 385 | - width="120" | ||
| 386 | - /> | ||
| 387 | - <el-table-column | ||
| 388 | - prop="event" | ||
| 389 | - :label="$t('session.detail.waitRecord.waitEvent')" | ||
| 390 | - width="120" | ||
| 391 | - /> | ||
| 392 | - <el-table-column | ||
| 393 | - prop="lockmode" | ||
| 394 | - :label="$t('session.detail.waitRecord.waitLockMode')" | ||
| 395 | - width="160" | ||
| 396 | - /> | ||
| 397 | - <el-table-column prop="locktag" :label="$t('session.detail.waitRecord.lockInfo')" /> | ||
| 398 | - </el-table> | ||
| 399 | - </el-tab-pane> | ||
| 400 | - </el-tabs> | ||
| 401 | - </div> | ||
| 402 | - </el-main> | ||
| 403 | - </el-container> | ||
| 404 | - </div> | ||
| 405 | </template> | 341 | </template> |
| 406 | 342 | ||
| 407 | <script setup lang="ts"> | 343 | <script setup lang="ts"> |
| @@ -424,116 +360,116 @@ const innerRefreshTime = ref<number>(30) | |||
| 424 | const innerRefreshDoneTime = ref<string>('') | 360 | const innerRefreshDoneTime = ref<string>('') |
| 425 | 361 | ||
| 426 | interface SessionData { | 362 | interface SessionData { |
| 427 | - general: SessionGeneralDetail | any | 363 | + general: SessionGeneralDetail | any |
| 428 | - blockTree: BlockTable[] | 364 | + blockTree: BlockTable[] |
| 429 | - statisticStatus: Statistic[] | 365 | + statisticStatus: Statistic[] |
| 430 | - statisticRuntime: Statistic[] | 366 | + statisticRuntime: Statistic[] |
| 431 | - waiting: WaitingRecord[] | 367 | + waiting: WaitingRecord[] |
| 432 | } | 368 | } |
| 433 | const sessionDataDefault = { | 369 | const sessionDataDefault = { |
| 434 | - general: {}, | 370 | + general: {}, |
| 435 | - blockTree: [], | 371 | + blockTree: [], |
| 436 | - statisticStatus: [], | 372 | + statisticStatus: [], |
| 437 | - statisticRuntime: [], | 373 | + statisticRuntime: [], |
| 438 | - waiting: [], | 374 | + waiting: [], |
| 439 | } | 375 | } |
| 440 | const sessionData = ref<SessionData>(sessionDataDefault) | 376 | const sessionData = ref<SessionData>(sessionDataDefault) |
| 441 | 377 | ||
| 442 | // same for every page in index | 378 | // same for every page in index |
| 443 | onMounted(() => { | 379 | onMounted(() => { |
| 444 | - if ( | 380 | + if ( |
| 445 | - typeof router.currentRoute.value.params.dbid === 'string' && | 381 | + typeof router.currentRoute.value.params.dbid === 'string' && |
| 446 | - typeof router.currentRoute.value.params.id === 'string' | 382 | + typeof router.currentRoute.value.params.id === 'string' |
| 447 | - ) { | 383 | + ) { |
| 448 | - instanceId.value = router.currentRoute.value.params.dbid | 384 | + instanceId.value = router.currentRoute.value.params.dbid |
| 449 | - sessionId.value = router.currentRoute.value.params.id | 385 | + sessionId.value = router.currentRoute.value.params.id |
| 450 | - } else { | 386 | + } else { |
| 451 | - // @ts-ignore | 387 | + // @ts-ignore |
| 452 | - const wujie = window.$wujie | 388 | + const wujie = window.$wujie |
| 453 | - instanceId.value = wujie?.props.data.dbid | 389 | + instanceId.value = wujie?.props.data.dbid |
| 454 | - sessionId.value = wujie?.props.data.id | 390 | + sessionId.value = wujie?.props.data.id |
| 455 | - } | 391 | + } |
| 456 | - loadSessionData(instanceId.value, sessionId.value) | 392 | + loadSessionData(instanceId.value, sessionId.value) |
| 457 | - updateTimerInner() | 393 | + updateTimerInner() |
| 458 | }) | 394 | }) |
| 459 | 395 | ||
| 460 | // load data | 396 | // load data |
| 461 | const { data: sessionResultWrapper, run: loadSessionData } = useRequest(getSessionDetail, { manual: true }) | 397 | const { data: sessionResultWrapper, run: loadSessionData } = useRequest(getSessionDetail, { manual: true }) |
| 462 | watch( | 398 | watch( |
| 463 | - sessionResultWrapper, | 399 | + sessionResultWrapper, |
| 464 | - () => { | 400 | + () => { |
| 465 | - tips.value = '' | 401 | + tips.value = '' |
| 466 | - if (sessionResultWrapper?.value?.code !== 200 && sessionResultWrapper?.value?.code !== '200') { | 402 | + if (sessionResultWrapper?.value?.code !== 200 && sessionResultWrapper?.value?.code !== '200') { |
| 467 | - tips.value = sessionResultWrapper?.value?.msg | 403 | + tips.value = sessionResultWrapper?.value?.msg |
| 404 | + } | ||
| 405 | + | ||
| 406 | + console.log('DEBUG: sessionResultWrapper', sessionResultWrapper) | ||
| 407 | + | ||
| 408 | + let sessionResult = sessionResultWrapper?.value?.data | ||
| 409 | + console.log('DEBUG: sessionResult', sessionResult) | ||
| 410 | + | ||
| 411 | + innerRefreshDoneTime.value = moment(new Date()).format('HH:mm:ss') | ||
| 412 | + | ||
| 413 | + // clear data | ||
| 414 | + sessionData.value = sessionDataDefault | ||
| 415 | + | ||
| 416 | + if (sessionResult) { | ||
| 417 | + sessionData.value.general = sessionResult.general | ||
| 418 | + sessionData.value.statisticRuntime = sessionResult.statistic.filter((item) => { | ||
| 419 | + if (item.type === 'RUNTIME') { | ||
| 420 | + return true | ||
| 468 | } | 421 | } |
| 469 | - | 422 | + return false |
| 470 | - console.log('DEBUG: sessionResultWrapper', sessionResultWrapper) | 423 | + }) |
| 471 | - | 424 | + sessionData.value.statisticStatus = sessionResult.statistic.filter((item) => { |
| 472 | - let sessionResult = sessionResultWrapper?.value?.data | 425 | + if (item.type === 'STATUS') { |
| 473 | - console.log('DEBUG: sessionResult', sessionResult) | 426 | + return true |
| 474 | - | ||
| 475 | - innerRefreshDoneTime.value = moment(new Date()).format('HH:mm:ss') | ||
| 476 | - | ||
| 477 | - // clear data | ||
| 478 | - sessionData.value = sessionDataDefault | ||
| 479 | - | ||
| 480 | - if (sessionResult) { | ||
| 481 | - sessionData.value.general = sessionResult.general | ||
| 482 | - sessionData.value.statisticRuntime = sessionResult.statistic.filter((item) => { | ||
| 483 | - if (item.type === 'RUNTIME') { | ||
| 484 | - return true | ||
| 485 | - } | ||
| 486 | - return false | ||
| 487 | - }) | ||
| 488 | - sessionData.value.statisticStatus = sessionResult.statistic.filter((item) => { | ||
| 489 | - if (item.type === 'STATUS') { | ||
| 490 | - return true | ||
| 491 | - } | ||
| 492 | - return false | ||
| 493 | - }) | ||
| 494 | - | ||
| 495 | - // block sessions | ||
| 496 | - if (sessionResult.blockTree) { | ||
| 497 | - sessionData.value.blockTree = sessionResult.blockTree | ||
| 498 | - } | ||
| 499 | - | ||
| 500 | - // waiting | ||
| 501 | - for (let index = 0; index < sessionResult.waiting.length; index++) { | ||
| 502 | - const element = sessionResult.waiting[index] | ||
| 503 | - element.sample_time = utcTimeFormat(element.sample_time, 'YYYY-MM-DD HH:mm:ss') | ||
| 504 | - } | ||
| 505 | - sessionData.value.waiting = sessionResult.waiting | ||
| 506 | } | 427 | } |
| 507 | - }, | 428 | + return false |
| 508 | - { deep: true } | 429 | + }) |
| 430 | + | ||
| 431 | + // block sessions | ||
| 432 | + if (sessionResult.blockTree) { | ||
| 433 | + sessionData.value.blockTree = sessionResult.blockTree | ||
| 434 | + } | ||
| 435 | + | ||
| 436 | + // waiting | ||
| 437 | + for (let index = 0; index < sessionResult.waiting.length; index++) { | ||
| 438 | + const element = sessionResult.waiting[index] | ||
| 439 | + element.sample_time = utcTimeFormat(element.sample_time, 'YYYY-MM-DD HH:mm:ss') | ||
| 440 | + } | ||
| 441 | + sessionData.value.waiting = sessionResult.waiting | ||
| 442 | + } | ||
| 443 | + }, | ||
| 444 | + { deep: true } | ||
| 509 | ) | 445 | ) |
| 510 | const tips = ref<string | undefined>() | 446 | const tips = ref<string | undefined>() |
| 511 | const timerInner = ref<number>() | 447 | const timerInner = ref<number>() |
| 512 | const updateTimerInner = () => { | 448 | const updateTimerInner = () => { |
| 513 | - clearInterval(timerInner.value) | 449 | + clearInterval(timerInner.value) |
| 514 | - const timeInner = innerRefreshTime.value | 450 | + const timeInner = innerRefreshTime.value |
| 515 | - timerInner.value = useIntervalTime( | 451 | + timerInner.value = useIntervalTime( |
| 516 | - () => { | 452 | + () => { |
| 517 | - loadSessionData(instanceId.value, sessionId.value) | 453 | + loadSessionData(instanceId.value, sessionId.value) |
| 518 | - }, | 454 | + }, |
| 519 | - computed(() => timeInner * 1000) | 455 | + computed(() => timeInner * 1000) |
| 520 | - ) | 456 | + ) |
| 521 | } | 457 | } |
| 522 | const gotoSessionDetail = (id: string) => { | 458 | const gotoSessionDetail = (id: string) => { |
| 523 | - const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | 459 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') |
| 524 | - if (curMode === 'wujie') { | 460 | + if (curMode === 'wujie') { |
| 525 | - // @ts-ignore plug-in components | 461 | + // @ts-ignore plug-in components |
| 526 | - window.$wujie?.props.methods.jump({ | 462 | + window.$wujie?.props.methods.jump({ |
| 527 | - name: `Static-pluginObservability-instanceVemSessionDetail`, | 463 | + name: `Static-pluginObservability-instanceVemSessionDetail`, |
| 528 | - query: { | 464 | + query: { |
| 529 | - dbid: instanceId.value, | 465 | + dbid: instanceId.value, |
| 530 | - id, | 466 | + id, |
| 531 | - }, | 467 | + }, |
| 532 | - }) | 468 | + }) |
| 533 | - } else { | 469 | + } else { |
| 534 | - // local | 470 | + // local |
| 535 | - window.sessionStorage.setItem('sqlId', id) | 471 | + window.sessionStorage.setItem('sqlId', id) |
| 536 | - router.push(`/vem/sessionDetail/${instanceId.value}/${id}`) | 472 | + router.push(`/vem/sessionDetail/${instanceId.value}/${id}`) |
| 537 | - } | 473 | + } |
| 538 | } | 474 | } |
| 539 | </script> | 475 | </script> |
Mplugins/observability-instance/web-ui/src/pages/dashboardV2/instanceMonitor/topSQL/Index.vue+126-114
| @@ -1,44 +1,54 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | - <IndexBar :tabId="props.tabId"></IndexBar> | 2 | + <IndexBar :tabId="props.tabId"></IndexBar> |
| 3 | - <div style="margin-bottom: 0px"></div> | 3 | + <div style="margin-bottom: 0px"></div> |
| 4 | - <div class="top-sql"> | 4 | + <div class="top-sql"> |
| 5 | - <el-tabs v-model="typeTab" class="tab2"> | 5 | + <el-tabs v-model="typeTab" class="tab2"> |
| 6 | - <el-tab-pane label="DB_TIME" name="db_time" /> | 6 | + <el-tab-pane label="DB_TIME" name="db_time" /> |
| 7 | - <el-tab-pane label="CPU_TIME" name="cpu_time" /> | 7 | + <el-tab-pane label="CPU_TIME" name="cpu_time" /> |
| 8 | - <el-tab-pane label="EXEC_TIME" name="execution_time" /> | 8 | + <el-tab-pane label="EXEC_TIME" name="execution_time" /> |
| 9 | - </el-tabs> | 9 | + <el-tab-pane label="IO_TIME" name="data_io_time" /> |
| 10 | - <div class="top-sql-table" v-if="!errorInfo" v-loading="loading"> | 10 | + </el-tabs> |
| 11 | - <el-table :data="data.tableData" border> | 11 | + <div class="top-sql-table" v-if="!errorInfo" v-loading="loading"> |
| 12 | - <el-table-column label="SQLID" width="150"> | 12 | + <el-table :data="data.tableData" border> |
| 13 | - <template #default="scope"> | 13 | + <el-table-column label="SQLID" width="150"> |
| 14 | - <el-link type="primary" @click="gotoTopsqlDetail(scope.row.debug_query_id)"> | 14 | + <template #default="scope"> |
| 15 | - {{ scope.row.debug_query_id }} | 15 | + <el-link type="primary" @click="gotoTopsqlDetail(scope.row.debug_query_id)"> |
| 16 | - </el-link> | 16 | + {{ scope.row.debug_query_id }} |
| 17 | - </template> | 17 | + </el-link> |
| 18 | - </el-table-column> | 18 | + </template> |
| 19 | - <el-table-column :label="$t('sql.dbName')" prop="db_name" width="90"></el-table-column> | 19 | + </el-table-column> |
| 20 | - <el-table-column :label="$t('sql.schemaName')" prop="schema_name" width="140"></el-table-column> | 20 | + <el-table-column :label="$t('sql.dbName')" prop="db_name" width="90" show-overflow-tooltip></el-table-column> |
| 21 | - <el-table-column :label="$t('sql.userName')" prop="user_name" width="90"></el-table-column> | 21 | + <el-table-column :label="$t('sql.schemaName')" prop="schema_name" width="100" show-overflow-tooltip> |
| 22 | - <el-table-column :label="$t('sql.applicationName')" prop="application_name"></el-table-column> | 22 | + </el-table-column> |
| 23 | - <el-table-column | 23 | + <el-table-column |
| 24 | - :label="$t('sql.startTime')" | 24 | + :label="$t('sql.userName')" |
| 25 | - :formatter="(r: any) => moment(r.start_time).format('YYYY-MM-DD HH:mm:ss')" | 25 | + prop="user_name" |
| 26 | - width="140" | 26 | + width="80" |
| 27 | - ></el-table-column> | 27 | + show-overflow-tooltip |
| 28 | - /> | 28 | + ></el-table-column> |
| 29 | - <el-table-column | 29 | + <el-table-column :label="$t('sql.applicationName')" prop="application_name" width="100" show-overflow-tooltip> |
| 30 | - :label="$t('sql.finishTime')" | 30 | + </el-table-column> |
| 31 | - :formatter="(r: any) => moment(r.finish_time).format('YYYY-MM-DD HH:mm:ss')" | 31 | + <el-table-column prop="query" label="SQL" show-overflow-tooltip /> |
| 32 | - width="140" | 32 | + <el-table-column |
| 33 | - ></el-table-column> | 33 | + :label="$t('sql.startTime')" |
| 34 | - /> | 34 | + :formatter="(r: any) => moment(r.start_time).format('YYYY-MM-DD HH:mm:ss')" |
| 35 | - <el-table-column :label="$t('sql.dbTime')" prop="db_time" width="110"></el-table-column> | 35 | + width="140" |
| 36 | - <el-table-column :label="$t('sql.cpuTime')" prop="cpu_time" width="115"></el-table-column> | 36 | + > |
| 37 | - <el-table-column :label="$t('sql.excutionTime')" prop="execution_time" width="120"></el-table-column> | 37 | + </el-table-column> |
| 38 | - </el-table> | 38 | + <el-table-column |
| 39 | - </div> | 39 | + :label="$t('sql.finishTime')" |
| 40 | - <my-message v-if="errorInfo" type="error" :tip="errorInfo" defaultTip="" /> | 40 | + :formatter="(r: any) => moment(r.finish_time).format('YYYY-MM-DD HH:mm:ss')" |
| 41 | + width="140" | ||
| 42 | + > | ||
| 43 | + </el-table-column> | ||
| 44 | + <el-table-column :label="$t('sql.dbTime')" prop="db_time" width="80"></el-table-column> | ||
| 45 | + <el-table-column :label="$t('sql.cpuTime')" prop="cpu_time" width="90"></el-table-column> | ||
| 46 | + <el-table-column :label="$t('sql.excutionTime')" prop="execution_time" width="90"></el-table-column> | ||
| 47 | + <el-table-column label="IO_TIME(ms)" prop="data_io_time" width="80"></el-table-column> | ||
| 48 | + </el-table> | ||
| 41 | </div> | 49 | </div> |
| 50 | + <my-message v-if="errorInfo" type="error" :tip="errorInfo" defaultTip="" /> | ||
| 51 | + </div> | ||
| 42 | </template> | 52 | </template> |
| 43 | 53 | ||
| 44 | <script setup lang="ts"> | 54 | <script setup lang="ts"> |
| @@ -64,111 +74,113 @@ const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId } = store | |||
| 64 | const { culRangeTimeAndStep } = monitorStore | 74 | const { culRangeTimeAndStep } = monitorStore |
| 65 | 75 | ||
| 66 | const data = reactive<{ | 76 | const data = reactive<{ |
| 67 | - tableData: Array<Record<string, string>> | 77 | + tableData: Array<Record<string, string>> |
| 68 | }>({ | 78 | }>({ |
| 69 | - tableData: [], | 79 | + tableData: [], |
| 70 | }) | 80 | }) |
| 71 | 81 | ||
| 72 | const getParam = () => { | 82 | const getParam = () => { |
| 73 | - return { | 83 | + return { |
| 74 | - dbid: instanceId, | 84 | + dbid: instanceId, |
| 75 | - startTime: dateFormat(new Date(culRangeTimeAndStep()[0] * 1000)), | 85 | + startTime: dateFormat(new Date(culRangeTimeAndStep()[0] * 1000)), |
| 76 | - finishTime: dateFormat(new Date(culRangeTimeAndStep()[1] * 1000)), | 86 | + finishTime: dateFormat(new Date(culRangeTimeAndStep()[1] * 1000)), |
| 77 | - } | 87 | + } |
| 78 | } | 88 | } |
| 79 | 89 | ||
| 80 | const outsideGoto = (key: string, param: any) => { | 90 | const outsideGoto = (key: string, param: any) => { |
| 81 | - if (param && param.key === tabKeys.InstanceMonitorTOPSQLCPUTime) typeTab.value = 'cpu_time' | 91 | + if (param && param.key === tabKeys.InstanceMonitorTOPSQLCPUTime) typeTab.value = 'cpu_time' |
| 92 | + if (param && param.key === tabKeys.InstanceMonitorTOPSQLIOTime) typeTab.value = 'data_io_time' | ||
| 82 | } | 93 | } |
| 83 | defineExpose({ outsideGoto }) | 94 | defineExpose({ outsideGoto }) |
| 84 | 95 | ||
| 85 | // same for every page in index | 96 | // same for every page in index |
| 86 | const timer = ref<number>() | 97 | const timer = ref<number>() |
| 87 | onMounted(() => { | 98 | onMounted(() => { |
| 88 | - load() | 99 | + load() |
| 89 | }) | 100 | }) |
| 90 | watch( | 101 | watch( |
| 91 | - updateCounter, | 102 | + updateCounter, |
| 92 | - () => { | 103 | + () => { |
| 93 | - clearInterval(timer.value) | 104 | + clearInterval(timer.value) |
| 94 | - if (tabNow.value === tabKeys.InstanceMonitorTOPSQL) { | 105 | + if (tabNow.value === tabKeys.InstanceMonitorTOPSQL) { |
| 95 | - if (updateCounter.value.source === sourceType.value.INSTANCE) load() | 106 | + if (updateCounter.value.source === sourceType.value.INSTANCE) load() |
| 96 | - if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() | 107 | + if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() |
| 97 | - if (updateCounter.value.source === sourceType.value.TIMETYPE) load() | 108 | + if (updateCounter.value.source === sourceType.value.TIMETYPE) load() |
| 98 | - if (updateCounter.value.source === sourceType.value.TIMERANGE) load() | 109 | + if (updateCounter.value.source === sourceType.value.TIMERANGE) load() |
| 99 | - if (updateCounter.value.source === sourceType.value.TABCHANGE) load() | 110 | + if (updateCounter.value.source === sourceType.value.TABCHANGE) load() |
| 100 | - const time = autoRefreshTime.value | 111 | + const time = autoRefreshTime.value |
| 101 | - timer.value = useIntervalTime( | 112 | + timer.value = useIntervalTime( |
| 102 | - () => { | 113 | + () => { |
| 103 | - load() | 114 | + load() |
| 104 | - }, | 115 | + }, |
| 105 | - computed(() => time * 1000) | 116 | + computed(() => time * 1000) |
| 106 | - ) | 117 | + ) |
| 107 | - } | 118 | + } |
| 108 | - }, | 119 | + }, |
| 109 | - { immediate: false } | 120 | + { immediate: false } |
| 110 | ) | 121 | ) |
| 111 | 122 | ||
| 112 | watch(typeTab, () => { | 123 | watch(typeTab, () => { |
| 113 | - load() | 124 | + load() |
| 114 | }) | 125 | }) |
| 115 | const load = () => { | 126 | const load = () => { |
| 116 | - requestData(getParam()) | 127 | + data.tableData = [] |
| 128 | + requestData(getParam()) | ||
| 117 | } | 129 | } |
| 118 | const { run: requestData, loading } = useRequest( | 130 | const { run: requestData, loading } = useRequest( |
| 119 | - (query) => { | 131 | + (query) => { |
| 120 | - const res = new Promise((resolve, reject) => { | 132 | + const res = new Promise((resolve, reject) => { |
| 121 | - const result = ogRequest.getNative( | 133 | + const result = ogRequest.getNative( |
| 122 | - `/observability/v1/topsql/list?id=${query.dbid}&startTime=${query.startTime}&finishTime=${query.finishTime}&orderField=${typeTab.value}` | 134 | + `/observability/v1/topsql/list?id=${query.dbid}&startTime=${query.startTime}&finishTime=${query.finishTime}&orderField=${typeTab.value}` |
| 123 | - ) | 135 | + ) |
| 124 | - result ? resolve(result) : reject(result) | 136 | + result ? resolve(result) : reject(result) |
| 125 | - }) | 137 | + }) |
| 126 | - .then((r: any) => { | 138 | + .then((r: any) => { |
| 127 | - const code = r?.data.code | 139 | + const code = r?.data.code |
| 128 | - const list = r?.data.data | 140 | + const list = r?.data.data |
| 129 | - if (code === 602) { | 141 | + if (code === 602) { |
| 130 | - errorInfo.value = t('dashboard.topsqlListTip') | 142 | + errorInfo.value = t('dashboard.topsqlListTip') |
| 131 | - } else if (code === 200 && Array.isArray(list)) { | 143 | + } else if (code === 200 && Array.isArray(list)) { |
| 132 | - errorInfo.value = '' | 144 | + errorInfo.value = '' |
| 133 | - data.tableData = list | 145 | + data.tableData = list |
| 134 | - } | 146 | + } |
| 135 | - }) | 147 | + }) |
| 136 | - .catch((e) => { | 148 | + .catch((e) => { |
| 137 | - errorInfo.value = e | 149 | + errorInfo.value = e |
| 138 | - }) | 150 | + }) |
| 139 | - return res | 151 | + return res |
| 140 | - }, | 152 | + }, |
| 141 | - { manual: true } | 153 | + { manual: true } |
| 142 | ) | 154 | ) |
| 143 | 155 | ||
| 144 | const gotoTopsqlDetail = (id: string) => { | 156 | const gotoTopsqlDetail = (id: string) => { |
| 145 | - const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | 157 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') |
| 146 | - if (curMode === 'wujie') { | 158 | + if (curMode === 'wujie') { |
| 147 | - // @ts-ignore plug-in components | 159 | + // @ts-ignore plug-in components |
| 148 | - window.$wujie?.props.methods.jump({ | 160 | + window.$wujie?.props.methods.jump({ |
| 149 | - name: `Static-pluginObservability-instanceVemSql_detail`, | 161 | + name: `Static-pluginObservability-instanceVemSql_detail`, |
| 150 | - query: { | 162 | + query: { |
| 151 | - dbid: getParam().dbid.value, | 163 | + dbid: getParam().dbid.value, |
| 152 | - id, | 164 | + id, |
| 153 | - }, | 165 | + }, |
| 154 | - }) | 166 | + }) |
| 155 | - } else { | 167 | + } else { |
| 156 | - // local | 168 | + // local |
| 157 | - window.sessionStorage.setItem('sqlId', id) | 169 | + window.sessionStorage.setItem('sqlId', id) |
| 158 | - router.push(`/vem/sql_detail/${getParam().dbid.value}/${id}`) | 170 | + router.push(`/vem/sql_detail/${getParam().dbid.value}/${id}`) |
| 159 | - } | 171 | + } |
| 160 | } | 172 | } |
| 161 | </script> | 173 | </script> |
| 162 | 174 | ||
| 163 | <style scoped lang="scss"> | 175 | <style scoped lang="scss"> |
| 164 | .top-sql { | 176 | .top-sql { |
| 165 | - &:deep(.el-tabs__header) { | 177 | + &:deep(.el-tabs__header) { |
| 166 | - width: 100%; | 178 | + width: 100%; |
| 167 | - } | 179 | + } |
| 168 | 180 | ||
| 169 | - &-table-id { | 181 | + &-table-id { |
| 170 | - color: #0093ff; | 182 | + color: #0093ff; |
| 171 | - cursor: pointer; | 183 | + cursor: pointer; |
| 172 | - } | 184 | + } |
| 173 | } | 185 | } |
| 174 | </style> | 186 | </style> |
| @@ -1,132 +1,159 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | - <el-row :gutter="12"> | 2 | + <el-row :gutter="12"> |
| 3 | - <el-col :span="12"> | 3 | + <el-col :span="12"> |
| 4 | - <my-card :title="$t('resourceMonitor.cpu.cpuUse')" height="300" :bodyPadding="false"> | 4 | + <my-card :title="$t('resourceMonitor.cpu.cpuUse')" height="300" :bodyPadding="false"> |
| 5 | - <template #headerExtend> | 5 | + <template #headerExtend> |
| 6 | - <div class="card-links"> | 6 | + <div class="card-links"> |
| 7 | - <el-link | 7 | + <el-link |
| 8 | - v-if="isManualRangeSelected" | 8 | + v-if="isManualRangeSelected" |
| 9 | - type="primary" | 9 | + type="primary" |
| 10 | - @click="goto(tabKeys.InstanceMonitorTOPSQL, { key: tabKeys.InstanceMonitorTOPSQLCPUTime })" | 10 | + @click="goto(tabKeys.InstanceMonitorTOPSQL, { key: tabKeys.InstanceMonitorTOPSQLCPUTime })" |
| 11 | - > | 11 | + > |
| 12 | - TOP CPU SQL | 12 | + TOP CPU SQL |
| 13 | - </el-link> | 13 | + </el-link> |
| 14 | - <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> | 14 | + <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> |
| 15 | - {{ $t('app.diagnosis') }} | 15 | + {{ $t('app.diagnosis') }} |
| 16 | - </el-link> | 16 | + </el-link> |
| 17 | - </div> | 17 | + <el-link v-if="isManualRangeSelected" type="primary" @click="wdr(tabId)" v-loading="wdrLoading"> |
| 18 | - </template> | 18 | + {{$t('instanceIndex.wdrAnalysis')}} |
| 19 | - <LazyLine | 19 | + </el-link> |
| 20 | - :tips="$t('instanceIndex.activeSessionQtyTips')" | 20 | + </div> |
| 21 | - :rangeSelect="true" | 21 | + </template> |
| 22 | - :tabId="props.tabId" | 22 | + <LazyLine |
| 23 | - :formatter="toFixed" | 23 | + :tips="$t('instanceIndex.activeSessionQtyTips')" |
| 24 | - :data="metricsData.cpu" | 24 | + :rangeSelect="true" |
| 25 | - :xData="metricsData.time" | 25 | + :tabId="props.tabId" |
| 26 | - :max="100" | 26 | + :formatter="toFixed" |
| 27 | - :min="0" | 27 | + :data="metricsData.cpu" |
| 28 | - :interval="25" | 28 | + :xData="metricsData.time" |
| 29 | - :unit="'%'" | 29 | + :max="100" |
| 30 | - /> | 30 | + :min="0" |
| 31 | - </my-card> | 31 | + :interval="25" |
| 32 | - </el-col> | 32 | + :unit="'%'" |
| 33 | - <el-col :span="12"> | 33 | + /> |
| 34 | - <my-card :title="$t('resourceMonitor.cpu.cpuLoad')" height="300" :bodyPadding="false"> | 34 | + </my-card> |
| 35 | - <LazyLine | 35 | + </el-col> |
| 36 | - :tabId="props.tabId" | 36 | + <el-col :span="12"> |
| 37 | - :formatter="toFixed" | 37 | + <my-card :title="$t('resourceMonitor.cpu.cpuLoad')" height="300" :bodyPadding="false"> |
| 38 | - :data="metricsData.cpuPayload" | 38 | + <LazyLine :tabId="props.tabId" :formatter="toFixed" :data="metricsData.cpuPayload" :xData="metricsData.time" /> |
| 39 | - :xData="metricsData.time" | 39 | + </my-card> |
| 40 | - /> | 40 | + </el-col> |
| 41 | - </my-card> | 41 | + </el-row> |
| 42 | - </el-col> | ||
| 43 | - </el-row> | ||
| 44 | 42 | ||
| 45 | - <div style="margin-bottom: 12px"></div> | 43 | + <div style="margin-bottom: 12px"></div> |
| 46 | - <div style="position: relative"> | 44 | + <div style="position: relative"> |
| 47 | - <div | 45 | + <div |
| 48 | - style=" | 46 | + style=" |
| 49 | - position: absolute; | 47 | + position: absolute; |
| 50 | - right: 0px; | 48 | + right: 0px; |
| 51 | - top: 2px; | 49 | + top: 2px; |
| 52 | - z-index: 1; | 50 | + z-index: 1; |
| 53 | - display: flex; | 51 | + display: flex; |
| 54 | - flex-direction: row; | 52 | + flex-direction: row; |
| 55 | - align-items: center; | 53 | + align-items: center; |
| 56 | - font-size: 12px; | 54 | + font-size: 12px; |
| 57 | - " | 55 | + " |
| 58 | - > | 56 | + > |
| 59 | - <div style="margin-right: 12px">{{ $t('app.refreshOn') }} {{ innerRefreshDoneTime }}</div> | 57 | + <div style="margin-right: 12px">{{ $t('app.refreshOn') }} {{ innerRefreshDoneTime }}</div> |
| 60 | - <div>{{ $t('app.autoRefreshFor') }}</div> | 58 | + <div>{{ $t('app.autoRefreshFor') }}</div> |
| 61 | - <el-select v-model="innerRefreshTime" style="width: 60px; margin: 0 4px" @change="updateTimerInner"> | 59 | + <el-select v-model="innerRefreshTime" style="width: 100px; margin: 0 4px" @change="updateTimerInner"> |
| 62 | - <el-option :value="1" label="1s" /> | 60 | + <el-option :value="99999999" label="NO-AUTO" /> |
| 63 | - <el-option :value="15" label="15s" /> | 61 | + <el-option :value="1" label="1s" /> |
| 64 | - <el-option :value="30" label="30s" /> | 62 | + <el-option :value="15" label="15s" /> |
| 65 | - <el-option :value="60" label="60s" /> | 63 | + <el-option :value="30" label="30s" /> |
| 66 | - </el-select> | 64 | + <el-option :value="60" label="60s" /> |
| 67 | - <el-button | 65 | + </el-select> |
| 68 | - class="refresh-button" | 66 | + <el-button |
| 69 | - type="primary" | 67 | + class="refresh-button" |
| 70 | - :icon="Refresh" | 68 | + type="primary" |
| 71 | - style="margin-left: 8px" | 69 | + :icon="Refresh" |
| 72 | - @click="loadTOPCPUProcessNow(props.tabId)" | 70 | + style="margin-left: 8px" |
| 73 | - /> | 71 | + @click="loadTOPCPUProcessNow(props.tabId)" |
| 74 | - </div> | 72 | + /> |
| 75 | - <el-tabs v-model="tab" class="tab2"> | ||
| 76 | - <el-tab-pane :label="$t('resourceMonitor.cpu.topProcess')" :name="0"> | ||
| 77 | - <el-table | ||
| 78 | - :table-layout="'auto'" | ||
| 79 | - :data="topCPUProcessNowData == null ? [] : topCPUProcessNowData" | ||
| 80 | - style="width: 100%" | ||
| 81 | - :border="true" | ||
| 82 | - :header-cell-class-name=" | ||
| 83 | - () => { | ||
| 84 | - return 'grid-header' | ||
| 85 | - } | ||
| 86 | - " | ||
| 87 | - > | ||
| 88 | - <el-table-column prop="%CPU" label="%CPU" width="60" /> | ||
| 89 | - <el-table-column prop="%MEM" label="%MEM" width="60" /> | ||
| 90 | - <el-table-column prop="COMMAND" label="COMMAND" /> | ||
| 91 | - <el-table-column prop="NI" label="NI" width="40" /> | ||
| 92 | - <el-table-column prop="PID" label="PID" width="90" /> | ||
| 93 | - <el-table-column prop="PR" label="PR" width="40" /> | ||
| 94 | - <el-table-column prop="RES" label="RES" width="80" /> | ||
| 95 | - <el-table-column prop="S" label="S" width="40" /> | ||
| 96 | - <el-table-column prop="SHR" label="SHR" width="80" /> | ||
| 97 | - <el-table-column prop="TIME+" label="TIME+" width="100" /> | ||
| 98 | - <el-table-column prop="USER" label="USER" width="120" /> | ||
| 99 | - <el-table-column prop="VIRT" label="VIRT" width="120" /> | ||
| 100 | - </el-table> | ||
| 101 | - </el-tab-pane> | ||
| 102 | - <el-tab-pane :label="$t('resourceMonitor.cpu.topThread')" :name="1"> | ||
| 103 | - <el-table | ||
| 104 | - :table-layout="'auto'" | ||
| 105 | - :data="topCPUDBThreadNowData == null ? [] : topCPUDBThreadNowData" | ||
| 106 | - style="width: 100%" | ||
| 107 | - :border="true" | ||
| 108 | - :header-cell-class-name=" | ||
| 109 | - () => { | ||
| 110 | - return 'grid-header' | ||
| 111 | - } | ||
| 112 | - " | ||
| 113 | - > | ||
| 114 | - <el-table-column prop="%CPU" label="%CPU" width="60" /> | ||
| 115 | - <el-table-column prop="%MEM" label="%MEM" width="60" /> | ||
| 116 | - <el-table-column prop="COMMAND" label="COMMAND" /> | ||
| 117 | - <el-table-column prop="NI" label="NI" width="40" /> | ||
| 118 | - <el-table-column prop="PID" label="PID" width="90" /> | ||
| 119 | - <el-table-column prop="PR" label="PR" width="40" /> | ||
| 120 | - <el-table-column prop="RES" label="RES" width="80" /> | ||
| 121 | - <el-table-column prop="S" label="S" width="40" /> | ||
| 122 | - <el-table-column prop="SHR" label="SHR" width="80" /> | ||
| 123 | - <el-table-column prop="TIME+" label="TIME+" width="100" /> | ||
| 124 | - <el-table-column prop="USER" label="USER" width="120" /> | ||
| 125 | - <el-table-column prop="VIRT" label="VIRT" width="120" /> | ||
| 126 | - </el-table> | ||
| 127 | - </el-tab-pane> | ||
| 128 | - </el-tabs> | ||
| 129 | </div> | 73 | </div> |
| 74 | + <el-tabs v-model="tab" class="tab2"> | ||
| 75 | + <el-tab-pane :label="$t('resourceMonitor.cpu.topProcess')" :name="0"> | ||
| 76 | + <el-table | ||
| 77 | + :table-layout="'auto'" | ||
| 78 | + :data="topCPUProcessNowData == null ? [] : topCPUProcessNowData" | ||
| 79 | + style="width: 100%" | ||
| 80 | + :border="true" | ||
| 81 | + :header-cell-class-name=" | ||
| 82 | + () => { | ||
| 83 | + return 'grid-header' | ||
| 84 | + } | ||
| 85 | + " | ||
| 86 | + :row-class-name="rowClassName" | ||
| 87 | + > | ||
| 88 | + <el-table-column prop="%CPU" label="%CPU" width="60" /> | ||
| 89 | + <el-table-column prop="%MEM" label="%MEM" width="60" /> | ||
| 90 | + <el-table-column label="COMMAND" width="260" show-overflow-tooltip> | ||
| 91 | + <template #default="scope"> | ||
| 92 | + <el-link | ||
| 93 | + v-if="scope.row.port && node.dbPort != scope.row.port" | ||
| 94 | + type="primary" | ||
| 95 | + class="top-sql-table-id" | ||
| 96 | + @click="changeCluster(scope.row)" | ||
| 97 | + > | ||
| 98 | + {{ scope.row.COMMAND }} | ||
| 99 | + </el-link> | ||
| 100 | + <span v-else>{{ scope.row.COMMAND }}</span> | ||
| 101 | + </template> | ||
| 102 | + </el-table-column> | ||
| 103 | + <el-table-column prop="FullCommand" label="FULL COMMAND" show-overflow-tooltip /> | ||
| 104 | + <el-table-column prop="NI" label="NI" width="40" /> | ||
| 105 | + <el-table-column prop="PID" label="PID" width="90" /> | ||
| 106 | + <el-table-column prop="PR" label="PR" width="40" /> | ||
| 107 | + <el-table-column prop="RES" label="RES" width="80" /> | ||
| 108 | + <el-table-column prop="S" label="S" width="40" /> | ||
| 109 | + <el-table-column prop="SHR" label="SHR" width="80" /> | ||
| 110 | + <el-table-column prop="TIME+" label="TIME+" width="100" /> | ||
| 111 | + <el-table-column prop="USER" label="USER" width="120" /> | ||
| 112 | + <el-table-column prop="VIRT" label="VIRT" width="120" /> | ||
| 113 | + </el-table> | ||
| 114 | + </el-tab-pane> | ||
| 115 | + <el-tab-pane :label="$t('resourceMonitor.cpu.topThread')" :name="1"> | ||
| 116 | + <el-table | ||
| 117 | + :table-layout="'auto'" | ||
| 118 | + :data="topCPUDBThreadNowData == null ? [] : topCPUDBThreadNowData" | ||
| 119 | + style="width: 100%" | ||
| 120 | + :border="true" | ||
| 121 | + :header-cell-class-name=" | ||
| 122 | + () => { | ||
| 123 | + return 'grid-header' | ||
| 124 | + } | ||
| 125 | + " | ||
| 126 | + > | ||
| 127 | + <el-table-column prop="%CPU" label="%CPU" width="60" /> | ||
| 128 | + <el-table-column prop="%MEM" label="%MEM" width="60" /> | ||
| 129 | + <el-table-column prop="COMMAND" label="COMMAND" show-overflow-tooltip /> | ||
| 130 | + <el-table-column prop="NI" label="NI" width="40" /> | ||
| 131 | + <el-table-column prop="PID" label="PID" width="90" /> | ||
| 132 | + <el-table-column prop="PR" label="PR" width="40" /> | ||
| 133 | + <el-table-column prop="RES" label="RES" width="80" /> | ||
| 134 | + <el-table-column prop="S" label="S" width="40" /> | ||
| 135 | + <el-table-column prop="SHR" label="SHR" width="80" /> | ||
| 136 | + <el-table-column prop="TIME+" label="TIME+" width="100" /> | ||
| 137 | + <el-table-column prop="USER" label="USER" width="120" /> | ||
| 138 | + <el-table-column prop="VIRT" label="VIRT" width="120" /> | ||
| 139 | + <el-table-column :label="$t('session.trans.sessionID')" width="130"> | ||
| 140 | + <template #default="scope"> | ||
| 141 | + <el-link type="primary" class="top-sql-table-id" @click="gotoSessionDetail(scope.row.sessionid)"> | ||
| 142 | + {{ scope.row.sessionid }} | ||
| 143 | + </el-link> | ||
| 144 | + </template> | ||
| 145 | + </el-table-column> | ||
| 146 | + <el-table-column label="SQLID" width="150"> | ||
| 147 | + <template #default="scope"> | ||
| 148 | + <el-link type="primary" @click="gotoTopsqlDetail(scope.row.query_id)"> | ||
| 149 | + {{ scope.row.query_id }} | ||
| 150 | + </el-link> | ||
| 151 | + </template> | ||
| 152 | + </el-table-column> | ||
| 153 | + </el-table> | ||
| 154 | + </el-tab-pane> | ||
| 155 | + </el-tabs> | ||
| 156 | + </div> | ||
| 130 | </template> | 157 | </template> |
| 131 | 158 | ||
| 132 | <script setup lang="ts"> | 159 | <script setup lang="ts"> |
| @@ -143,6 +170,8 @@ import { Refresh } from '@element-plus/icons-vue' | |||
| 143 | import moment from 'moment' | 170 | import moment from 'moment' |
| 144 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' | 171 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' |
| 145 | import { ElMessage } from 'element-plus' | 172 | import { ElMessage } from 'element-plus' |
| 173 | +import router from '@/router' | ||
| 174 | +import { getWDRSnapshot } from '@/api/wdr' | ||
| 146 | 175 | ||
| 147 | const { t } = useI18n() | 176 | const { t } = useI18n() |
| 148 | 177 | ||
| @@ -150,184 +179,300 @@ const props = withDefaults(defineProps<{ tabId: string }>(), {}) | |||
| 150 | const tab = 0 | 179 | const tab = 0 |
| 151 | 180 | ||
| 152 | interface LineData { | 181 | interface LineData { |
| 153 | - name: string | 182 | + name: string |
| 154 | - data: any[] | 183 | + data: any[] |
| 155 | - [other: string]: any | 184 | + [other: string]: any |
| 156 | } | 185 | } |
| 157 | interface MetricsData { | 186 | interface MetricsData { |
| 158 | - cpu: LineData[] | 187 | + cpu: LineData[] |
| 159 | - cpuPayload: LineData[] | 188 | + cpuPayload: LineData[] |
| 160 | - time: string[] | 189 | + time: string[] |
| 161 | } | 190 | } |
| 162 | const metricsData = ref<MetricsData>({ | 191 | const metricsData = ref<MetricsData>({ |
| 163 | - cpu: [], | 192 | + cpu: [], |
| 164 | - cpuPayload: [], | 193 | + cpuPayload: [], |
| 165 | - time: [], | 194 | + time: [], |
| 166 | }) | 195 | }) |
| 167 | const topCPUProcessNowData = ref<void | TopCPUProcessNow[]>([]) | 196 | const topCPUProcessNowData = ref<void | TopCPUProcessNow[]>([]) |
| 168 | const topCPUDBThreadNowData = ref<void | TopCPUProcessNow[]>([]) | 197 | const topCPUDBThreadNowData = ref<void | TopCPUProcessNow[]>([]) |
| 169 | const innerRefreshTime = ref<number>(30) | 198 | const innerRefreshTime = ref<number>(30) |
| 170 | const innerRefreshDoneTime = ref<string>('') | 199 | const innerRefreshDoneTime = ref<string>('') |
| 171 | -const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId, isManualRangeSelected, timeRange } = | 200 | +const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId, isManualRangeSelected, timeRange, node } = |
| 172 | - storeToRefs(useMonitorStore(props.tabId)) | 201 | + storeToRefs(useMonitorStore(props.tabId)) |
| 173 | 202 | ||
| 174 | // same for every page in index | 203 | // same for every page in index |
| 175 | const timer = ref<number>() | 204 | const timer = ref<number>() |
| 176 | onMounted(() => { | 205 | onMounted(() => { |
| 177 | - load() | 206 | + load() |
| 178 | - loadTOPCPUProcessNow(props.tabId) | 207 | + loadTOPCPUProcessNow(props.tabId) |
| 179 | }) | 208 | }) |
| 180 | watch( | 209 | watch( |
| 181 | - updateCounter, | 210 | + updateCounter, |
| 182 | - () => { | 211 | + () => { |
| 183 | - clearInterval(timer.value) | 212 | + clearInterval(timer.value) |
| 184 | - if (tabNow.value === tabKeys.ResourceMonitorCPU) { | 213 | + if (tabNow.value === tabKeys.ResourceMonitorCPU) { |
| 185 | - if (updateCounter.value.source === sourceType.value.INSTANCE) { | 214 | + if (updateCounter.value.source === sourceType.value.INSTANCE) { |
| 186 | - load() | 215 | + load() |
| 187 | - loadTOPCPUProcessNow(props.tabId) | 216 | + loadTOPCPUProcessNow(props.tabId) |
| 188 | - } | 217 | + } |
| 189 | - if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() | 218 | + if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() |
| 190 | - if (updateCounter.value.source === sourceType.value.TIMETYPE) load() | 219 | + if (updateCounter.value.source === sourceType.value.TIMETYPE) load() |
| 191 | - if (updateCounter.value.source === sourceType.value.TIMERANGE) load() | 220 | + if (updateCounter.value.source === sourceType.value.TIMERANGE) load() |
| 192 | - if (updateCounter.value.source === sourceType.value.TABCHANGE) load() | 221 | + if (updateCounter.value.source === sourceType.value.TABCHANGE) load() |
| 193 | - const time = autoRefreshTime.value | 222 | + const time = autoRefreshTime.value |
| 194 | - timer.value = useIntervalTime( | 223 | + timer.value = useIntervalTime( |
| 195 | - () => { | 224 | + () => { |
| 196 | - load() | 225 | + load() |
| 197 | - }, | 226 | + }, |
| 198 | - computed(() => time * 1000) | 227 | + computed(() => time * 1000) |
| 199 | - ) | 228 | + ) |
| 200 | - updateTimerInner() | 229 | + updateTimerInner() |
| 201 | - } | 230 | + } |
| 202 | - }, | 231 | + }, |
| 203 | - { immediate: false } | 232 | + { immediate: false } |
| 204 | ) | 233 | ) |
| 205 | 234 | ||
| 206 | // load data | 235 | // load data |
| 207 | const load = (checkTab?: boolean, checkRange?: boolean) => { | 236 | const load = (checkTab?: boolean, checkRange?: boolean) => { |
| 208 | - if (!instanceId.value) return | 237 | + if (!instanceId.value) return |
| 209 | - requestData(props.tabId) | 238 | + requestData(props.tabId) |
| 239 | +} | ||
| 240 | + | ||
| 241 | +const rowClassName = ({ row }: { row: any }) => { | ||
| 242 | + if (row.port) { | ||
| 243 | + return 'highlight-row' | ||
| 244 | + } | ||
| 245 | + return '' | ||
| 210 | } | 246 | } |
| 211 | const { data: indexData, run: requestData } = useRequest(getCPUMetrics, { manual: true }) | 247 | const { data: indexData, run: requestData } = useRequest(getCPUMetrics, { manual: true }) |
| 212 | watch( | 248 | watch( |
| 213 | - indexData, | 249 | + indexData, |
| 214 | - () => { | 250 | + () => { |
| 215 | - // clear data | 251 | + // clear data |
| 216 | - metricsData.value.cpu = [] | 252 | + metricsData.value.cpu = [] |
| 217 | - metricsData.value.cpuPayload = [] | 253 | + metricsData.value.cpuPayload = [] |
| 218 | 254 | ||
| 219 | - const baseData = indexData.value | 255 | + const baseData = indexData.value |
| 220 | - if (!baseData) return | 256 | + if (!baseData) return |
| 221 | 257 | ||
| 222 | - { | 258 | + { |
| 223 | - let tempData: string[] = [] | 259 | + let tempData: string[] = [] |
| 224 | - baseData.CPU_TOTAL.forEach((d: number) => { | 260 | + baseData.CPU_DB.forEach((d: number) => { |
| 225 | - tempData.push(toFixed(d)) | 261 | + tempData.push(toFixed(d)) |
| 226 | - }) | 262 | + }) |
| 227 | - metricsData.value.cpu.push({ data: tempData, name: 'Total' }) | 263 | + metricsData.value.cpu.push({ data: tempData, name: t('resourceMonitor.cpu.dbThread') }) |
| 228 | - } | 264 | + } |
| 229 | - { | 265 | + { |
| 230 | - let tempData: string[] = [] | 266 | + let tempData: string[] = [] |
| 231 | - baseData.CPU_IOWAIT.forEach((d: number) => { | 267 | + baseData.CPU_TOTAL.forEach((d: number) => { |
| 232 | - tempData.push(toFixed(d)) | 268 | + tempData.push(toFixed(d)) |
| 233 | - }) | 269 | + }) |
| 234 | - metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'IOWait' }) | 270 | + metricsData.value.cpu.push({ data: tempData, name: 'Total' }) |
| 235 | - } | 271 | + } |
| 236 | - { | 272 | + { |
| 237 | - let tempData: string[] = [] | 273 | + let tempData: string[] = [] |
| 238 | - baseData.CPU_SYSTEM.forEach((d: number) => { | 274 | + baseData.CPU_USER.forEach((d: number) => { |
| 239 | - tempData.push(toFixed(d)) | 275 | + tempData.push(toFixed(d)) |
| 240 | - }) | 276 | + }) |
| 241 | - metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'System' }) | 277 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'User' }) |
| 242 | - } | 278 | + } |
| 243 | - { | 279 | + { |
| 244 | - let tempData: string[] = [] | 280 | + let tempData: string[] = [] |
| 245 | - baseData.CPU_USER.forEach((d: number) => { | 281 | + baseData.CPU_SYSTEM.forEach((d: number) => { |
| 246 | - tempData.push(toFixed(d)) | 282 | + tempData.push(toFixed(d)) |
| 247 | - }) | 283 | + }) |
| 248 | - metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'User' }) | 284 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'System' }) |
| 249 | - } | 285 | + } |
| 250 | - { | 286 | + { |
| 251 | - let tempData: string[] = [] | 287 | + let tempData: string[] = [] |
| 252 | - baseData.CPU_DB.forEach((d: number) => { | 288 | + baseData.CPU_IOWAIT.forEach((d: number) => { |
| 253 | - tempData.push(toFixed(d)) | 289 | + tempData.push(toFixed(d)) |
| 254 | - }) | 290 | + }) |
| 255 | - metricsData.value.cpu.push({ data: tempData, name: t('resourceMonitor.cpu.dbThread') }) | 291 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'IOWait' }) |
| 256 | - } | 292 | + } |
| 257 | - { | 293 | + { |
| 258 | - let tempData: string[] = [] | 294 | + let tempData: string[] = [] |
| 259 | - baseData.CPU_TOTAL_5M_LOAD.forEach((d: number) => { | 295 | + baseData.CPU_NICE.forEach((d: number) => { |
| 260 | - tempData.push(toFixed(d)) | 296 | + tempData.push(toFixed(d)) |
| 261 | - }) | 297 | + }) |
| 262 | - metricsData.value.cpuPayload.push({ data: tempData, name: t('resourceMonitor.cpu.total5mLoad') }) | 298 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Nice' }) |
| 263 | - } | 299 | + } |
| 264 | - { | 300 | + { |
| 265 | - let tempData: string[] = [] | 301 | + let tempData: string[] = [] |
| 266 | - baseData.CPU_TOTAL_CORE_NUM.forEach((d: number) => { | 302 | + baseData.CPU_IRQ.forEach((d: number) => { |
| 267 | - tempData.push(toFixed(d)) | 303 | + tempData.push(toFixed(d)) |
| 268 | - }) | 304 | + }) |
| 269 | - metricsData.value.cpuPayload.push({ data: tempData, name: t('resourceMonitor.cpu.coreNum') }) | 305 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'IRQ' }) |
| 270 | - } | 306 | + } |
| 307 | + { | ||
| 308 | + let tempData: string[] = [] | ||
| 309 | + baseData.CPU_SOFTIRQ.forEach((d: number) => { | ||
| 310 | + tempData.push(toFixed(d)) | ||
| 311 | + }) | ||
| 312 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Soft IRQ' }) | ||
| 313 | + } | ||
| 314 | + { | ||
| 315 | + let tempData: string[] = [] | ||
| 316 | + baseData.CPU_STEAL.forEach((d: number) => { | ||
| 317 | + tempData.push(toFixed(d)) | ||
| 318 | + }) | ||
| 319 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Steal' }) | ||
| 320 | + } | ||
| 321 | + { | ||
| 322 | + let tempData: string[] = [] | ||
| 323 | + baseData.CPU_IDLE.forEach((d: number) => { | ||
| 324 | + tempData.push(toFixed(d)) | ||
| 325 | + }) | ||
| 326 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Idle' }) | ||
| 327 | + } | ||
| 328 | + { | ||
| 329 | + let tempData: string[] = [] | ||
| 330 | + baseData.CPU_TOTAL_5M_LOAD.forEach((d: number) => { | ||
| 331 | + tempData.push(toFixed(d)) | ||
| 332 | + }) | ||
| 333 | + metricsData.value.cpuPayload.push({ data: tempData, name: t('resourceMonitor.cpu.total5mLoad') }) | ||
| 334 | + } | ||
| 335 | + { | ||
| 336 | + let tempData: string[] = [] | ||
| 337 | + baseData.CPU_TOTAL_CORE_NUM.forEach((d: number) => { | ||
| 338 | + tempData.push(toFixed(d)) | ||
| 339 | + }) | ||
| 340 | + metricsData.value.cpuPayload.push({ data: tempData, name: t('resourceMonitor.cpu.coreNum') }) | ||
| 341 | + } | ||
| 271 | 342 | ||
| 272 | - metricsData.value.cpu = metricsData.value.cpu.sort((a, b) => { | 343 | + metricsData.value.cpu = metricsData.value.cpu.sort((a, b) => { |
| 273 | - const sorts = ['CPU_TOTAL', 'CPU_USER', 'CPU_SYSTEM', 'CPU_IOWAIT'] | 344 | + const sorts = ['CPU_TOTAL', 'CPU_USER', 'CPU_SYSTEM', 'CPU_IOWAIT'] |
| 274 | - return sorts.indexOf(a.name) - sorts.indexOf(b.name) | 345 | + return sorts.indexOf(a.name) - sorts.indexOf(b.name) |
| 275 | - }) | 346 | + }) |
| 276 | - metricsData.value.cpuPayload = metricsData.value.cpuPayload.sort((a, b) => { | 347 | + metricsData.value.cpuPayload = metricsData.value.cpuPayload.sort((a, b) => { |
| 277 | - const sorts = ['CPU_TOTAL_5M_LOAD', 'CPU_TOTAL_CORE_NUM', 'CPU_TOTAL_AVERAGE_UTILIZATION'] | 348 | + const sorts = ['CPU_TOTAL_5M_LOAD', 'CPU_TOTAL_CORE_NUM', 'CPU_TOTAL_AVERAGE_UTILIZATION'] |
| 278 | - return sorts.indexOf(a.name) - sorts.indexOf(b.name) | 349 | + return sorts.indexOf(a.name) - sorts.indexOf(b.name) |
| 279 | - }) | 350 | + }) |
| 280 | 351 | ||
| 281 | - // time | 352 | + // time |
| 282 | - metricsData.value.time = baseData.time | 353 | + metricsData.value.time = baseData.time |
| 283 | - }, | 354 | + }, |
| 284 | - { deep: true } | 355 | + { deep: true } |
| 285 | ) | 356 | ) |
| 286 | const { data: topCPUProcessNowResult, run: loadTOPCPUProcessNow } = useRequest(getTOPCPUProcessNow, { manual: true }) | 357 | const { data: topCPUProcessNowResult, run: loadTOPCPUProcessNow } = useRequest(getTOPCPUProcessNow, { manual: true }) |
| 287 | watch( | 358 | watch( |
| 288 | - topCPUProcessNowResult, | 359 | + topCPUProcessNowResult, |
| 289 | - () => { | 360 | + () => { |
| 290 | - topCPUProcessNowData.value = topCPUProcessNowResult.value ? topCPUProcessNowResult.value[0] : [] | 361 | + topCPUProcessNowData.value = topCPUProcessNowResult.value ? topCPUProcessNowResult.value[0] : [] |
| 291 | - topCPUDBThreadNowData.value = topCPUProcessNowResult.value ? topCPUProcessNowResult.value[1] : [] | 362 | + topCPUDBThreadNowData.value = topCPUProcessNowResult.value ? topCPUProcessNowResult.value[1] : [] |
| 292 | - innerRefreshDoneTime.value = moment(new Date()).format('HH:mm:ss') | 363 | + topCPUProcessNowData.value.forEach((item) => { |
| 293 | - }, | 364 | + if (item.port) { |
| 294 | - { deep: true } | 365 | + item.COMMAND += '(' + node.value.publicIp + ':' + item.port |
| 366 | + if (node.value.dbPort.toString() === item.port.toString()) { | ||
| 367 | + item.COMMAND += t('instanceMonitor.thisInstance') | ||
| 368 | + } | ||
| 369 | + item.COMMAND += ')' | ||
| 370 | + item.publicIp = node.value.publicIp | ||
| 371 | + } | ||
| 372 | + }) | ||
| 373 | + innerRefreshDoneTime.value = moment(new Date()).format('HH:mm:ss') | ||
| 374 | + }, | ||
| 375 | + { deep: true } | ||
| 295 | ) | 376 | ) |
| 296 | const timerInner = ref<number>() | 377 | const timerInner = ref<number>() |
| 297 | const updateTimerInner = () => { | 378 | const updateTimerInner = () => { |
| 298 | - clearInterval(timerInner.value) | 379 | + clearInterval(timerInner.value) |
| 299 | - const timeInner = innerRefreshTime.value | 380 | + const timeInner = innerRefreshTime.value |
| 300 | - timerInner.value = useIntervalTime( | 381 | + timerInner.value = useIntervalTime( |
| 301 | - () => { | 382 | + () => { |
| 302 | - loadTOPCPUProcessNow(props.tabId) | 383 | + loadTOPCPUProcessNow(props.tabId) |
| 303 | - }, | 384 | + }, |
| 304 | - computed(() => timeInner * 1000) | 385 | + computed(() => timeInner * 1000) |
| 305 | - ) | 386 | + ) |
| 387 | +} | ||
| 388 | +const emit = defineEmits(['goto', 'changeCluster']) | ||
| 389 | +const changeCluster = (row: TopCPUProcessNow) => { | ||
| 390 | + emit('changeCluster', row.publicIp, row.port) | ||
| 306 | } | 391 | } |
| 307 | -const emit = defineEmits(['goto']) | ||
| 308 | const goto = (key: string, param: object) => { | 392 | const goto = (key: string, param: object) => { |
| 309 | - emit('goto', key, param) | 393 | + emit('goto', key, param) |
| 310 | } | 394 | } |
| 311 | const gotoSQLDiagnosis = () => { | 395 | const gotoSQLDiagnosis = () => { |
| 312 | - hasSQLDiagnosisModule() | 396 | + hasSQLDiagnosisModule() |
| 313 | - .then(() => { | 397 | + .then(() => { |
| 314 | - const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | 398 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') |
| 315 | - if (curMode === 'wujie') { | 399 | + if (curMode === 'wujie') { |
| 316 | - // @ts-ignore plug-in components | 400 | + // @ts-ignore plug-in components |
| 317 | - window.$wujie?.props.methods.jump({ | 401 | + window.$wujie?.props.methods.jump({ |
| 318 | - name: `Static-pluginObservability-sql-diagnosisVemHistoryDiagnosis`, | 402 | + name: `Static-pluginObservability-sql-diagnosisVemHistoryDiagnosis`, |
| 319 | - query: { | 403 | + query: { |
| 320 | - instanceId: instanceId.value, | 404 | + instanceId: instanceId.value, |
| 321 | - startTime: timeRange.value[0], | 405 | + startTime: timeRange.value[0], |
| 322 | - endTime: timeRange.value[1], | 406 | + endTime: timeRange.value[1], |
| 323 | - }, | 407 | + }, |
| 324 | - }) | ||
| 325 | - } else ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 326 | - }) | ||
| 327 | - .catch(() => { | ||
| 328 | - ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 329 | }) | 408 | }) |
| 409 | + } else ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 410 | + }) | ||
| 411 | + .catch(() => { | ||
| 412 | + ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 413 | + }) | ||
| 330 | } | 414 | } |
| 415 | +const gotoSessionDetail = (id: string) => { | ||
| 416 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 417 | + if (curMode === 'wujie') { | ||
| 418 | + // @ts-ignore plug-in components | ||
| 419 | + window.$wujie?.props.methods.jump({ | ||
| 420 | + name: `Static-pluginObservability-instanceVemSessionDetail`, | ||
| 421 | + query: { | ||
| 422 | + dbid: instanceId.value, | ||
| 423 | + id, | ||
| 424 | + }, | ||
| 425 | + }) | ||
| 426 | + } else { | ||
| 427 | + // local | ||
| 428 | + window.sessionStorage.setItem('sqlId', id) | ||
| 429 | + router.push(`/vem/sessionDetail/${instanceId.value}/${id}`) | ||
| 430 | + } | ||
| 431 | +} | ||
| 432 | +const gotoTopsqlDetail = (id: string) => { | ||
| 433 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 434 | + if (curMode === 'wujie') { | ||
| 435 | + // @ts-ignore plug-in components | ||
| 436 | + window.$wujie?.props.methods.jump({ | ||
| 437 | + name: `Static-pluginObservability-instanceVemSql_detail`, | ||
| 438 | + query: { | ||
| 439 | + dbid: instanceId.value, | ||
| 440 | + id, | ||
| 441 | + }, | ||
| 442 | + }) | ||
| 443 | + } else { | ||
| 444 | + // local | ||
| 445 | + window.sessionStorage.setItem('sqlId', id) | ||
| 446 | + router.push(`/vem/sql_detail/${instanceId.value}/${id}`) | ||
| 447 | + } | ||
| 448 | +} | ||
| 449 | + | ||
| 450 | +const { data: wdrData, run: wdr, loading: wdrLoading } = useRequest(getWDRSnapshot, { manual: true }) | ||
| 451 | +watch( | ||
| 452 | + wdrData, | ||
| 453 | + (res: any) => { | ||
| 454 | + // goto wdr | ||
| 455 | + if (res && res.wdrId && res.wdrId.length > 0) { | ||
| 456 | + const { timeRange } = useMonitorStore(props.tabId) | ||
| 457 | + let param = { | ||
| 458 | + operation: 'search', | ||
| 459 | + startTime: timeRange == null ? '' : moment(timeRange[0]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 460 | + endTime: timeRange == null ? '' : moment(timeRange[1]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 461 | + } | ||
| 462 | + emit('goto', tabKeys.WDR, param) | ||
| 463 | + } else if (res && res.start && res.end) { | ||
| 464 | + let param = { | ||
| 465 | + operation: 'edit', | ||
| 466 | + startId: res.start, | ||
| 467 | + endId: res.end | ||
| 468 | + } | ||
| 469 | + emit('goto', tabKeys.WDR, param) | ||
| 470 | + } else { | ||
| 471 | + ElMessage.error(t('wdrReports.wdrErrtip')) | ||
| 472 | + } | ||
| 473 | + }, | ||
| 474 | + { deep: true } | ||
| 475 | +) | ||
| 331 | </script> | 476 | </script> |
| 332 | 477 | ||
| 333 | <style scoped lang="scss"></style> | 478 | <style scoped lang="scss"></style> |
| @@ -1,97 +1,122 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | - <my-card :title="$t('resourceMonitor.io.deviceIO')" :bodyPadding="false" skipBodyHeight> | 2 | + <my-card :title="$t('resourceMonitor.io.deviceIO')" :bodyPadding="false" skipBodyHeight> |
| 3 | - <el-table | 3 | + <el-table |
| 4 | - :data="metricsData.table" | 4 | + :data="metricsData.table" |
| 5 | - style="width: 100%" | 5 | + style="width: 100%" |
| 6 | - border | 6 | + border |
| 7 | - :header-cell-class-name=" | 7 | + :header-cell-class-name=" |
| 8 | - () => { | 8 | + () => { |
| 9 | - return 'grid-header' | 9 | + return 'grid-header' |
| 10 | - } | 10 | + } |
| 11 | - " | 11 | + " |
| 12 | - @selection-change="handleSelectionChange" | 12 | + @selection-change="handleSelectionChange" |
| 13 | - > | 13 | + > |
| 14 | - <el-table-column type="selection" width="50" align="center" /> | 14 | + <el-table-column type="selection" width="50" align="center" /> |
| 15 | - <el-table-column prop="device" label="Device" /> | 15 | + <el-table-column prop="device" label="Device" /> |
| 16 | - <el-table-column prop="IO_TPS" label="TPS" /> | 16 | + <el-table-column prop="IO_TPS" label="TPS" /> |
| 17 | - <el-table-column prop="IO_RD" label="rd(KB)/s" /> | 17 | + <el-table-column prop="IO_RD" label="rd(KB)/s" /> |
| 18 | - <el-table-column prop="IO_WT" label="wt(KB)/s" /> | 18 | + <el-table-column prop="IO_WT" label="wt(KB)/s" /> |
| 19 | - <el-table-column prop="IO_AVGRQ_SZ" label="avgrq-sz (KB)" /> | 19 | + <el-table-column prop="IO_AVGRQ_SZ" label="avgrq-sz (KB)" /> |
| 20 | - <el-table-column prop="IO_AVGQU_SZ" label="avgqu-sz" /> | 20 | + <el-table-column prop="IO_AVGQU_SZ" label="avgqu-sz" /> |
| 21 | - <el-table-column prop="IO_AWAIT" label="await(ms)" /> | 21 | + <el-table-column prop="IO_AWAIT" label="await(ms)" /> |
| 22 | - <el-table-column prop="IO_UTIL" label="%util" /> | 22 | + <el-table-column prop="IO_UTIL" label="%util" /> |
| 23 | - </el-table> | 23 | + </el-table> |
| 24 | - </my-card> | 24 | + </my-card> |
| 25 | 25 | ||
| 26 | - <div class="gap-row"></div> | 26 | + <div class="gap-row"></div> |
| 27 | 27 | ||
| 28 | - <el-row :gutter="12"> | 28 | + <el-row :gutter="12"> |
| 29 | - <el-col :span="12"> | 29 | + <el-col :span="12"> |
| 30 | - <my-card :title="'IOPS'" height="300" :bodyPadding="false"> | 30 | + <my-card :title="'IOPS'" height="300" :bodyPadding="false"> |
| 31 | - <template #headerExtend> | 31 | + <template #headerExtend> |
| 32 | - <div class="card-links"> | 32 | + <div class="card-links"> |
| 33 | - <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> | 33 | + <el-link |
| 34 | - {{ $t('app.diagnosis') }} | 34 | + v-if="isManualRangeSelected" |
| 35 | - </el-link> | 35 | + type="primary" |
| 36 | - </div> | 36 | + @click="goto(tabKeys.InstanceMonitorTOPSQL, { key: tabKeys.InstanceMonitorTOPSQLIOTime })" |
| 37 | - </template> | 37 | + > |
| 38 | - <LazyLine | 38 | + TOP CPU SQL |
| 39 | - :tips="$t('instanceIndex.activeSessionQtyTips')" | 39 | + </el-link> |
| 40 | - :rangeSelect="true" | 40 | + <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> |
| 41 | - :tabId="props.tabId" | 41 | + {{ $t('app.diagnosis') }} |
| 42 | - :formatter="toFixed" | 42 | + </el-link> |
| 43 | - :data="deviceIOPS" | 43 | + <el-link v-if="isManualRangeSelected" type="primary" @click="wdr(tabId)" v-loading="wdrLoading"> |
| 44 | - :xData="metricsData.time" | 44 | + {{$t('instanceIndex.wdrAnalysis')}} |
| 45 | - /> | 45 | + </el-link> |
| 46 | - </my-card> | 46 | + </div> |
| 47 | - </el-col> | 47 | + </template> |
| 48 | - <el-col :span="12"> | 48 | + <LazyLine |
| 49 | - <my-card :title="$t('resourceMonitor.io.rwSecond')" height="300" :bodyPadding="false"> | 49 | + :tips="$t('instanceIndex.activeSessionQtyTips')" |
| 50 | - <LazyLine | 50 | + :rangeSelect="true" |
| 51 | - :tabId="props.tabId" | 51 | + :tabId="props.tabId" |
| 52 | - :formatter="toFixed" | 52 | + :formatter="toFixed" |
| 53 | - :data="deviceRW" | 53 | + :data="deviceIOPS" |
| 54 | - :xData="metricsData.time" | 54 | + :xData="metricsData.time" |
| 55 | - :unit="'B'" | 55 | + :tool-tips-sort="'desc'" |
| 56 | - /> | 56 | + :tool-tips-exclude-zero="true" |
| 57 | - </my-card> | 57 | + /> |
| 58 | - </el-col> | 58 | + </my-card> |
| 59 | - </el-row> | 59 | + </el-col> |
| 60 | + <el-col :span="12"> | ||
| 61 | + <my-card :title="$t('resourceMonitor.io.rwSecond')" height="300" :bodyPadding="false"> | ||
| 62 | + <LazyLine | ||
| 63 | + :tabId="props.tabId" | ||
| 64 | + :formatter="toFixed" | ||
| 65 | + :data="deviceRW" | ||
| 66 | + :xData="metricsData.time" | ||
| 67 | + :unit="'B'" | ||
| 68 | + :tool-tips-sort="'desc'" | ||
| 69 | + :tool-tips-exclude-zero="true" | ||
| 70 | + /> | ||
| 71 | + </my-card> | ||
| 72 | + </el-col> | ||
| 73 | + </el-row> | ||
| 60 | 74 | ||
| 61 | - <div class="gap-row"></div> | 75 | + <div class="gap-row"></div> |
| 62 | 76 | ||
| 63 | - <el-row :gutter="12"> | 77 | + <el-row :gutter="12"> |
| 64 | - <el-col :span="8"> | 78 | + <el-col :span="8"> |
| 65 | - <my-card :title="$t('resourceMonitor.io.queueLength')" height="300" :bodyPadding="false"> | 79 | + <my-card :title="$t('resourceMonitor.io.queueLength')" height="300" :bodyPadding="false"> |
| 66 | - <LazyLine :tabId="props.tabId" :formatter="toFixed" :data="deviceIOQueue" :xData="metricsData.time" /> | 80 | + <LazyLine |
| 67 | - </my-card> | 81 | + :tabId="props.tabId" |
| 68 | - </el-col> | 82 | + :formatter="toFixed" |
| 69 | - <el-col :span="8"> | 83 | + :data="deviceIOQueue" |
| 70 | - <my-card :title="$t('resourceMonitor.io.ioUsage')" height="300" :bodyPadding="false"> | 84 | + :xData="metricsData.time" |
| 71 | - <LazyLine | 85 | + :tool-tips-sort="'desc'" |
| 72 | - :tabId="props.tabId" | 86 | + :tool-tips-exclude-zero="true" |
| 73 | - :formatter="toFixed" | 87 | + /> |
| 74 | - :data="deviceIOUsage" | 88 | + </my-card> |
| 75 | - :xData="metricsData.time" | 89 | + </el-col> |
| 76 | - :max="100" | 90 | + <el-col :span="8"> |
| 77 | - :min="0" | 91 | + <my-card :title="$t('resourceMonitor.io.ioUsage')" height="300" :bodyPadding="false"> |
| 78 | - :interval="25" | 92 | + <LazyLine |
| 79 | - :unit="'%'" | 93 | + :tabId="props.tabId" |
| 80 | - /> | 94 | + :formatter="toFixed" |
| 81 | - </my-card> | 95 | + :data="deviceIOUsage" |
| 82 | - </el-col> | 96 | + :xData="metricsData.time" |
| 83 | - <el-col :span="8"> | 97 | + :max="100" |
| 84 | - <my-card :title="$t('resourceMonitor.io.ioTime')" height="300" :bodyPadding="false"> | 98 | + :min="0" |
| 85 | - <LazyLine | 99 | + :interval="25" |
| 86 | - :tabId="props.tabId" | 100 | + :unit="'%'" |
| 87 | - :formatter="toFixed" | 101 | + :tool-tips-sort="'desc'" |
| 88 | - :data="deviceIOTime" | 102 | + :tool-tips-exclude-zero="true" |
| 89 | - :xData="metricsData.time" | 103 | + /> |
| 90 | - :unit="'ms'" | 104 | + </my-card> |
| 91 | - /> | 105 | + </el-col> |
| 92 | - </my-card> | 106 | + <el-col :span="8"> |
| 93 | - </el-col> | 107 | + <my-card :title="$t('resourceMonitor.io.ioTime')" height="300" :bodyPadding="false"> |
| 94 | - </el-row> | 108 | + <LazyLine |
| 109 | + :tabId="props.tabId" | ||
| 110 | + :formatter="toFixed" | ||
| 111 | + :data="deviceIOTime" | ||
| 112 | + :xData="metricsData.time" | ||
| 113 | + :unit="'ms'" | ||
| 114 | + :tool-tips-sort="'desc'" | ||
| 115 | + :tool-tips-exclude-zero="true" | ||
| 116 | + /> | ||
| 117 | + </my-card> | ||
| 118 | + </el-col> | ||
| 119 | + </el-row> | ||
| 95 | </template> | 120 | </template> |
| 96 | 121 | ||
| 97 | <script setup lang="ts"> | 122 | <script setup lang="ts"> |
| @@ -106,297 +131,330 @@ import { useRequest } from 'vue-request' | |||
| 106 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' | 131 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' |
| 107 | import { useI18n } from 'vue-i18n' | 132 | import { useI18n } from 'vue-i18n' |
| 108 | import { ElMessage } from 'element-plus' | 133 | import { ElMessage } from 'element-plus' |
| 134 | +import { getWDRSnapshot } from '@/api/wdr' | ||
| 135 | +import moment from 'moment' | ||
| 109 | 136 | ||
| 110 | const props = withDefaults(defineProps<{ tabId: string }>(), {}) | 137 | const props = withDefaults(defineProps<{ tabId: string }>(), {}) |
| 111 | const { t } = useI18n() | 138 | const { t } = useI18n() |
| 112 | 139 | ||
| 113 | interface LineData { | 140 | interface LineData { |
| 114 | - name: string | 141 | + name: string |
| 115 | - data: any[] | 142 | + data: any[] |
| 116 | - [other: string]: any | 143 | + [other: string]: any |
| 117 | } | 144 | } |
| 118 | interface MetricsData { | 145 | interface MetricsData { |
| 119 | - table: any[] | 146 | + table: any[] |
| 120 | - iops: LineData[] | 147 | + iops: LineData[] |
| 121 | - rw: LineData[] | 148 | + rw: LineData[] |
| 122 | - queueLenth: LineData[] | 149 | + queueLenth: LineData[] |
| 123 | - ioUse: LineData[] | 150 | + ioUse: LineData[] |
| 124 | - ioTime: LineData[] | 151 | + ioTime: LineData[] |
| 125 | - time: string[] | 152 | + time: string[] |
| 126 | } | 153 | } |
| 127 | const metricsData = ref<MetricsData>({ | 154 | const metricsData = ref<MetricsData>({ |
| 128 | - table: [], | 155 | + table: [], |
| 129 | - iops: [], | 156 | + iops: [], |
| 130 | - rw: [], | 157 | + rw: [], |
| 131 | - queueLenth: [], | 158 | + queueLenth: [], |
| 132 | - ioUse: [], | 159 | + ioUse: [], |
| 133 | - ioTime: [], | 160 | + ioTime: [], |
| 134 | - time: [], | 161 | + time: [], |
| 135 | }) | 162 | }) |
| 136 | const multipleSelection = ref<string[]>([]) | 163 | const multipleSelection = ref<string[]>([]) |
| 137 | const deviceIOPS = computed(() => { | 164 | const deviceIOPS = computed(() => { |
| 138 | - let baseData = metricsData.value.iops | 165 | + let baseData = metricsData.value.iops |
| 139 | - if (multipleSelection.value.length <= 0) { | 166 | + if (multipleSelection.value.length <= 0) { |
| 140 | - return baseData | 167 | + return baseData |
| 141 | - } else { | 168 | + } else { |
| 142 | - let result = [] | 169 | + let result = [] |
| 143 | - let selectedKeys = [] | 170 | + let selectedKeys = [] |
| 144 | - for (let index = 0; index < multipleSelection.value.length; index++) { | 171 | + for (let index = 0; index < multipleSelection.value.length; index++) { |
| 145 | - const element: any = multipleSelection.value[index] | 172 | + const element: any = multipleSelection.value[index] |
| 146 | - selectedKeys.push(element.device) | 173 | + selectedKeys.push(element.device) |
| 147 | - } | ||
| 148 | - for (let index = 0; index < baseData.length; index++) { | ||
| 149 | - const element: any = baseData[index] | ||
| 150 | - if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 151 | - result.push(element) | ||
| 152 | - } | ||
| 153 | - } | ||
| 154 | - return result | ||
| 155 | } | 174 | } |
| 175 | + for (let index = 0; index < baseData.length; index++) { | ||
| 176 | + const element: any = baseData[index] | ||
| 177 | + if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 178 | + result.push(element) | ||
| 179 | + } | ||
| 180 | + } | ||
| 181 | + return result | ||
| 182 | + } | ||
| 156 | }) | 183 | }) |
| 184 | +const emit = defineEmits(['goto']) | ||
| 185 | +const goto = (key: string, param: object) => { | ||
| 186 | + emit('goto', key, param) | ||
| 187 | +} | ||
| 157 | const deviceRW = computed(() => { | 188 | const deviceRW = computed(() => { |
| 158 | - let baseData = metricsData.value.rw | 189 | + let baseData = metricsData.value.rw |
| 159 | - if (multipleSelection.value.length <= 0) { | 190 | + if (multipleSelection.value.length <= 0) { |
| 160 | - return baseData | 191 | + return baseData |
| 161 | - } else { | 192 | + } else { |
| 162 | - let result = [] | 193 | + let result = [] |
| 163 | - let selectedKeys = [] | 194 | + let selectedKeys = [] |
| 164 | - for (let index = 0; index < multipleSelection.value.length; index++) { | 195 | + for (let index = 0; index < multipleSelection.value.length; index++) { |
| 165 | - const element: any = multipleSelection.value[index] | 196 | + const element: any = multipleSelection.value[index] |
| 166 | - selectedKeys.push(element.device) | 197 | + selectedKeys.push(element.device) |
| 167 | - } | ||
| 168 | - for (let index = 0; index < baseData.length; index++) { | ||
| 169 | - const element: any = baseData[index] | ||
| 170 | - if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 171 | - result.push(element) | ||
| 172 | - } | ||
| 173 | - } | ||
| 174 | - return result | ||
| 175 | } | 198 | } |
| 199 | + for (let index = 0; index < baseData.length; index++) { | ||
| 200 | + const element: any = baseData[index] | ||
| 201 | + if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 202 | + result.push(element) | ||
| 203 | + } | ||
| 204 | + } | ||
| 205 | + return result | ||
| 206 | + } | ||
| 176 | }) | 207 | }) |
| 177 | const deviceIOUsage = computed(() => { | 208 | const deviceIOUsage = computed(() => { |
| 178 | - let baseData = metricsData.value.ioUse | 209 | + let baseData = metricsData.value.ioUse |
| 179 | - if (multipleSelection.value.length <= 0) { | 210 | + if (multipleSelection.value.length <= 0) { |
| 180 | - return baseData | 211 | + return baseData |
| 181 | - } else { | 212 | + } else { |
| 182 | - let result = [] | 213 | + let result = [] |
| 183 | - let selectedKeys = [] | 214 | + let selectedKeys = [] |
| 184 | - for (let index = 0; index < multipleSelection.value.length; index++) { | 215 | + for (let index = 0; index < multipleSelection.value.length; index++) { |
| 185 | - const element: any = multipleSelection.value[index] | 216 | + const element: any = multipleSelection.value[index] |
| 186 | - selectedKeys.push(element.device) | 217 | + selectedKeys.push(element.device) |
| 187 | - } | ||
| 188 | - for (let index = 0; index < baseData.length; index++) { | ||
| 189 | - const element: any = baseData[index] | ||
| 190 | - if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 191 | - result.push(element) | ||
| 192 | - } | ||
| 193 | - } | ||
| 194 | - return result | ||
| 195 | } | 218 | } |
| 219 | + for (let index = 0; index < baseData.length; index++) { | ||
| 220 | + const element: any = baseData[index] | ||
| 221 | + if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 222 | + result.push(element) | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | + return result | ||
| 226 | + } | ||
| 196 | }) | 227 | }) |
| 197 | const deviceIOQueue = computed(() => { | 228 | const deviceIOQueue = computed(() => { |
| 198 | - let baseData = metricsData.value.queueLenth | 229 | + let baseData = metricsData.value.queueLenth |
| 199 | - if (multipleSelection.value.length <= 0) { | 230 | + if (multipleSelection.value.length <= 0) { |
| 200 | - return baseData | 231 | + return baseData |
| 201 | - } else { | 232 | + } else { |
| 202 | - let result = [] | 233 | + let result = [] |
| 203 | - let selectedKeys = [] | 234 | + let selectedKeys = [] |
| 204 | - for (let index = 0; index < multipleSelection.value.length; index++) { | 235 | + for (let index = 0; index < multipleSelection.value.length; index++) { |
| 205 | - const element: any = multipleSelection.value[index] | 236 | + const element: any = multipleSelection.value[index] |
| 206 | - selectedKeys.push(element.device) | 237 | + selectedKeys.push(element.device) |
| 207 | - } | ||
| 208 | - for (let index = 0; index < baseData.length; index++) { | ||
| 209 | - const element: any = baseData[index] | ||
| 210 | - if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 211 | - result.push(element) | ||
| 212 | - } | ||
| 213 | - } | ||
| 214 | - return result | ||
| 215 | } | 238 | } |
| 239 | + for (let index = 0; index < baseData.length; index++) { | ||
| 240 | + const element: any = baseData[index] | ||
| 241 | + if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 242 | + result.push(element) | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | + return result | ||
| 246 | + } | ||
| 216 | }) | 247 | }) |
| 217 | const deviceIOTime = computed(() => { | 248 | const deviceIOTime = computed(() => { |
| 218 | - let baseData = metricsData.value.ioTime | 249 | + let baseData = metricsData.value.ioTime |
| 219 | - if (multipleSelection.value.length <= 0) { | 250 | + if (multipleSelection.value.length <= 0) { |
| 220 | - return baseData | 251 | + return baseData |
| 221 | - } else { | 252 | + } else { |
| 222 | - let result = [] | 253 | + let result = [] |
| 223 | - let selectedKeys = [] | 254 | + let selectedKeys = [] |
| 224 | - for (let index = 0; index < multipleSelection.value.length; index++) { | 255 | + for (let index = 0; index < multipleSelection.value.length; index++) { |
| 225 | - const element: any = multipleSelection.value[index] | 256 | + const element: any = multipleSelection.value[index] |
| 226 | - selectedKeys.push(element.device) | 257 | + selectedKeys.push(element.device) |
| 227 | - } | ||
| 228 | - for (let index = 0; index < baseData.length; index++) { | ||
| 229 | - const element: any = baseData[index] | ||
| 230 | - if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 231 | - result.push(element) | ||
| 232 | - } | ||
| 233 | - } | ||
| 234 | - return result | ||
| 235 | } | 258 | } |
| 259 | + for (let index = 0; index < baseData.length; index++) { | ||
| 260 | + const element: any = baseData[index] | ||
| 261 | + if (selectedKeys.indexOf(element.key) >= 0) { | ||
| 262 | + result.push(element) | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + return result | ||
| 266 | + } | ||
| 236 | }) | 267 | }) |
| 237 | 268 | ||
| 238 | const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId, isManualRangeSelected, timeRange } = | 269 | const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId, isManualRangeSelected, timeRange } = |
| 239 | - storeToRefs(useMonitorStore(props.tabId)) | 270 | + storeToRefs(useMonitorStore(props.tabId)) |
| 240 | 271 | ||
| 241 | // same for every page in index | 272 | // same for every page in index |
| 242 | const timer = ref<number>() | 273 | const timer = ref<number>() |
| 243 | onMounted(() => { | 274 | onMounted(() => { |
| 244 | - load() | 275 | + load() |
| 245 | }) | 276 | }) |
| 246 | watch( | 277 | watch( |
| 247 | - updateCounter, | 278 | + updateCounter, |
| 248 | - () => { | 279 | + () => { |
| 249 | - clearInterval(timer.value) | 280 | + clearInterval(timer.value) |
| 250 | - if (tabNow.value === tabKeys.ResourceMonitorIO) { | 281 | + if (tabNow.value === tabKeys.ResourceMonitorIO) { |
| 251 | - if (updateCounter.value.source === sourceType.value.INSTANCE) load() | 282 | + if (updateCounter.value.source === sourceType.value.INSTANCE) load() |
| 252 | - if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() | 283 | + if (updateCounter.value.source === sourceType.value.MANUALREFRESH) load() |
| 253 | - if (updateCounter.value.source === sourceType.value.TIMETYPE) load() | 284 | + if (updateCounter.value.source === sourceType.value.TIMETYPE) load() |
| 254 | - if (updateCounter.value.source === sourceType.value.TIMERANGE) load() | 285 | + if (updateCounter.value.source === sourceType.value.TIMERANGE) load() |
| 255 | - if (updateCounter.value.source === sourceType.value.TABCHANGE) load() | 286 | + if (updateCounter.value.source === sourceType.value.TABCHANGE) load() |
| 256 | - const time = autoRefreshTime.value | 287 | + const time = autoRefreshTime.value |
| 257 | - timer.value = useIntervalTime( | 288 | + timer.value = useIntervalTime( |
| 258 | - () => { | 289 | + () => { |
| 259 | - load() | 290 | + load() |
| 260 | - }, | 291 | + }, |
| 261 | - computed(() => time * 1000) | 292 | + computed(() => time * 1000) |
| 262 | - ) | 293 | + ) |
| 263 | - } | 294 | + } |
| 264 | - }, | 295 | + }, |
| 265 | - { immediate: false } | 296 | + { immediate: false } |
| 266 | ) | 297 | ) |
| 267 | 298 | ||
| 268 | // load data | 299 | // load data |
| 269 | const load = (checkTab?: boolean, checkRange?: boolean) => { | 300 | const load = (checkTab?: boolean, checkRange?: boolean) => { |
| 270 | - if (!instanceId.value) return | 301 | + if (!instanceId.value) return |
| 271 | - requestData(props.tabId) | 302 | + requestData(props.tabId) |
| 272 | } | 303 | } |
| 273 | const { data: indexData, run: requestData } = useRequest(getIOMetrics, { manual: true }) | 304 | const { data: indexData, run: requestData } = useRequest(getIOMetrics, { manual: true }) |
| 274 | watch( | 305 | watch( |
| 275 | - indexData, | 306 | + indexData, |
| 276 | - () => { | 307 | + () => { |
| 277 | - // clear data | 308 | + // clear data |
| 278 | - metricsData.value.iops = [] | 309 | + metricsData.value.iops = [] |
| 279 | - metricsData.value.rw = [] | 310 | + metricsData.value.rw = [] |
| 280 | - metricsData.value.queueLenth = [] | 311 | + metricsData.value.queueLenth = [] |
| 281 | - metricsData.value.ioUse = [] | 312 | + metricsData.value.ioUse = [] |
| 282 | - metricsData.value.ioTime = [] | 313 | + metricsData.value.ioTime = [] |
| 283 | 314 | ||
| 284 | - const baseData = indexData.value | 315 | + const baseData = indexData.value |
| 285 | - if (!baseData) return | 316 | + if (!baseData) return |
| 286 | 317 | ||
| 287 | - // table | 318 | + // table |
| 288 | - for (let index = 0; index < baseData.table.length; index++) { | 319 | + for (let index = 0; index < baseData.table.length; index++) { |
| 289 | - const element = baseData.table[index] | 320 | + const element = baseData.table[index] |
| 290 | - element.IO_TPS = toFixed(element.IO_TPS) | 321 | + element.IO_TPS = toFixed(element.IO_TPS) |
| 291 | - element.IO_RD = toFixed(element.IO_RD) | 322 | + element.IO_RD = toFixed(element.IO_RD) |
| 292 | - element.IO_WT = toFixed(element.IO_WT) | 323 | + element.IO_WT = toFixed(element.IO_WT) |
| 293 | - element.IO_AVGRQ_SZ = toFixed(element.IO_AVGRQ_SZ) | 324 | + element.IO_AVGRQ_SZ = toFixed(element.IO_AVGRQ_SZ) |
| 294 | - element.IO_AVGQU_SZ = toFixed(element.IO_AVGQU_SZ) | 325 | + element.IO_AVGQU_SZ = toFixed(element.IO_AVGQU_SZ) |
| 295 | - element.IO_AWAIT = toFixed(element.IO_AWAIT) | 326 | + element.IO_AWAIT = toFixed(element.IO_AWAIT) |
| 296 | - element.IO_UTIL = toFixed(element.IO_UTIL) | 327 | + element.IO_UTIL = toFixed(element.IO_UTIL) |
| 297 | - } | 328 | + } |
| 298 | - metricsData.value.table = baseData.table | 329 | + metricsData.value.table = baseData.table |
| 299 | 330 | ||
| 300 | - // IOPS | 331 | + // IOPS |
| 301 | - for (let key in baseData.IOPS_R) { | 332 | + for (let key in baseData.IOPS_R) { |
| 302 | - let tempData: string[] = [] | 333 | + let tempData: string[] = [] |
| 303 | - baseData.IOPS_R[key].forEach((element) => { | 334 | + baseData.IOPS_R[key].forEach((element) => { |
| 304 | - tempData.push(toFixed(element)) | 335 | + tempData.push(toFixed(element)) |
| 305 | - }) | 336 | + }) |
| 306 | - metricsData.value.iops.push({ data: tempData, name: key + '(读)', key }) | 337 | + metricsData.value.iops.push({ data: tempData, name: key + '(读)', key }) |
| 307 | - } | 338 | + } |
| 308 | - for (let key in baseData.IOPS_W) { | 339 | + for (let key in baseData.IOPS_W) { |
| 309 | - let tempData: string[] = [] | 340 | + let tempData: string[] = [] |
| 310 | - baseData.IOPS_W[key].forEach((element) => { | 341 | + baseData.IOPS_W[key].forEach((element) => { |
| 311 | - tempData.push(toFixed(element)) | 342 | + tempData.push(toFixed(element)) |
| 312 | - }) | 343 | + }) |
| 313 | - metricsData.value.iops.push({ data: tempData, name: key + '(写)', key }) | 344 | + metricsData.value.iops.push({ data: tempData, name: key + '(写)', key }) |
| 314 | - } | 345 | + } |
| 315 | 346 | ||
| 316 | - // rw byte | 347 | + // rw byte |
| 317 | - for (let key in baseData.IO_DISK_READ_BYTES_PER_SECOND) { | 348 | + for (let key in baseData.IO_DISK_READ_BYTES_PER_SECOND) { |
| 318 | - let tempData: string[] = [] | 349 | + let tempData: string[] = [] |
| 319 | - baseData.IO_DISK_READ_BYTES_PER_SECOND[key].forEach((element) => { | 350 | + baseData.IO_DISK_READ_BYTES_PER_SECOND[key].forEach((element) => { |
| 320 | - tempData.push(toFixed(element)) | 351 | + tempData.push(toFixed(element)) |
| 321 | - }) | 352 | + }) |
| 322 | - metricsData.value.rw.push({ data: tempData, name: key + '(读)', key }) | 353 | + metricsData.value.rw.push({ data: tempData, name: key + '(读)', key }) |
| 323 | - } | 354 | + } |
| 324 | - for (let key in baseData.IO_DISK_WRITE_BYTES_PER_SECOND) { | 355 | + for (let key in baseData.IO_DISK_WRITE_BYTES_PER_SECOND) { |
| 325 | - let tempData: string[] = [] | 356 | + let tempData: string[] = [] |
| 326 | - baseData.IO_DISK_WRITE_BYTES_PER_SECOND[key].forEach((element) => { | 357 | + baseData.IO_DISK_WRITE_BYTES_PER_SECOND[key].forEach((element) => { |
| 327 | - tempData.push(toFixed(element)) | 358 | + tempData.push(toFixed(element)) |
| 328 | - }) | 359 | + }) |
| 329 | - metricsData.value.rw.push({ data: tempData, name: key + '(写)', key }) | 360 | + metricsData.value.rw.push({ data: tempData, name: key + '(写)', key }) |
| 330 | - } | 361 | + } |
| 331 | 362 | ||
| 332 | - // queue | 363 | + // queue |
| 333 | - for (let key in baseData.IO_QUEUE_LENGTH) { | 364 | + for (let key in baseData.IO_QUEUE_LENGTH) { |
| 334 | - let tempData: string[] = [] | 365 | + let tempData: string[] = [] |
| 335 | - baseData.IO_QUEUE_LENGTH[key].forEach((element) => { | 366 | + baseData.IO_QUEUE_LENGTH[key].forEach((element) => { |
| 336 | - tempData.push(toFixed(element)) | 367 | + tempData.push(toFixed(element)) |
| 337 | - }) | 368 | + }) |
| 338 | - metricsData.value.queueLenth.push({ data: tempData, name: key, key }) | 369 | + metricsData.value.queueLenth.push({ data: tempData, name: key, key }) |
| 339 | - } | 370 | + } |
| 340 | 371 | ||
| 341 | - // io use | 372 | + // io use |
| 342 | - for (let key in baseData.IO_UTIL) { | 373 | + for (let key in baseData.IO_UTIL) { |
| 343 | - let tempData: string[] = [] | 374 | + let tempData: string[] = [] |
| 344 | - baseData.IO_UTIL[key].forEach((element) => { | 375 | + baseData.IO_UTIL[key].forEach((element) => { |
| 345 | - tempData.push(toFixed(element)) | 376 | + tempData.push(toFixed(element)) |
| 346 | - }) | 377 | + }) |
| 347 | - metricsData.value.ioUse.push({ data: tempData, name: key, key }) | 378 | + metricsData.value.ioUse.push({ data: tempData, name: key, key }) |
| 348 | - } | 379 | + } |
| 349 | 380 | ||
| 350 | - // io time | 381 | + // io time |
| 351 | - for (let key in baseData.IO_AVG_REPONSE_TIME_READ) { | 382 | + for (let key in baseData.IO_AVG_REPONSE_TIME_READ) { |
| 352 | - let tempData: string[] = [] | 383 | + let tempData: string[] = [] |
| 353 | - baseData.IO_AVG_REPONSE_TIME_READ[key].forEach((element) => { | 384 | + baseData.IO_AVG_REPONSE_TIME_READ[key].forEach((element) => { |
| 354 | - tempData.push(toFixed(element)) | 385 | + tempData.push(toFixed(element)) |
| 355 | - }) | 386 | + }) |
| 356 | - metricsData.value.ioTime.push({ data: tempData, name: key + '(读)', key }) | 387 | + metricsData.value.ioTime.push({ data: tempData, name: key + '(读)', key }) |
| 357 | - } | 388 | + } |
| 358 | - for (let key in baseData.IO_AVG_REPONSE_TIME_WRITE) { | 389 | + for (let key in baseData.IO_AVG_REPONSE_TIME_WRITE) { |
| 359 | - let tempData: string[] = [] | 390 | + let tempData: string[] = [] |
| 360 | - baseData.IO_AVG_REPONSE_TIME_WRITE[key].forEach((element) => { | 391 | + baseData.IO_AVG_REPONSE_TIME_WRITE[key].forEach((element) => { |
| 361 | - tempData.push(toFixed(element)) | 392 | + tempData.push(toFixed(element)) |
| 362 | - }) | 393 | + }) |
| 363 | - metricsData.value.ioTime.push({ data: tempData, name: key + '(写)', key }) | 394 | + metricsData.value.ioTime.push({ data: tempData, name: key + '(写)', key }) |
| 364 | - } | 395 | + } |
| 365 | - for (let key in baseData.IO_AVG_REPONSE_TIME_RW) { | 396 | + for (let key in baseData.IO_AVG_REPONSE_TIME_RW) { |
| 366 | - let tempData: string[] = [] | 397 | + let tempData: string[] = [] |
| 367 | - baseData.IO_AVG_REPONSE_TIME_RW[key].forEach((element) => { | 398 | + baseData.IO_AVG_REPONSE_TIME_RW[key].forEach((element) => { |
| 368 | - tempData.push(toFixed(element)) | 399 | + tempData.push(toFixed(element)) |
| 369 | - }) | 400 | + }) |
| 370 | - metricsData.value.ioTime.push({ data: tempData, name: key + '(读+写)', key }) | 401 | + metricsData.value.ioTime.push({ data: tempData, name: key + '(读+写)', key }) |
| 371 | - } | 402 | + } |
| 372 | 403 | ||
| 373 | - metricsData.value.time = baseData.time | 404 | + metricsData.value.time = baseData.time |
| 374 | - }, | 405 | + }, |
| 375 | - { deep: true } | 406 | + { deep: true } |
| 376 | ) | 407 | ) |
| 377 | const handleSelectionChange = (val: any) => { | 408 | const handleSelectionChange = (val: any) => { |
| 378 | - multipleSelection.value = val | 409 | + multipleSelection.value = val |
| 379 | } | 410 | } |
| 380 | const gotoSQLDiagnosis = () => { | 411 | const gotoSQLDiagnosis = () => { |
| 381 | - hasSQLDiagnosisModule() | 412 | + hasSQLDiagnosisModule() |
| 382 | - .then(() => { | 413 | + .then(() => { |
| 383 | - const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | 414 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') |
| 384 | - if (curMode === 'wujie') { | 415 | + if (curMode === 'wujie') { |
| 385 | - // @ts-ignore plug-in components | 416 | + // @ts-ignore plug-in components |
| 386 | - window.$wujie?.props.methods.jump({ | 417 | + window.$wujie?.props.methods.jump({ |
| 387 | - name: `Static-pluginObservability-sql-diagnosisVemHistoryDiagnosis`, | 418 | + name: `Static-pluginObservability-sql-diagnosisVemHistoryDiagnosis`, |
| 388 | - query: { | 419 | + query: { |
| 389 | - instanceId: instanceId.value, | 420 | + instanceId: instanceId.value, |
| 390 | - startTime: timeRange.value[0], | 421 | + startTime: timeRange.value[0], |
| 391 | - endTime: timeRange.value[1], | 422 | + endTime: timeRange.value[1], |
| 392 | - }, | 423 | + }, |
| 393 | - }) | ||
| 394 | - } else ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 395 | - }) | ||
| 396 | - .catch(() => { | ||
| 397 | - ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 398 | }) | 424 | }) |
| 425 | + } else ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 426 | + }) | ||
| 427 | + .catch(() => { | ||
| 428 | + ElMessage.error(t('app.needSQLDiagnosis')) | ||
| 429 | + }) | ||
| 399 | } | 430 | } |
| 431 | + | ||
| 432 | +const { data: wdrData, run: wdr, loading: wdrLoading } = useRequest(getWDRSnapshot, { manual: true }) | ||
| 433 | +watch( | ||
| 434 | + wdrData, | ||
| 435 | + (res: any) => { | ||
| 436 | + // goto wdr | ||
| 437 | + if (res && res.wdrId && res.wdrId.length > 0) { | ||
| 438 | + const { timeRange } = useMonitorStore(props.tabId) | ||
| 439 | + let param = { | ||
| 440 | + operation: 'search', | ||
| 441 | + startTime: timeRange == null ? '' : moment(timeRange[0]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 442 | + endTime: timeRange == null ? '' : moment(timeRange[1]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 443 | + } | ||
| 444 | + emit('goto', tabKeys.WDR, param) | ||
| 445 | + } else if (res && res.start && res.end) { | ||
| 446 | + let param = { | ||
| 447 | + operation: 'edit', | ||
| 448 | + startId: res.start, | ||
| 449 | + endId: res.end | ||
| 450 | + } | ||
| 451 | + emit('goto', tabKeys.WDR, param) | ||
| 452 | + } else { | ||
| 453 | + ElMessage.error(t('wdrReports.wdrErrtip')) | ||
| 454 | + } | ||
| 455 | + }, | ||
| 456 | + { deep: true } | ||
| 457 | +) | ||
| 400 | </script> | 458 | </script> |
| 401 | 459 | ||
| 402 | <style scoped lang="scss"></style> | 460 | <style scoped lang="scss"></style> |
| @@ -15,11 +15,13 @@ | |||
| 15 | </el-tab-pane> | 15 | </el-tab-pane> |
| 16 | <el-tab-pane :label="$t('resourceMonitor.memoryTab')" :name="tabKeys.ResourceMonitorMemory"> | 16 | <el-tab-pane :label="$t('resourceMonitor.memoryTab')" :name="tabKeys.ResourceMonitorMemory"> |
| 17 | <Memory | 17 | <Memory |
| 18 | + @changeCluster="toChangeCluster" | ||
| 18 | :tabId="props.tabId" | 19 | :tabId="props.tabId" |
| 19 | v-if=" | 20 | v-if=" |
| 20 | tabKeyLoaded.indexOf(tabKeys.ResourceMonitorMemory) >= 0 || | 21 | tabKeyLoaded.indexOf(tabKeys.ResourceMonitorMemory) >= 0 || |
| 21 | resourceMonitorTabIndex === tabKeys.ResourceMonitorMemory | 22 | resourceMonitorTabIndex === tabKeys.ResourceMonitorMemory |
| 22 | " | 23 | " |
| 24 | + @goto="goto" | ||
| 23 | > | 25 | > |
| 24 | </Memory> | 26 | </Memory> |
| 25 | </el-tab-pane> | 27 | </el-tab-pane> |
| @@ -30,6 +32,7 @@ | |||
| 30 | tabKeyLoaded.indexOf(tabKeys.ResourceMonitorIO) >= 0 || | 32 | tabKeyLoaded.indexOf(tabKeys.ResourceMonitorIO) >= 0 || |
| 31 | resourceMonitorTabIndex === tabKeys.ResourceMonitorIO | 33 | resourceMonitorTabIndex === tabKeys.ResourceMonitorIO |
| 32 | " | 34 | " |
| 35 | + @goto="goto" | ||
| 33 | > | 36 | > |
| 34 | </IO> | 37 | </IO> |
| 35 | </el-tab-pane> | 38 | </el-tab-pane> |
| @@ -40,6 +43,7 @@ | |||
| 40 | tabKeyLoaded.indexOf(tabKeys.ResourceMonitorNetwork) >= 0 || | 43 | tabKeyLoaded.indexOf(tabKeys.ResourceMonitorNetwork) >= 0 || |
| 41 | resourceMonitorTabIndex === tabKeys.ResourceMonitorNetwork | 44 | resourceMonitorTabIndex === tabKeys.ResourceMonitorNetwork |
| 42 | " | 45 | " |
| 46 | + @goto="goto" | ||
| 43 | > | 47 | > |
| 44 | </Network> | 48 | </Network> |
| 45 | </el-tab-pane> | 49 | </el-tab-pane> |
| @@ -79,11 +83,13 @@ onMounted(() => { | |||
| 79 | watch(resourceMonitorTabIndex, (v) => { | 83 | watch(resourceMonitorTabIndex, (v) => { |
| 80 | setNowTab() | 84 | setNowTab() |
| 81 | }) | 85 | }) |
| 82 | -const emit = defineEmits(['goto']) | 86 | +const emit = defineEmits(['goto', 'changeCluster']) |
| 83 | const goto = (key: string, param: object) => { | 87 | const goto = (key: string, param: object) => { |
| 84 | - console.log('DEBUG: resourceMonitor param', param) | ||
| 85 | emit('goto', key, param) | 88 | emit('goto', key, param) |
| 86 | } | 89 | } |
| 90 | +const toChangeCluster = (publicIp: string, port: string) => { | ||
| 91 | + emit('changeCluster', publicIp, port) | ||
| 92 | +} | ||
| 87 | 93 | ||
| 88 | // same for every page in index | 94 | // same for every page in index |
| 89 | watch( | 95 | watch( |
| @@ -7,6 +7,9 @@ | |||
| 7 | <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> | 7 | <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> |
| 8 | {{ $t('app.diagnosis') }} | 8 | {{ $t('app.diagnosis') }} |
| 9 | </el-link> | 9 | </el-link> |
| 10 | + <el-link v-if="isManualRangeSelected" type="primary" @click="wdr(tabId)" v-loading="wdrLoading"> | ||
| 11 | + {{$t('instanceIndex.wdrAnalysis')}} | ||
| 12 | + </el-link> | ||
| 10 | </div> | 13 | </div> |
| 11 | </template> | 14 | </template> |
| 12 | <div style="height: 257px"> | 15 | <div style="height: 257px"> |
| @@ -38,6 +41,7 @@ | |||
| 38 | <el-table-column prop="MEM_USED" :label="$t('resourceMonitor.memory.usedMemory')" /> | 41 | <el-table-column prop="MEM_USED" :label="$t('resourceMonitor.memory.usedMemory')" /> |
| 39 | <el-table-column prop="MEM_FREE" :label="$t('resourceMonitor.memory.freeMemory')" /> | 42 | <el-table-column prop="MEM_FREE" :label="$t('resourceMonitor.memory.freeMemory')" /> |
| 40 | <el-table-column prop="MEM_CACHE" :label="$t('resourceMonitor.memory.cachedMemory')" /> | 43 | <el-table-column prop="MEM_CACHE" :label="$t('resourceMonitor.memory.cachedMemory')" /> |
| 44 | + <el-table-column prop="MEMORY_DB_USED_CURR" :label="$t('resourceMonitor.memory.dbMemory')" /> | ||
| 41 | </el-table> | 45 | </el-table> |
| 42 | </div> | 46 | </div> |
| 43 | </my-card> | 47 | </my-card> |
| @@ -92,7 +96,8 @@ | |||
| 92 | > | 96 | > |
| 93 | <div style="margin-right: 12px">{{ $t('app.refreshOn') }} {{ innerRefreshDoneTime }}</div> | 97 | <div style="margin-right: 12px">{{ $t('app.refreshOn') }} {{ innerRefreshDoneTime }}</div> |
| 94 | <div>{{ $t('app.autoRefreshFor') }}</div> | 98 | <div>{{ $t('app.autoRefreshFor') }}</div> |
| 95 | - <el-select v-model="innerRefreshTime" style="width: 60px; margin: 0 4px" @change="updateTimerInner"> | 99 | + <el-select v-model="innerRefreshTime" style="width: 100px; margin: 0 4px" @change="updateTimerInner"> |
| 100 | + <el-option :value="99999999" label="NO-AUTO" /> | ||
| 96 | <el-option :value="1" label="1s" /> | 101 | <el-option :value="1" label="1s" /> |
| 97 | <el-option :value="15" label="15s" /> | 102 | <el-option :value="15" label="15s" /> |
| 98 | <el-option :value="30" label="30s" /> | 103 | <el-option :value="30" label="30s" /> |
| @@ -118,10 +123,24 @@ | |||
| 118 | return 'grid-header' | 123 | return 'grid-header' |
| 119 | } | 124 | } |
| 120 | " | 125 | " |
| 126 | + :row-class-name="rowClassName" | ||
| 121 | > | 127 | > |
| 128 | + <el-table-column prop="%MEM" label="%MEM" width="70" /> | ||
| 122 | <el-table-column prop="%CPU" label="%CPU" width="60" /> | 129 | <el-table-column prop="%CPU" label="%CPU" width="60" /> |
| 123 | - <el-table-column prop="%MEM" label="%MEM" width="60" /> | 130 | + <el-table-column label="COMMAND" width="260" show-overflow-tooltip> |
| 124 | - <el-table-column prop="COMMAND" label="COMMAND" /> | 131 | + <template #default="scope"> |
| 132 | + <el-link | ||
| 133 | + v-if="scope.row.port && node.dbPort != scope.row.port" | ||
| 134 | + type="primary" | ||
| 135 | + class="top-sql-table-id" | ||
| 136 | + @click="changeCluster(scope.row)" | ||
| 137 | + > | ||
| 138 | + {{ scope.row.COMMAND }} | ||
| 139 | + </el-link> | ||
| 140 | + <span v-else>{{ scope.row.COMMAND }}</span> | ||
| 141 | + </template> | ||
| 142 | + </el-table-column> | ||
| 143 | + <el-table-column prop="FullCommand" label="FULL COMMAND" show-overflow-tooltip /> | ||
| 125 | <el-table-column prop="NI" label="NI" width="40" /> | 144 | <el-table-column prop="NI" label="NI" width="40" /> |
| 126 | <el-table-column prop="PID" label="PID" width="90" /> | 145 | <el-table-column prop="PID" label="PID" width="90" /> |
| 127 | <el-table-column prop="PR" label="PR" width="40" /> | 146 | <el-table-column prop="PR" label="PR" width="40" /> |
| @@ -145,9 +164,9 @@ | |||
| 145 | } | 164 | } |
| 146 | " | 165 | " |
| 147 | > | 166 | > |
| 167 | + <el-table-column prop="%MEM" label="%MEM" width="70" /> | ||
| 148 | <el-table-column prop="%CPU" label="%CPU" width="60" /> | 168 | <el-table-column prop="%CPU" label="%CPU" width="60" /> |
| 149 | - <el-table-column prop="%MEM" label="%MEM" width="60" /> | 169 | + <el-table-column prop="COMMAND" label="COMMAND" show-overflow-tooltip /> |
| 150 | - <el-table-column prop="COMMAND" label="COMMAND" /> | ||
| 151 | <el-table-column prop="NI" label="NI" width="40" /> | 170 | <el-table-column prop="NI" label="NI" width="40" /> |
| 152 | <el-table-column prop="PID" label="PID" width="90" /> | 171 | <el-table-column prop="PID" label="PID" width="90" /> |
| 153 | <el-table-column prop="PR" label="PR" width="40" /> | 172 | <el-table-column prop="PR" label="PR" width="40" /> |
| @@ -157,6 +176,20 @@ | |||
| 157 | <el-table-column prop="TIME+" label="TIME+" width="100" /> | 176 | <el-table-column prop="TIME+" label="TIME+" width="100" /> |
| 158 | <el-table-column prop="USER" label="USER" width="120" /> | 177 | <el-table-column prop="USER" label="USER" width="120" /> |
| 159 | <el-table-column prop="VIRT" label="VIRT" width="120" /> | 178 | <el-table-column prop="VIRT" label="VIRT" width="120" /> |
| 179 | + <el-table-column :label="$t('session.trans.sessionID')" width="130"> | ||
| 180 | + <template #default="scope"> | ||
| 181 | + <el-link type="primary" class="top-sql-table-id" @click="gotoSessionDetail(scope.row.sessionid)"> | ||
| 182 | + {{ scope.row.sessionid }} | ||
| 183 | + </el-link> | ||
| 184 | + </template> | ||
| 185 | + </el-table-column> | ||
| 186 | + <el-table-column label="SQLID" width="150"> | ||
| 187 | + <template #default="scope"> | ||
| 188 | + <el-link type="primary" @click="gotoTopsqlDetail(scope.row.query_id)"> | ||
| 189 | + {{ scope.row.query_id }} | ||
| 190 | + </el-link> | ||
| 191 | + </template> | ||
| 192 | + </el-table-column> | ||
| 160 | </el-table> | 193 | </el-table> |
| 161 | </el-tab-pane> | 194 | </el-tab-pane> |
| 162 | </el-tabs> | 195 | </el-tabs> |
| @@ -219,6 +252,8 @@ import { Refresh } from '@element-plus/icons-vue' | |||
| 219 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' | 252 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' |
| 220 | import moment from 'moment' | 253 | import moment from 'moment' |
| 221 | import { ElMessage } from 'element-plus' | 254 | import { ElMessage } from 'element-plus' |
| 255 | +import router from '@/router' | ||
| 256 | +import { getWDRSnapshot } from '@/api/wdr' | ||
| 222 | 257 | ||
| 223 | const { t } = useI18n() | 258 | const { t } = useI18n() |
| 224 | 259 | ||
| @@ -249,11 +284,12 @@ const metricsData = ref<MetricsData>({ | |||
| 249 | time: [], | 284 | time: [], |
| 250 | }) | 285 | }) |
| 251 | 286 | ||
| 287 | +const emit = defineEmits(['changeCluster', 'goto']) | ||
| 252 | const topMemoryProcessNowData = ref<void | TopMemoryProcessNow[]>([]) | 288 | const topMemoryProcessNowData = ref<void | TopMemoryProcessNow[]>([]) |
| 253 | const topMemoryDBThreadNowData = ref<void | TopMemoryProcessNow[]>([]) | 289 | const topMemoryDBThreadNowData = ref<void | TopMemoryProcessNow[]>([]) |
| 254 | const innerRefreshTime = ref<number>(30) | 290 | const innerRefreshTime = ref<number>(30) |
| 255 | const innerRefreshDoneTime = ref<string>('') | 291 | const innerRefreshDoneTime = ref<string>('') |
| 256 | -const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId, isManualRangeSelected, timeRange } = | 292 | +const { updateCounter, sourceType, autoRefreshTime, tabNow, instanceId, isManualRangeSelected, timeRange, node } = |
| 257 | storeToRefs(useMonitorStore(props.tabId)) | 293 | storeToRefs(useMonitorStore(props.tabId)) |
| 258 | 294 | ||
| 259 | // same for every page in index | 295 | // same for every page in index |
| @@ -293,6 +329,12 @@ const load = (checkTab?: boolean, checkRange?: boolean) => { | |||
| 293 | if (!instanceId.value) return | 329 | if (!instanceId.value) return |
| 294 | requestData(props.tabId) | 330 | requestData(props.tabId) |
| 295 | } | 331 | } |
| 332 | +const rowClassName = ({ row }: { row: any }) => { | ||
| 333 | + if (row.port) { | ||
| 334 | + return 'highlight-row' | ||
| 335 | + } | ||
| 336 | + return '' | ||
| 337 | +} | ||
| 296 | const { data: indexData, run: requestData } = useRequest(getMemoryMetrics, { manual: true }) | 338 | const { data: indexData, run: requestData } = useRequest(getMemoryMetrics, { manual: true }) |
| 297 | watch( | 339 | watch( |
| 298 | indexData, | 340 | indexData, |
| @@ -311,6 +353,7 @@ watch( | |||
| 311 | MEM_FREE: byteToMB(baseData.MEM_FREE) + 'MB', | 353 | MEM_FREE: byteToMB(baseData.MEM_FREE) + 'MB', |
| 312 | MEM_TOTAL: byteToMB(baseData.MEM_TOTAL) + 'MB', | 354 | MEM_TOTAL: byteToMB(baseData.MEM_TOTAL) + 'MB', |
| 313 | MEM_USED: byteToMB(baseData.MEM_USED) + 'MB', | 355 | MEM_USED: byteToMB(baseData.MEM_USED) + 'MB', |
| 356 | + MEMORY_DB_USED_CURR: byteToMB(baseData.MEMORY_DB_USED_CURR) + 'MB', | ||
| 314 | }, | 357 | }, |
| 315 | ] | 358 | ] |
| 316 | metricsData.value.swapInfo = [ | 359 | metricsData.value.swapInfo = [ |
| @@ -376,6 +419,16 @@ watch( | |||
| 376 | () => { | 419 | () => { |
| 377 | topMemoryProcessNowData.value = topMemoryProcessNowResult.value ? topMemoryProcessNowResult.value[0] : [] | 420 | topMemoryProcessNowData.value = topMemoryProcessNowResult.value ? topMemoryProcessNowResult.value[0] : [] |
| 378 | topMemoryDBThreadNowData.value = topMemoryProcessNowResult.value ? topMemoryProcessNowResult.value[1] : [] | 421 | topMemoryDBThreadNowData.value = topMemoryProcessNowResult.value ? topMemoryProcessNowResult.value[1] : [] |
| 422 | + topMemoryProcessNowData.value.forEach((item) => { | ||
| 423 | + if (item.port) { | ||
| 424 | + item.COMMAND += '(' + node.value.publicIp + ':' + item.port | ||
| 425 | + if (node.value.dbPort.toString() === item.port.toString()) { | ||
| 426 | + item.COMMAND += t('instanceMonitor.thisInstance') | ||
| 427 | + } | ||
| 428 | + item.COMMAND += ')' | ||
| 429 | + item.publicIp = node.value.publicIp | ||
| 430 | + } | ||
| 431 | + }) | ||
| 379 | innerRefreshDoneTime.value = moment(new Date()).format('HH:mm:ss') | 432 | innerRefreshDoneTime.value = moment(new Date()).format('HH:mm:ss') |
| 380 | }, | 433 | }, |
| 381 | { deep: true } | 434 | { deep: true } |
| @@ -391,6 +444,9 @@ const updateTimerInner = () => { | |||
| 391 | computed(() => timeInner * 1000) | 444 | computed(() => timeInner * 1000) |
| 392 | ) | 445 | ) |
| 393 | } | 446 | } |
| 447 | +const changeCluster = (row: TopMemoryProcessNow) => { | ||
| 448 | + emit('changeCluster', row.publicIp, row.port) | ||
| 449 | +} | ||
| 394 | 450 | ||
| 395 | const gotoSQLDiagnosis = () => { | 451 | const gotoSQLDiagnosis = () => { |
| 396 | hasSQLDiagnosisModule() | 452 | hasSQLDiagnosisModule() |
| @@ -412,4 +468,66 @@ const gotoSQLDiagnosis = () => { | |||
| 412 | ElMessage.error(t('app.needSQLDiagnosis')) | 468 | ElMessage.error(t('app.needSQLDiagnosis')) |
| 413 | }) | 469 | }) |
| 414 | } | 470 | } |
| 471 | + | ||
| 472 | +const gotoSessionDetail = (id: string) => { | ||
| 473 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 474 | + if (curMode === 'wujie') { | ||
| 475 | + // @ts-ignore plug-in components | ||
| 476 | + window.$wujie?.props.methods.jump({ | ||
| 477 | + name: `Static-pluginObservability-instanceVemSessionDetail`, | ||
| 478 | + query: { | ||
| 479 | + dbid: instanceId.value, | ||
| 480 | + id, | ||
| 481 | + }, | ||
| 482 | + }) | ||
| 483 | + } else { | ||
| 484 | + // local | ||
| 485 | + window.sessionStorage.setItem('sqlId', id) | ||
| 486 | + router.push(`/vem/sessionDetail/${instanceId.value}/${id}`) | ||
| 487 | + } | ||
| 488 | +} | ||
| 489 | +const gotoTopsqlDetail = (id: string) => { | ||
| 490 | + const curMode = localStorage.getItem('INSTANCE_CURRENT_MODE') | ||
| 491 | + if (curMode === 'wujie') { | ||
| 492 | + // @ts-ignore plug-in components | ||
| 493 | + window.$wujie?.props.methods.jump({ | ||
| 494 | + name: `Static-pluginObservability-instanceVemSql_detail`, | ||
| 495 | + query: { | ||
| 496 | + dbid: instanceId.value, | ||
| 497 | + id, | ||
| 498 | + }, | ||
| 499 | + }) | ||
| 500 | + } else { | ||
| 501 | + // local | ||
| 502 | + window.sessionStorage.setItem('sqlId', id) | ||
| 503 | + router.push(`/vem/sql_detail/${instanceId.value}/${id}`) | ||
| 504 | + } | ||
| 505 | +} | ||
| 506 | + | ||
| 507 | +const { data: wdrData, run: wdr, loading: wdrLoading } = useRequest(getWDRSnapshot, { manual: true }) | ||
| 508 | +watch( | ||
| 509 | + wdrData, | ||
| 510 | + (res: any) => { | ||
| 511 | + // goto wdr | ||
| 512 | + if (res && res.wdrId && res.wdrId.length > 0) { | ||
| 513 | + const { timeRange } = useMonitorStore(props.tabId) | ||
| 514 | + let param = { | ||
| 515 | + operation: 'search', | ||
| 516 | + startTime: timeRange == null ? '' : moment(timeRange[0]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 517 | + endTime: timeRange == null ? '' : moment(timeRange[1]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 518 | + } | ||
| 519 | + emit('goto', tabKeys.WDR, param) | ||
| 520 | + } else if (res && res.start && res.end) { | ||
| 521 | + let param = { | ||
| 522 | + operation: 'edit', | ||
| 523 | + startId: res.start, | ||
| 524 | + endId: res.end | ||
| 525 | + } | ||
| 526 | + emit('goto', tabKeys.WDR, param) | ||
| 527 | + } else { | ||
| 528 | + ElMessage.error(t('wdrReports.wdrErrtip')) | ||
| 529 | + } | ||
| 530 | + }, | ||
| 531 | + { deep: true } | ||
| 532 | +) | ||
| 415 | </script> | 533 | </script> |
| @@ -7,6 +7,9 @@ | |||
| 7 | <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> | 7 | <el-link v-if="isManualRangeSelected" type="primary" @click="gotoSQLDiagnosis()"> |
| 8 | {{ $t('app.diagnosis') }} | 8 | {{ $t('app.diagnosis') }} |
| 9 | </el-link> | 9 | </el-link> |
| 10 | + <el-link v-if="isManualRangeSelected" type="primary" @click="wdr(tabId)" v-loading="wdrLoading"> | ||
| 11 | + {{$t('instanceIndex.wdrAnalysis')}} | ||
| 12 | + </el-link> | ||
| 10 | </div> | 13 | </div> |
| 11 | </template> | 14 | </template> |
| 12 | <LazyLine | 15 | <LazyLine |
| @@ -17,6 +20,8 @@ | |||
| 17 | :data="metricsData.flowIn" | 20 | :data="metricsData.flowIn" |
| 18 | :xData="metricsData.time" | 21 | :xData="metricsData.time" |
| 19 | :unit="'MB'" | 22 | :unit="'MB'" |
| 23 | + :tool-tips-sort="'desc'" | ||
| 24 | + :tool-tips-exclude-zero="true" | ||
| 20 | /> | 25 | /> |
| 21 | </my-card> | 26 | </my-card> |
| 22 | </el-col> | 27 | </el-col> |
| @@ -28,12 +33,21 @@ | |||
| 28 | :data="metricsData.flowOut" | 33 | :data="metricsData.flowOut" |
| 29 | :xData="metricsData.time" | 34 | :xData="metricsData.time" |
| 30 | :unit="'MB'" | 35 | :unit="'MB'" |
| 36 | + :tool-tips-sort="'desc'" | ||
| 37 | + :tool-tips-exclude-zero="true" | ||
| 31 | /> | 38 | /> |
| 32 | </my-card> | 39 | </my-card> |
| 33 | </el-col> | 40 | </el-col> |
| 34 | <el-col :span="8"> | 41 | <el-col :span="8"> |
| 35 | <my-card :title="$t('resourceMonitor.network.lost')" height="300" :bodyPadding="false"> | 42 | <my-card :title="$t('resourceMonitor.network.lost')" height="300" :bodyPadding="false"> |
| 36 | - <LazyLine :tabId="props.tabId" :formatter="toFixed" :data="metricsData.lost" :xData="metricsData.time" /> | 43 | + <LazyLine |
| 44 | + :tabId="props.tabId" | ||
| 45 | + :formatter="toFixed" | ||
| 46 | + :data="metricsData.lost" | ||
| 47 | + :xData="metricsData.time" | ||
| 48 | + :tool-tips-sort="'desc'" | ||
| 49 | + :tool-tips-exclude-zero="true" | ||
| 50 | + /> | ||
| 37 | </my-card> | 51 | </my-card> |
| 38 | </el-col> | 52 | </el-col> |
| 39 | </el-row> | 53 | </el-row> |
| @@ -48,17 +62,33 @@ | |||
| 48 | :formatter="toFixed" | 62 | :formatter="toFixed" |
| 49 | :data="metricsData.networkSocket" | 63 | :data="metricsData.networkSocket" |
| 50 | :xData="metricsData.time" | 64 | :xData="metricsData.time" |
| 65 | + :tool-tips-sort="'desc'" | ||
| 66 | + :tool-tips-exclude-zero="true" | ||
| 51 | /> | 67 | /> |
| 52 | </my-card> | 68 | </my-card> |
| 53 | </el-col> | 69 | </el-col> |
| 54 | <el-col :span="8"> | 70 | <el-col :span="8"> |
| 55 | <my-card :title="$t('resourceMonitor.network.tcpQty')" height="300" :bodyPadding="false"> | 71 | <my-card :title="$t('resourceMonitor.network.tcpQty')" height="300" :bodyPadding="false"> |
| 56 | - <LazyLine :tabId="props.tabId" :formatter="toFixed" :data="metricsData.tcpSocket" :xData="metricsData.time" /> | 72 | + <LazyLine |
| 73 | + :tabId="props.tabId" | ||
| 74 | + :formatter="toFixed" | ||
| 75 | + :data="metricsData.tcpSocket" | ||
| 76 | + :xData="metricsData.time" | ||
| 77 | + :tool-tips-sort="'desc'" | ||
| 78 | + :tool-tips-exclude-zero="true" | ||
| 79 | + /> | ||
| 57 | </my-card> | 80 | </my-card> |
| 58 | </el-col> | 81 | </el-col> |
| 59 | <el-col :span="8"> | 82 | <el-col :span="8"> |
| 60 | <my-card :title="$t('resourceMonitor.network.UDPQty')" height="300" :bodyPadding="false"> | 83 | <my-card :title="$t('resourceMonitor.network.UDPQty')" height="300" :bodyPadding="false"> |
| 61 | - <LazyLine :tabId="props.tabId" :formatter="toFixed" :data="metricsData.udpSocket" :xData="metricsData.time" /> | 84 | + <LazyLine |
| 85 | + :tabId="props.tabId" | ||
| 86 | + :formatter="toFixed" | ||
| 87 | + :data="metricsData.udpSocket" | ||
| 88 | + :xData="metricsData.time" | ||
| 89 | + :tool-tips-sort="'desc'" | ||
| 90 | + :tool-tips-exclude-zero="true" | ||
| 91 | + /> | ||
| 62 | </my-card> | 92 | </my-card> |
| 63 | </el-col> | 93 | </el-col> |
| 64 | </el-row> | 94 | </el-row> |
| @@ -103,10 +133,14 @@ import { useRequest } from 'vue-request' | |||
| 103 | import { ElMessage } from 'element-plus' | 133 | import { ElMessage } from 'element-plus' |
| 104 | import { useI18n } from 'vue-i18n' | 134 | import { useI18n } from 'vue-i18n' |
| 105 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' | 135 | import { hasSQLDiagnosisModule } from '@/api/sqlDiagnosis' |
| 136 | +import { getWDRSnapshot } from '@/api/wdr' | ||
| 137 | +import moment from 'moment' | ||
| 106 | 138 | ||
| 107 | const props = withDefaults(defineProps<{ tabId: string }>(), {}) | 139 | const props = withDefaults(defineProps<{ tabId: string }>(), {}) |
| 108 | const { t } = useI18n() | 140 | const { t } = useI18n() |
| 109 | 141 | ||
| 142 | +const emit = defineEmits(['goto']) | ||
| 143 | + | ||
| 110 | interface LineData { | 144 | interface LineData { |
| 111 | name: string | 145 | name: string |
| 112 | data: any[] | 146 | data: any[] |
| @@ -302,6 +336,33 @@ const gotoSQLDiagnosis = () => { | |||
| 302 | ElMessage.error(t('app.needSQLDiagnosis')) | 336 | ElMessage.error(t('app.needSQLDiagnosis')) |
| 303 | }) | 337 | }) |
| 304 | } | 338 | } |
| 339 | + | ||
| 340 | +const { data: wdrData, run: wdr, loading: wdrLoading } = useRequest(getWDRSnapshot, { manual: true }) | ||
| 341 | +watch( | ||
| 342 | + wdrData, | ||
| 343 | + (res: any) => { | ||
| 344 | + // goto wdr | ||
| 345 | + if (res && res.wdrId && res.wdrId.length > 0) { | ||
| 346 | + const { timeRange } = useMonitorStore(props.tabId) | ||
| 347 | + let param = { | ||
| 348 | + operation: 'search', | ||
| 349 | + startTime: timeRange == null ? '' : moment(timeRange[0]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 350 | + endTime: timeRange == null ? '' : moment(timeRange[1]).format("YYYY-MM-DD HH:mm:ss"), | ||
| 351 | + } | ||
| 352 | + emit('goto', tabKeys.WDR, param) | ||
| 353 | + } else if (res && res.start && res.end) { | ||
| 354 | + let param = { | ||
| 355 | + operation: 'edit', | ||
| 356 | + startId: res.start, | ||
| 357 | + endId: res.end | ||
| 358 | + } | ||
| 359 | + emit('goto', tabKeys.WDR, param) | ||
| 360 | + } else { | ||
| 361 | + ElMessage.error(t('wdrReports.wdrErrtip')) | ||
| 362 | + } | ||
| 363 | + }, | ||
| 364 | + { deep: true } | ||
| 365 | +) | ||
| 305 | </script> | 366 | </script> |
| 306 | 367 | ||
| 307 | <style scoped lang="scss"></style> | 368 | <style scoped lang="scss"></style> |
| @@ -1,18 +1,24 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | <div class="top-sql" style="min-height: 500px"> | 2 | <div class="top-sql" style="min-height: 500px"> |
| 3 | <div class="tab-wrapper-container"> | 3 | <div class="tab-wrapper-container"> |
| 4 | + <div class="row" style="margin-bottom: 10px;"> | ||
| 5 | + <el-button type="primary" @click="showSnapshotManage">{{ | ||
| 6 | + $t('dashboard.wdrReports.snapshotManage') | ||
| 7 | + }}</el-button> | ||
| 8 | + <el-button type="primary" @click="showBuildWDR">{{ $t('dashboard.wdrReports.buildWDR') }}</el-button> | ||
| 9 | + </div> | ||
| 4 | <div class="search-form-multirow"> | 10 | <div class="search-form-multirow"> |
| 5 | <div class="row"> | 11 | <div class="row"> |
| 6 | <div class="filter"> | 12 | <div class="filter"> |
| 7 | <span>{{ $t('dashboard.wdrReports.reportRange') }} </span> | 13 | <span>{{ $t('dashboard.wdrReports.reportRange') }} </span> |
| 8 | - <el-select v-model="formData.reportRange" style="width: 160px; margin: 0 4px"> | 14 | + <el-select v-model="formData.reportRange" style="width: 160px; margin: 0 4px" clearable> |
| 9 | <el-option value="CLUSTER" :label="$t('dashboard.wdrReports.reportRangeSelect[0]')" /> | 15 | <el-option value="CLUSTER" :label="$t('dashboard.wdrReports.reportRangeSelect[0]')" /> |
| 10 | <el-option value="NODE" :label="$t('dashboard.wdrReports.reportRangeSelect[1]')" /> | 16 | <el-option value="NODE" :label="$t('dashboard.wdrReports.reportRangeSelect[1]')" /> |
| 11 | </el-select> | 17 | </el-select> |
| 12 | </div> | 18 | </div> |
| 13 | <div class="filter"> | 19 | <div class="filter"> |
| 14 | <span>{{ $t('dashboard.wdrReports.reportType') }} </span> | 20 | <span>{{ $t('dashboard.wdrReports.reportType') }} </span> |
| 15 | - <el-select v-model="formData.reportType" style="width: 160px; margin: 0 4px"> | 21 | + <el-select v-model="formData.reportType" style="width: 160px; margin: 0 4px" clearable> |
| 16 | <el-option value="DETAIL" :label="$t('dashboard.wdrReports.reportTypeSelect[0]')" /> | 22 | <el-option value="DETAIL" :label="$t('dashboard.wdrReports.reportTypeSelect[0]')" /> |
| 17 | <el-option value="SUMMARY" :label="$t('dashboard.wdrReports.reportTypeSelect[1]')" /> | 23 | <el-option value="SUMMARY" :label="$t('dashboard.wdrReports.reportTypeSelect[1]')" /> |
| 18 | <el-option value="ALL" :label="$t('dashboard.wdrReports.reportTypeSelect[2]')" /> | 24 | <el-option value="ALL" :label="$t('dashboard.wdrReports.reportTypeSelect[2]')" /> |
| @@ -29,16 +35,9 @@ | |||
| 29 | style="width: 300px" | 35 | style="width: 300px" |
| 30 | /> | 36 | /> |
| 31 | </div> | 37 | </div> |
| 32 | - </div> | ||
| 33 | - | ||
| 34 | - <div class="row"> | ||
| 35 | <div class="filter"> | 38 | <div class="filter"> |
| 36 | <el-button @click="handleQuery">{{ $t('app.query') }}</el-button> | 39 | <el-button @click="handleQuery">{{ $t('app.query') }}</el-button> |
| 37 | <el-button @click="handleReset">{{ $t('app.reset') }}</el-button> | 40 | <el-button @click="handleReset">{{ $t('app.reset') }}</el-button> |
| 38 | - <el-button type="primary" @click="showSnapshotManage">{{ | ||
| 39 | - $t('dashboard.wdrReports.snapshotManage') | ||
| 40 | - }}</el-button> | ||
| 41 | - <el-button type="primary" @click="showBuildWDR">{{ $t('dashboard.wdrReports.buildWDR') }}</el-button> | ||
| 42 | </div> | 41 | </div> |
| 43 | </div> | 42 | </div> |
| 44 | </div> | 43 | </div> |
| @@ -54,28 +53,49 @@ | |||
| 54 | :default-sort="{ prop: 'date', order: 'descending' }" | 53 | :default-sort="{ prop: 'date', order: 'descending' }" |
| 55 | > | 54 | > |
| 56 | <el-table-column | 55 | <el-table-column |
| 57 | - prop="scope" | 56 | + prop="reportName" |
| 57 | + :label="$t('dashboard.wdrReports.list.reportName')" | ||
| 58 | + align="center" | ||
| 59 | + min-width="40%" | ||
| 60 | + /> | ||
| 61 | + <el-table-column | ||
| 62 | + prop="scope" | ||
| 58 | :label="$t('dashboard.wdrReports.reportRange')" | 63 | :label="$t('dashboard.wdrReports.reportRange')" |
| 59 | min-width="10%" | 64 | min-width="10%" |
| 60 | align="center" | 65 | align="center" |
| 61 | - /> | 66 | + > |
| 62 | - <el-table-column | 67 | + <template #default="scope"> |
| 63 | - prop="reportAt" | 68 | + <div v-if="scope.row.scope === 'CLUSTER'"> |
| 64 | - :label="$t('dashboard.wdrReports.list.buildTime')" | 69 | + {{ $t('dashboard.wdrReports.reportRangeSelect[0]') }} |
| 65 | - min-width="20%" | 70 | + </div> |
| 66 | - align="center" | 71 | + <div v-if="scope.row.scope === 'NODE'"> |
| 67 | - /> | 72 | + {{ $t('dashboard.wdrReports.reportRangeSelect[1]') }} |
| 73 | + </div> | ||
| 74 | + </template> | ||
| 75 | + </el-table-column> | ||
| 68 | <el-table-column | 76 | <el-table-column |
| 69 | prop="reportType" | 77 | prop="reportType" |
| 70 | :label="$t('dashboard.wdrReports.reportType')" | 78 | :label="$t('dashboard.wdrReports.reportType')" |
| 71 | min-width="10%" | 79 | min-width="10%" |
| 72 | align="center" | 80 | align="center" |
| 73 | - /> | 81 | + > |
| 82 | + <template #default="scope"> | ||
| 83 | + <div v-if="scope.row.reportType === 'DETAIL'"> | ||
| 84 | + {{ $t('dashboard.wdrReports.reportTypeSelect[0]') }} | ||
| 85 | + </div> | ||
| 86 | + <div v-if="scope.row.reportType === 'SUMMARY'"> | ||
| 87 | + {{ $t('dashboard.wdrReports.reportTypeSelect[1]') }} | ||
| 88 | + </div> | ||
| 89 | + <div v-if="scope.row.reportType === 'ALL'"> | ||
| 90 | + {{ $t('dashboard.wdrReports.reportTypeSelect[2]') }} | ||
| 91 | + </div> | ||
| 92 | + </template> | ||
| 93 | + </el-table-column> | ||
| 74 | <el-table-column | 94 | <el-table-column |
| 75 | - prop="reportName" | 95 | + prop="reportAt" |
| 76 | - :label="$t('dashboard.wdrReports.list.reportName')" | 96 | + :label="$t('dashboard.wdrReports.list.buildTime')" |
| 97 | + min-width="20%" | ||
| 77 | align="center" | 98 | align="center" |
| 78 | - min-width="40%" | ||
| 79 | /> | 99 | /> |
| 80 | <el-table-column :label="$t('app.operate')" align="center" fixed="right" min-width="20%"> | 100 | <el-table-column :label="$t('app.operate')" align="center" fixed="right" min-width="20%"> |
| 81 | <template #default="scope"> | 101 | <template #default="scope"> |
| @@ -115,6 +135,8 @@ | |||
| 115 | <SnapshotManage :tabId="tabId" v-if="snapshotManageShown" @changeModal="changeModalSnapshotManage" /> | 135 | <SnapshotManage :tabId="tabId" v-if="snapshotManageShown" @changeModal="changeModalSnapshotManage" /> |
| 116 | <BuildWdr | 136 | <BuildWdr |
| 117 | :tabId="tabId" | 137 | :tabId="tabId" |
| 138 | + :startId="startId" | ||
| 139 | + :endId="endId" | ||
| 118 | v-if="buildWDRShown" | 140 | v-if="buildWDRShown" |
| 119 | @changeModal="changeModalBuildWDR" | 141 | @changeModal="changeModalBuildWDR" |
| 120 | @conveyFlag="bandleCoveyBuildWDR" | 142 | @conveyFlag="bandleCoveyBuildWDR" |
| @@ -140,6 +162,9 @@ const errorInfo = ref<string | Error>() | |||
| 140 | const props = withDefaults(defineProps<{ tabId: string }>(), {}) | 162 | const props = withDefaults(defineProps<{ tabId: string }>(), {}) |
| 141 | const { updateCounter, sourceType, tabNow } = storeToRefs(useMonitorStore(props.tabId)) | 163 | const { updateCounter, sourceType, tabNow } = storeToRefs(useMonitorStore(props.tabId)) |
| 142 | 164 | ||
| 165 | +const startId = ref<number>() | ||
| 166 | +const endId = ref<number>() | ||
| 167 | + | ||
| 143 | // same for every page in index | 168 | // same for every page in index |
| 144 | onMounted(() => { | 169 | onMounted(() => { |
| 145 | handleQuery() | 170 | handleQuery() |
| @@ -156,8 +181,8 @@ watch( | |||
| 156 | ) | 181 | ) |
| 157 | 182 | ||
| 158 | const initFormData = { | 183 | const initFormData = { |
| 159 | - reportRange: 'CLUSTER', | 184 | + reportRange: '', |
| 160 | - reportType: 'DETAIL', | 185 | + reportType: '', |
| 161 | dateValue: [ | 186 | dateValue: [ |
| 162 | moment(new Date()).format('YYYY-MM-DD') + ' 00:00:00', | 187 | moment(new Date()).format('YYYY-MM-DD') + ' 00:00:00', |
| 163 | moment(new Date()).format('YYYY-MM-DD') + ' 23:59:59', | 188 | moment(new Date()).format('YYYY-MM-DD') + ' 23:59:59', |
| @@ -185,6 +210,8 @@ const showBuildWDR = () => { | |||
| 185 | } | 210 | } |
| 186 | const changeModalBuildWDR = (val: boolean) => { | 211 | const changeModalBuildWDR = (val: boolean) => { |
| 187 | buildWDRShown.value = val | 212 | buildWDRShown.value = val |
| 213 | + startId.value = undefined | ||
| 214 | + endId.value = undefined | ||
| 188 | } | 215 | } |
| 189 | const bandleCoveyBuildWDR = (code: number) => { | 216 | const bandleCoveyBuildWDR = (code: number) => { |
| 190 | requestData() | 217 | requestData() |
| @@ -336,4 +363,21 @@ function debounce(func: any, delay: any) { | |||
| 336 | }, delay) | 363 | }, delay) |
| 337 | } | 364 | } |
| 338 | } | 365 | } |
| 366 | + | ||
| 367 | +const outsideGoto = (param: any) => { | ||
| 368 | + if (!param) { | ||
| 369 | + return; | ||
| 370 | + } | ||
| 371 | + console.log(param) | ||
| 372 | + if (param.operation === 'search') { | ||
| 373 | + formData.dateValue = [param.endTime, param.satrtTime] | ||
| 374 | + handleQuery() | ||
| 375 | + } | ||
| 376 | + if (param.operation === 'edit') { | ||
| 377 | + startId.value = param.startId | ||
| 378 | + endId.value = param.endId | ||
| 379 | + buildWDRShown.value = true | ||
| 380 | + } | ||
| 381 | +} | ||
| 382 | +defineExpose({ outsideGoto }) | ||
| 339 | </script> | 383 | </script> |
| @@ -1,71 +1,49 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | - <div class="dialog"> | 2 | + <div class="dialog"> |
| 3 | - <el-dialog | 3 | + <el-dialog width="400px" :title="$t('dashboard.wdrReports.buildWDR')" v-model="visible" :close-on-click-modal="false" |
| 4 | - width="400px" | 4 | + draggable @close="taskClose"> |
| 5 | - :title="$t('dashboard.wdrReports.buildWDR')" | 5 | + <div class="dialog-content" v-loading="generating"> |
| 6 | - v-model="visible" | 6 | + <el-form :model="formData" :rules="connectionFormRules" ref="connectionFormRef"> |
| 7 | - :close-on-click-modal="false" | 7 | + <el-form-item :label="$t('datasource.cluterTitle')" prop="hostId"> |
| 8 | - draggable | 8 | + <ClusterCascader ref="clusterComponent" width="200" instanceValueKey="hostId" @loaded="loaded" |
| 9 | - @close="taskClose" | 9 | + @getCluster="handleClusterValue" notClearable /> |
| 10 | - > | 10 | + </el-form-item> |
| 11 | - <div class="dialog-content" v-loading="generating"> | 11 | + <el-form-item :label="$t('dashboard.wdrReports.reportRange')" prop="reportRange"> |
| 12 | - <el-form :model="formData" :rules="connectionFormRules" ref="connectionFormRef"> | 12 | + <el-select v-model="formData.scope" style="width: 200px; margin: 0 4px"> |
| 13 | - <el-form-item :label="$t('datasource.cluterTitle')" prop="hostId"> | 13 | + <el-option value="CLUSTER" :label="$t('dashboard.wdrReports.reportRangeSelect[0]')" /> |
| 14 | - <ClusterCascader | 14 | + <el-option value="NODE" :label="$t('dashboard.wdrReports.reportRangeSelect[1]')" /> |
| 15 | - ref="clusterComponent" | 15 | + </el-select> |
| 16 | - width="200" | 16 | + </el-form-item> |
| 17 | - instanceValueKey="hostId" | 17 | + <el-form-item :label="$t('dashboard.wdrReports.reportType')" prop="reportType"> |
| 18 | - @loaded="loaded" | 18 | + <el-select v-model="formData.type" style="width: 200px; margin: 0 4px"> |
| 19 | - @getCluster="handleClusterValue" | 19 | + <el-option value="DETAIL" :label="$t('dashboard.wdrReports.reportTypeSelect[0]')" /> |
| 20 | - notClearable | 20 | + <el-option value="SUMMARY" :label="$t('dashboard.wdrReports.reportTypeSelect[1]')" /> |
| 21 | - /> | 21 | + <el-option value="ALL" :label="$t('dashboard.wdrReports.reportTypeSelect[2]')" /> |
| 22 | - </el-form-item> | 22 | + </el-select> |
| 23 | - <el-form-item :label="$t('dashboard.wdrReports.reportRange')" prop="reportRange"> | 23 | + </el-form-item> |
| 24 | - <el-select v-model="formData.scope" style="width: 200px; margin: 0 4px"> | 24 | + <el-form-item :label="$t('dashboard.wdrReports.buildWDRDialog.startSnapshot')" prop="startId"> |
| 25 | - <el-option value="CLUSTER" :label="$t('dashboard.wdrReports.reportRangeSelect[0]')" /> | 25 | + <el-select v-model="formData.startId" style="width: 200px; margin: 0 4px"> |
| 26 | - <el-option value="NODE" :label="$t('dashboard.wdrReports.reportRangeSelect[1]')" /> | 26 | + <el-option v-for="item in tableData" :key="item.snapshotId" :label="`${item.snapshotId}(${$t('dashboard.wdrReports.buildWDRDialog.startTime')}:${item.startTs})`" |
| 27 | - </el-select> | 27 | + :value="item.snapshotId" :disabled="parseInt(item.snapshotId) >= parseInt(formData.endId)" /> |
| 28 | - </el-form-item> | 28 | + </el-select> |
| 29 | - <el-form-item :label="$t('dashboard.wdrReports.reportType')" prop="reportType"> | 29 | + </el-form-item> |
| 30 | - <el-select v-model="formData.type" style="width: 200px; margin: 0 4px"> | 30 | + <el-form-item :label="$t('dashboard.wdrReports.buildWDRDialog.endSnapshot')" prop="endId"> |
| 31 | - <el-option value="DETAIL" :label="$t('dashboard.wdrReports.reportTypeSelect[0]')" /> | 31 | + <el-select v-model="formData.endId" style="width: 200px; margin: 0 4px"> |
| 32 | - <el-option value="SUMMARY" :label="$t('dashboard.wdrReports.reportTypeSelect[1]')" /> | 32 | + <el-option v-for="item in tableData" :key="item.snapshotId" :label="`${item.snapshotId}(${$t('dashboard.wdrReports.buildWDRDialog.endTime')}:${item.endTs})`" |
| 33 | - <el-option value="ALL" :label="$t('dashboard.wdrReports.reportTypeSelect[2]')" /> | 33 | + :value="item.snapshotId" :disabled="parseInt(item.snapshotId) <= parseInt(formData.startId)" /> |
| 34 | - </el-select> | 34 | + </el-select> |
| 35 | - </el-form-item> | 35 | + </el-form-item> |
| 36 | - <el-form-item :label="$t('dashboard.wdrReports.buildWDRDialog.startSnapshot')" prop="startId"> | 36 | + </el-form> |
| 37 | - <el-select v-model="formData.startId" style="width: 200px; margin: 0 4px"> | 37 | + </div> |
| 38 | - <el-option | ||
| 39 | - v-for="item in tableData" | ||
| 40 | - :key="item.snapshotId" | ||
| 41 | - :label="item.snapshotId" | ||
| 42 | - :value="item.snapshotId" | ||
| 43 | - :disabled="parseInt(item.snapshotId) >= parseInt(formData.endId)" | ||
| 44 | - /> | ||
| 45 | - </el-select> | ||
| 46 | - </el-form-item> | ||
| 47 | - <el-form-item :label="$t('dashboard.wdrReports.buildWDRDialog.endSnapshot')" prop="endId"> | ||
| 48 | - <el-select v-model="formData.endId" style="width: 200px; margin: 0 4px"> | ||
| 49 | - <el-option | ||
| 50 | - v-for="item in tableData" | ||
| 51 | - :key="item.snapshotId" | ||
| 52 | - :label="item.snapshotId" | ||
| 53 | - :value="item.snapshotId" | ||
| 54 | - :disabled="parseInt(item.snapshotId) <= parseInt(formData.startId)" | ||
| 55 | - /> | ||
| 56 | - </el-select> | ||
| 57 | - </el-form-item> | ||
| 58 | - </el-form> | ||
| 59 | - </div> | ||
| 60 | 38 | ||
| 61 | - <template #footer> | 39 | + <template #footer> |
| 62 | - <el-button style="padding: 5px 20px" :loading="generating" type="primary" @click="handleconfirmModel">{{ | 40 | + <el-button style="padding: 5px 20px" :loading="generating" type="primary" @click="handleconfirmModel">{{ |
| 63 | - $t('dashboard.wdrReports.buildWDRDialog.build') | 41 | + $t('dashboard.wdrReports.buildWDRDialog.build') |
| 64 | - }}</el-button> | 42 | + }}</el-button> |
| 65 | - <el-button style="padding: 5px 20px" @click="handleCancelModel">{{ $t('app.cancel') }}</el-button> | 43 | + <el-button style="padding: 5px 20px" @click="handleCancelModel">{{ $t('app.cancel') }}</el-button> |
| 66 | - </template> | 44 | + </template> |
| 67 | - </el-dialog> | 45 | + </el-dialog> |
| 68 | - </div> | 46 | + </div> |
| 69 | </template> | 47 | </template> |
| 70 | 48 | ||
| 71 | <script lang="ts" setup> | 49 | <script lang="ts" setup> |
| @@ -78,157 +56,161 @@ import { useMonitorStore } from '@/store/monitor' | |||
| 78 | const { t } = useI18n() | 56 | const { t } = useI18n() |
| 79 | 57 | ||
| 80 | const visible = ref(true) | 58 | const visible = ref(true) |
| 81 | -const props = withDefaults(defineProps<{ tabId: string }>(), {}) | 59 | +const props = withDefaults(defineProps<{ |
| 60 | + tabId: string, | ||
| 61 | + startId: number, | ||
| 62 | + endId: number | ||
| 63 | +}>(), {}) | ||
| 82 | 64 | ||
| 83 | const clusterComponent = ref<any>(null) | 65 | const clusterComponent = ref<any>(null) |
| 84 | const loaded = () => { | 66 | const loaded = () => { |
| 85 | - let instanceId = useMonitorStore(props.tabId).instanceId | 67 | + let instanceId = useMonitorStore(props.tabId).instanceId |
| 86 | - if (instanceId && clusterComponent.value != null) { | 68 | + if (instanceId && clusterComponent.value != null) { |
| 87 | - clusterComponent.value.setNodeId(instanceId) | 69 | + clusterComponent.value.setNodeId(instanceId) |
| 88 | - nextTick(() => { | 70 | + nextTick(() => { |
| 89 | - requestData() | 71 | + requestData() |
| 90 | - }) | 72 | + }) |
| 91 | - } | 73 | + } |
| 92 | } | 74 | } |
| 93 | 75 | ||
| 94 | // form data | 76 | // form data |
| 95 | const initFormData = { | 77 | const initFormData = { |
| 96 | - clusterId: '', | 78 | + clusterId: '', |
| 97 | - endId: '', | 79 | + endId: props.endId ? props.endId : '', |
| 98 | - hostId: '', | 80 | + hostId: '', |
| 99 | - scope: 'CLUSTER', | 81 | + scope: 'CLUSTER', |
| 100 | - startId: '', | 82 | + startId: props.startId ? props.startId : '', |
| 101 | - type: 'DETAIL', | 83 | + type: 'DETAIL', |
| 102 | } | 84 | } |
| 103 | const formData = reactive(cloneDeep(initFormData)) | 85 | const formData = reactive(cloneDeep(initFormData)) |
| 104 | 86 | ||
| 105 | // cluster component | 87 | // cluster component |
| 106 | const handleClusterValue = (val: any) => { | 88 | const handleClusterValue = (val: any) => { |
| 107 | - formData.clusterId = val.length ? val[0] : '' | 89 | + formData.clusterId = val.length ? val[0] : '' |
| 108 | - formData.hostId = val.length > 1 ? val[1] : '' | 90 | + formData.hostId = val.length > 1 ? val[1] : '' |
| 109 | - if (formData.hostId) requestData() | 91 | + if (formData.hostId) requestData() |
| 110 | } | 92 | } |
| 111 | 93 | ||
| 112 | // snapshotList | 94 | // snapshotList |
| 113 | const tableData = ref<Array<any>>([]) | 95 | const tableData = ref<Array<any>>([]) |
| 114 | const { data: res, run: requestData } = useRequest( | 96 | const { data: res, run: requestData } = useRequest( |
| 115 | - () => { | 97 | + () => { |
| 116 | - return restRequest | 98 | + return restRequest |
| 117 | - .get('/wdr/listSnapshot', { | 99 | + .get('/wdr/listSnapshot', { |
| 118 | - clusterId: formData.clusterId, | 100 | + clusterId: formData.clusterId, |
| 119 | - hostId: formData.hostId, | 101 | + hostId: formData.hostId, |
| 120 | - orderby: 'snapshot_id desc', | 102 | + orderby: 'snapshot_id desc', |
| 121 | - pageSize: 99999, | 103 | + pageSize: 99999, |
| 122 | - pageNum: 1, | 104 | + pageNum: 1, |
| 123 | - }) | 105 | + }) |
| 124 | - .then(function (res) { | 106 | + .then(function (res) { |
| 125 | - return res | 107 | + return res |
| 126 | - }) | 108 | + }) |
| 127 | - .catch(function (res) { | 109 | + .catch(function (res) { |
| 128 | - tableData.value = [] | 110 | + tableData.value = [] |
| 129 | - }) | 111 | + }) |
| 130 | - }, | 112 | + }, |
| 131 | - { manual: true } | 113 | + { manual: true } |
| 132 | ) | 114 | ) |
| 133 | watch(res, (res) => { | 115 | watch(res, (res) => { |
| 134 | - if (res && res.records && res.records.length) { | 116 | + if (res && res.records && res.records.length) { |
| 135 | - tableData.value = res.records | 117 | + tableData.value = res.records |
| 136 | - if (tableData.value.length > 0) { | 118 | + if (tableData.value.length > 0) { |
| 137 | - formData.startId = tableData.value[tableData.value.length - 1].snapshotId | 119 | + formData.startId = props.startId ? props.startId : tableData.value[tableData.value.length - 1].snapshotId |
| 138 | - formData.endId = tableData.value[0].snapshotId | 120 | + formData.endId = props.endId ? props.endId : tableData.value[0].snapshotId |
| 139 | - } | ||
| 140 | - } else { | ||
| 141 | - tableData.value = [] | ||
| 142 | } | 121 | } |
| 122 | + } else { | ||
| 123 | + tableData.value = [] | ||
| 124 | + } | ||
| 143 | }) | 125 | }) |
| 144 | 126 | ||
| 145 | // build | 127 | // build |
| 146 | const connectionFormRef = ref<FormInstance>() | 128 | const connectionFormRef = ref<FormInstance>() |
| 147 | async function handleconfirmModel() { | 129 | async function handleconfirmModel() { |
| 148 | - try { | 130 | + try { |
| 149 | - let result = await connectionFormRef.value?.validate() | 131 | + let result = await connectionFormRef.value?.validate() |
| 150 | - if (result) { | 132 | + if (result) { |
| 151 | - buildWDR() | 133 | + buildWDR() |
| 152 | - } | 134 | + } |
| 153 | - } catch (error) {} | 135 | + } catch (error) { } |
| 154 | } | 136 | } |
| 155 | const validateStartId = (rule: any, value: any, callback: any) => { | 137 | const validateStartId = (rule: any, value: any, callback: any) => { |
| 156 | - if (!value || !formData.endId) { | 138 | + if (!value || !formData.endId) { |
| 157 | - callback() | 139 | + callback() |
| 158 | - } else { | 140 | + } else { |
| 159 | - if (parseInt(value) >= parseInt(formData.endId)) { | 141 | + if (parseInt(value) >= parseInt(formData.endId)) { |
| 160 | - callback(new Error(t('datasource.trackFormRules[5]'))) | 142 | + callback(new Error(t('datasource.trackFormRules[5]'))) |
| 161 | - return | 143 | + return |
| 162 | - } | ||
| 163 | - callback() | ||
| 164 | } | 144 | } |
| 145 | + callback() | ||
| 146 | + } | ||
| 165 | } | 147 | } |
| 166 | const validateEndId = (rule: any, value: any, callback: any) => { | 148 | const validateEndId = (rule: any, value: any, callback: any) => { |
| 167 | - if (!value || !formData.startId) { | 149 | + if (!value || !formData.startId) { |
| 168 | - callback() | 150 | + callback() |
| 169 | - } else { | 151 | + } else { |
| 170 | - if (parseInt(value) <= parseInt(formData.startId)) { | 152 | + if (parseInt(value) <= parseInt(formData.startId)) { |
| 171 | - callback(new Error(t('datasource.trackFormRules[6]'))) | 153 | + callback(new Error(t('datasource.trackFormRules[6]'))) |
| 172 | - } | ||
| 173 | - callback() | ||
| 174 | } | 154 | } |
| 155 | + callback() | ||
| 156 | + } | ||
| 175 | } | 157 | } |
| 176 | const connectionFormRules = reactive<FormRules>({ | 158 | const connectionFormRules = reactive<FormRules>({ |
| 177 | - hostId: [{ required: true, message: t('datasource.trackFormRules[0]'), trigger: 'blur' }], | 159 | + hostId: [{ required: true, message: t('datasource.trackFormRules[0]'), trigger: 'blur' }], |
| 178 | - startId: [ | 160 | + startId: [ |
| 179 | - { required: true, message: t('datasource.trackFormRules[4]'), trigger: 'blur' }, | 161 | + { required: true, message: t('datasource.trackFormRules[4]'), trigger: 'blur' }, |
| 180 | - { validator: validateStartId, trigger: 'blur' }, | 162 | + { validator: validateStartId, trigger: 'blur' }, |
| 181 | - ], | 163 | + ], |
| 182 | - endId: [ | 164 | + endId: [ |
| 183 | - { required: true, message: t('datasource.trackFormRules[4]'), trigger: 'blur' }, | 165 | + { required: true, message: t('datasource.trackFormRules[4]'), trigger: 'blur' }, |
| 184 | - { validator: validateEndId, trigger: 'blur' }, | 166 | + { validator: validateEndId, trigger: 'blur' }, |
| 185 | - ], | 167 | + ], |
| 186 | }) | 168 | }) |
| 187 | const { | 169 | const { |
| 188 | - data: rez, | 170 | + data: rez, |
| 189 | - run: buildWDR, | 171 | + run: buildWDR, |
| 190 | - loading: generating, | 172 | + loading: generating, |
| 191 | } = useRequest( | 173 | } = useRequest( |
| 192 | - () => { | 174 | + () => { |
| 193 | - return restRequest.post('/wdr/generate', formData).then(function (res) { | 175 | + return restRequest.post('/wdr/generate', formData).then(function (res) { |
| 194 | - return res | 176 | + return res |
| 177 | + }) | ||
| 178 | + }, | ||
| 179 | + { | ||
| 180 | + manual: true, | ||
| 181 | + onSuccess: (res) => { | ||
| 182 | + if (res && res.code === 200) { | ||
| 183 | + const msg = t('dashboard.wdrReports.buildWDRDialog.buildSuccess') | ||
| 184 | + ElMessage({ | ||
| 185 | + showClose: true, | ||
| 186 | + message: msg, | ||
| 187 | + type: 'success', | ||
| 195 | }) | 188 | }) |
| 189 | + } else { | ||
| 190 | + const msg = t('dashboard.wdrReports.buildWDRDialog.buildFail') | ||
| 191 | + ElMessage({ | ||
| 192 | + showClose: true, | ||
| 193 | + message: msg, | ||
| 194 | + type: 'error', | ||
| 195 | + }) | ||
| 196 | + } | ||
| 196 | }, | 197 | }, |
| 197 | - { | 198 | + } |
| 198 | - manual: true, | ||
| 199 | - onSuccess: (res) => { | ||
| 200 | - if (res && res.code === 200) { | ||
| 201 | - const msg = t('dashboard.wdrReports.buildWDRDialog.buildSuccess') | ||
| 202 | - ElMessage({ | ||
| 203 | - showClose: true, | ||
| 204 | - message: msg, | ||
| 205 | - type: 'success', | ||
| 206 | - }) | ||
| 207 | - } else { | ||
| 208 | - const msg = t('dashboard.wdrReports.buildWDRDialog.buildFail') | ||
| 209 | - ElMessage({ | ||
| 210 | - showClose: true, | ||
| 211 | - message: msg, | ||
| 212 | - type: 'error', | ||
| 213 | - }) | ||
| 214 | - } | ||
| 215 | - }, | ||
| 216 | - } | ||
| 217 | ) | 199 | ) |
| 218 | watch(rez, (rez) => { | 200 | watch(rez, (rez) => { |
| 219 | - emit('conveyFlag') | 201 | + emit('conveyFlag') |
| 220 | - visible.value = false | 202 | + visible.value = false |
| 221 | - emit('changeModal', visible.value) | 203 | + emit('changeModal', visible.value) |
| 222 | }) | 204 | }) |
| 223 | 205 | ||
| 224 | const emit = defineEmits(['changeModal', 'conveyFlag']) | 206 | const emit = defineEmits(['changeModal', 'conveyFlag']) |
| 225 | const taskClose = () => { | 207 | const taskClose = () => { |
| 226 | - visible.value = false | 208 | + visible.value = false |
| 227 | - emit('changeModal', visible.value) | 209 | + emit('changeModal', visible.value) |
| 228 | } | 210 | } |
| 229 | const handleCancelModel = () => { | 211 | const handleCancelModel = () => { |
| 230 | - visible.value = false | 212 | + visible.value = false |
| 231 | - emit('changeModal', visible.value) | 213 | + emit('changeModal', visible.value) |
| 232 | } | 214 | } |
| 233 | </script> | 215 | </script> |
| 234 | <style lang="scss" scoped> | 216 | <style lang="scss" scoped> |
| @@ -43,6 +43,11 @@ | |||
| 43 | :label="$t('dashboard.wdrReports.snapshotManageDialog.snapshotID')" | 43 | :label="$t('dashboard.wdrReports.snapshotManageDialog.snapshotID')" |
| 44 | :align="'left'" | 44 | :align="'left'" |
| 45 | /> | 45 | /> |
| 46 | + <el-table-column | ||
| 47 | + prop="startTs" | ||
| 48 | + :label="$t('dashboard.wdrReports.snapshotManageDialog.captureTime')" | ||
| 49 | + :align="'left'" | ||
| 50 | + /> | ||
| 46 | <el-table-column | 51 | <el-table-column |
| 47 | prop="endTs" | 52 | prop="endTs" |
| 48 | :label="$t('dashboard.wdrReports.snapshotManageDialog.captureTime')" | 53 | :label="$t('dashboard.wdrReports.snapshotManageDialog.captureTime')" |
| @@ -1,69 +1,52 @@ | |||
| 1 | <template> | 1 | <template> |
| 2 | - <div class="sql-detail" v-loading="statisticalInfoLoading"> | 2 | + <div class="sql-detail" v-loading="statisticalInfoLoading"> |
| 3 | - <my-card | 3 | + <my-card |
| 4 | - :title="$t('sql.sqlText')" | 4 | + :title="$t('sql.sqlText')" |
| 5 | - :bodyPadding="false" | 5 | + :bodyPadding="false" |
| 6 | - @resize-body-height="resizeBodyHeight" | 6 | + @resize-body-height="resizeBodyHeight" |
| 7 | - collapse | 7 | + collapse |
| 8 | - resize | 8 | + resize |
| 9 | - :maxBodyHeight="`${editorMaxHeight}px`" | 9 | + :maxBodyHeight="`${editorMaxHeight}px`" |
| 10 | - > | 10 | + > |
| 11 | - <monaco-editor | 11 | + <monaco-editor :modelValue="data.sqlText" style="margin: 4px 0; border: 1px solid #ddd" :height="editorHeight" /> |
| 12 | - :modelValue="data.sqlText" | 12 | + </my-card> |
| 13 | - style="margin: 4px 0; border: 1px solid #ddd" | 13 | + <div class="sql-detail-tab"> |
| 14 | - :height="editorHeight" | 14 | + <el-tabs v-model="tab" class="tab2" @tab-change="changetTabs"> |
| 15 | - /> | 15 | + <el-tab-pane :label="$t('sql.statisticalInformation')" name="statisticalInformation"> |
| 16 | - </my-card> | 16 | + <StatisticalInformation :data="data.statisticalInfo" :loading="statisticalInfoLoading" /> |
| 17 | - <div class="sql-detail-tab"> | 17 | + </el-tab-pane> |
| 18 | - <el-tabs v-model="tab" class="tab2"> | 18 | + <el-tab-pane :label="$t('sql.implementationPlan')" name="implementationPlan"> |
| 19 | - <el-tab-pane :label="$t('sql.statisticalInformation')" name="statisticalInformation"> | 19 | + <ImplementationPlanThis v-if="tab === 'implementationPlan'" :sqlId="urlParam.sqlId" :dbid="urlParam.dbid" /> |
| 20 | - <StatisticalInformation :data="data.statisticalInfo" :loading="statisticalInfoLoading" /> | 20 | + </el-tab-pane> |
| 21 | - </el-tab-pane> | 21 | + <el-tab-pane :label="$t('sql.systemSource')" name="systemSource"> |
| 22 | - <el-tab-pane :label="$t('sql.implementationPlan')" name="implementationPlan"> | 22 | + <SystemSource v-if="tab === 'systemSource'" :dbid="urlParam.dbid" :fixedRangeTime="data.fixedRangeTime" /> |
| 23 | - <ImplementationPlanThis | 23 | + </el-tab-pane> |
| 24 | - v-if="tab === 'implementationPlan'" | 24 | + <el-tab-pane :label="$t('sql.objectInformation')" name="objectInformation"> |
| 25 | - :sqlId="urlParam.sqlId" | 25 | + <ObjectInformation v-if="tab === 'objectInformation'" :sqlId="urlParam.sqlId" :dbid="urlParam.dbid" /> |
| 26 | - :dbid="urlParam.dbid" | 26 | + </el-tab-pane> |
| 27 | - /> | 27 | + <el-tab-pane :label="$t('sql.indexSuggestions')" name="indexSuggestions"> |
| 28 | - </el-tab-pane> | 28 | + <IndexSuggestionData |
| 29 | - <el-tab-pane :label="$t('sql.systemSource')" name="systemSource"> | 29 | + v-if="tab === 'indexSuggestions'" |
| 30 | - <SystemSource v-if="tab === 'systemSource'" :fixedRangeTime="data.fixedRangeTime" /> | 30 | + :sqlId="urlParam.sqlId" |
| 31 | - </el-tab-pane> | 31 | + :dbid="urlParam.dbid" |
| 32 | - <el-tab-pane :label="$t('sql.objectInformation')" name="objectInformation"> | 32 | + :sqlText="data.sqlText" |
| 33 | - <ObjectInformation | 33 | + /> |
| 34 | - v-if="tab === 'objectInformation'" | 34 | + </el-tab-pane> |
| 35 | - :sqlId="urlParam.sqlId" | 35 | + <el-tab-pane :label="$t('sql.waitEvent')" name="waitEvent"> |
| 36 | - :dbid="urlParam.dbid" | 36 | + <WaitEvent v-if="tab === 'waitEvent'" :sqlId="urlParam.sqlId" :dbid="urlParam.dbid" :sqlText="data.sqlText" /> |
| 37 | - /> | 37 | + </el-tab-pane> |
| 38 | - </el-tab-pane> | 38 | + <el-tab-pane :label="$t('sql.sqlDiagnose')" name="diagnose"> |
| 39 | - <el-tab-pane :label="$t('sql.indexSuggestions')" name="indexSuggestions"> | 39 | + <SqlDiagnose |
| 40 | - <IndexSuggestionData | 40 | + v-if="tab === 'diagnose'" |
| 41 | - v-if="tab === 'indexSuggestions'" | 41 | + :sqlId="urlParam.sqlId" |
| 42 | - :sqlId="urlParam.sqlId" | 42 | + :dbid="urlParam.dbid" |
| 43 | - :dbid="urlParam.dbid" | 43 | + :dbName="dbName" |
| 44 | - :sqlText="data.sqlText" | 44 | + :sqlText="data.sqlText" |
| 45 | - /> | 45 | + /> |
| 46 | - </el-tab-pane> | 46 | + </el-tab-pane> |
| 47 | - <el-tab-pane :label="$t('sql.waitEvent')" name="waitEvent"> | 47 | + </el-tabs> |
| 48 | - <WaitEvent | ||
| 49 | - v-if="tab === 'waitEvent'" | ||
| 50 | - :sqlId="urlParam.sqlId" | ||
| 51 | - :dbid="urlParam.dbid" | ||
| 52 | - :sqlText="data.sqlText" | ||
| 53 | - /> | ||
| 54 | - </el-tab-pane> | ||
| 55 | - <el-tab-pane :label="$t('sql.sqlDiagnose')" name="diagnose"> | ||
| 56 | - <SqlDiagnose | ||
| 57 | - v-if="tab === 'diagnose'" | ||
| 58 | - :sqlId="urlParam.sqlId" | ||
| 59 | - :dbid="urlParam.dbid" | ||
| 60 | - :dbName="dbName" | ||
| 61 | - :sqlText="data.sqlText" | ||
| 62 | - /> | ||
| 63 | - </el-tab-pane> | ||
| 64 | - </el-tabs> | ||
| 65 | - </div> | ||
| 66 | </div> | 48 | </div> |
| 49 | + </div> | ||
| 67 | </template> | 50 | </template> |
| 68 | <script setup lang="ts"> | 51 | <script setup lang="ts"> |
| 69 | import { useRequest } from 'vue-request' | 52 | import { useRequest } from 'vue-request' |
| @@ -78,37 +61,38 @@ import ImplementationPlanThis from '@/pages/sql_detail/implementation_plan/Index | |||
| 78 | import SqlDiagnose from '@/pages/sql_detail/sql_diagnose/Index.vue' | 61 | import SqlDiagnose from '@/pages/sql_detail/sql_diagnose/Index.vue' |
| 79 | import WaitEvent from '@/pages/sql_detail/waitEvent/Index.vue' | 62 | import WaitEvent from '@/pages/sql_detail/waitEvent/Index.vue' |
| 80 | import { getDatabaseMetrics } from '@/api/prometheus' | 63 | import { getDatabaseMetrics } from '@/api/prometheus' |
| 64 | +import type { TabPanelName } from 'element-plus' | ||
| 81 | 65 | ||
| 82 | const router = useRouter() | 66 | const router = useRouter() |
| 83 | 67 | ||
| 84 | const tab = ref('statisticalInformation') | 68 | const tab = ref('statisticalInformation') |
| 85 | 69 | ||
| 86 | const urlParam = reactive<{ | 70 | const urlParam = reactive<{ |
| 87 | - dbid: string | string[] | 71 | + dbid: string | string[] |
| 88 | - sqlId: string | string[] | 72 | + sqlId: string | string[] |
| 89 | }>({ | 73 | }>({ |
| 90 | - dbid: '', | 74 | + dbid: '', |
| 91 | - sqlId: '', | 75 | + sqlId: '', |
| 92 | }) | 76 | }) |
| 93 | 77 | ||
| 94 | const data = reactive<{ | 78 | const data = reactive<{ |
| 95 | - sqlText: string | 79 | + sqlText: string |
| 96 | - statisticalInfo: Record<string, string> | 80 | + statisticalInfo: Record<string, string> |
| 97 | - fixedRangeTime: Array<string> | 81 | + fixedRangeTime: Array<string> |
| 98 | }>({ | 82 | }>({ |
| 99 | - sqlText: '', | 83 | + sqlText: '', |
| 100 | - statisticalInfo: {}, | 84 | + statisticalInfo: {}, |
| 101 | - fixedRangeTime: [], | 85 | + fixedRangeTime: [], |
| 102 | }) | 86 | }) |
| 103 | 87 | ||
| 104 | const { | 88 | const { |
| 105 | - data: statisticalInfoRes, | 89 | + data: statisticalInfoRes, |
| 106 | - run: requestStatisticalInfo, | 90 | + run: requestStatisticalInfo, |
| 107 | - loading: statisticalInfoLoading, | 91 | + loading: statisticalInfoLoading, |
| 108 | } = useRequest( | 92 | } = useRequest( |
| 109 | - (sqlId: string | string[], dbid: string | string[]) => | 93 | + (sqlId: string | string[], dbid: string | string[]) => |
| 110 | - ogRequest.get(`/observability/v1/topsql/detail?id=${dbid}&sqlId=${sqlId}`), | 94 | + ogRequest.get(`/observability/v1/topsql/detail?id=${dbid}&sqlId=${sqlId}`), |
| 111 | - { manual: true } | 95 | + { manual: true } |
| 112 | ) | 96 | ) |
| 113 | 97 | ||
| 114 | const editorHeight = ref(200) | 98 | const editorHeight = ref(200) |
| @@ -116,59 +100,62 @@ const editorMaxHeight = ref(400) | |||
| 116 | const dbName = ref('') | 100 | const dbName = ref('') |
| 117 | 101 | ||
| 118 | const resizeBodyHeight = useDebounceFn((height: number) => { | 102 | const resizeBodyHeight = useDebounceFn((height: number) => { |
| 119 | - editorHeight.value = height | 103 | + editorHeight.value = height |
| 120 | }, 100) | 104 | }, 100) |
| 121 | 105 | ||
| 122 | onMounted(() => { | 106 | onMounted(() => { |
| 123 | - const { sqlId, dbid } = router.currentRoute.value.params | 107 | + const { sqlId, dbid } = router.currentRoute.value.params |
| 124 | - if (typeof sqlId === 'string' && typeof dbid === 'string') { | 108 | + if (typeof sqlId === 'string' && typeof dbid === 'string') { |
| 125 | - urlParam.dbid = dbid | 109 | + urlParam.dbid = dbid |
| 126 | - urlParam.sqlId = sqlId | 110 | + urlParam.sqlId = sqlId |
| 127 | - } else { | 111 | + } else { |
| 128 | - // @ts-ignore | 112 | + // @ts-ignore |
| 129 | - const wujie = window.$wujie | 113 | + const wujie = window.$wujie |
| 130 | - urlParam.dbid = wujie?.props.data.dbid | 114 | + urlParam.dbid = wujie?.props.data.dbid |
| 131 | - urlParam.sqlId = wujie?.props.data.id | 115 | + urlParam.sqlId = wujie?.props.data.id |
| 132 | - } | 116 | + } |
| 133 | - console.log('sql detail urlParam:', urlParam) | 117 | + requestStatisticalInfo(urlParam.sqlId, urlParam.dbid) |
| 134 | - requestStatisticalInfo(urlParam.sqlId, urlParam.dbid) | 118 | + nextTick(() => { |
| 135 | - nextTick(() => { | 119 | + const domRect = document.querySelector('.page')?.getBoundingClientRect() as DOMRect |
| 136 | - const domRect = document.querySelector('.page')?.getBoundingClientRect() as DOMRect | 120 | + editorHeight.value = Math.floor(domRect.height / 3) |
| 137 | - editorHeight.value = Math.floor(domRect.height / 3) | 121 | + editorMaxHeight.value = editorHeight.value * 2 |
| 138 | - editorMaxHeight.value = editorHeight.value * 2 | 122 | + }) |
| 139 | - }) | ||
| 140 | }) | 123 | }) |
| 141 | 124 | ||
| 142 | watch(statisticalInfoRes, (res) => { | 125 | watch(statisticalInfoRes, (res) => { |
| 143 | - if (res != null) { | 126 | + if (res != null) { |
| 144 | - data.statisticalInfo = res | 127 | + data.statisticalInfo = res |
| 145 | - data.sqlText = res.query | 128 | + data.sqlText = res.query |
| 146 | - data.fixedRangeTime = [res.start_time, res.finish_time] | 129 | + data.fixedRangeTime = [res.start_time, res.finish_time] |
| 147 | - dbName.value = res.db_name | 130 | + dbName.value = res.db_name |
| 148 | - getDatabaseMetrics() | 131 | + getDatabaseMetrics() |
| 149 | - } | 132 | + } |
| 150 | }) | 133 | }) |
| 134 | + | ||
| 135 | +const changetTabs = (name: TabPanelName) => { | ||
| 136 | + if (name === 'statisticalInformation') requestStatisticalInfo(urlParam.sqlId, urlParam.dbid) | ||
| 137 | +} | ||
| 151 | </script> | 138 | </script> |
| 152 | 139 | ||
| 153 | <style scoped lang="scss"> | 140 | <style scoped lang="scss"> |
| 154 | .sql-detail { | 141 | .sql-detail { |
| 155 | - /* background-color: transparent; */ | 142 | + /* background-color: transparent; */ |
| 156 | - padding: 0; | 143 | + padding: 0; |
| 157 | 144 | ||
| 158 | - &-text { | 145 | + &-text { |
| 159 | - margin-top: 10px; | 146 | + margin-top: 10px; |
| 160 | - } | 147 | + } |
| 161 | - | 148 | + |
| 162 | - &-tab { | 149 | + &-tab { |
| 163 | - font-size: 14px; | 150 | + font-size: 14px; |
| 164 | - background-color: var(--el-bg-color); | 151 | + background-color: var(--el-bg-color); |
| 165 | - margin-top: 16px; | 152 | + margin-top: 16px; |
| 166 | - | 153 | + |
| 167 | - &:deep(.el-tabs__header) { | 154 | + &:deep(.el-tabs__header) { |
| 168 | - background-color: var(--el-bg-color-sub); | 155 | + background-color: var(--el-bg-color-sub); |
| 169 | - padding: 0 10px; | 156 | + padding: 0 10px; |
| 170 | - margin-bottom: 8px; | 157 | + margin-bottom: 8px; |
| 171 | - } | ||
| 172 | } | 158 | } |
| 159 | + } | ||
| 173 | } | 160 | } |
| 174 | </style> | 161 | </style> |
| @@ -1,334 +1,343 @@ | |||
| 1 | +<template> | ||
| 2 | + <div class="implementation-plan" v-if="!errorInfo"> | ||
| 3 | + <div class="i-p-filter"> | ||
| 4 | + <el-tooltip effect="light" placement="bottom-end" style="color: #fff"> | ||
| 5 | + <template #content | ||
| 6 | + ><p :style="{ color: theme === 'dark' ? '#D4D4D4' : '#868F9C' }">{{ $t('sql.mostWidthPosi') }}</p></template | ||
| 7 | + > | ||
| 8 | + <el-button size="small" @click="getMostValueRow('planWidth')">{{ $t('sql.mostWidth') }}</el-button> | ||
| 9 | + </el-tooltip> | ||
| 10 | + <el-tooltip effect="light" placement="bottom"> | ||
| 11 | + <template #content | ||
| 12 | + ><p :style="{ color: theme === 'dark' ? '#D4D4D4' : '#868F9C' }">{{ $t('sql.mostRowsPosi') }}</p></template | ||
| 13 | + > | ||
| 14 | + <el-button size="small" @click="getMostValueRow('planRows')">{{ $t('sql.mostRows') }}</el-button> | ||
| 15 | + </el-tooltip> | ||
| 16 | + <el-tooltip effect="light" placement="bottom-start"> | ||
| 17 | + <template #content | ||
| 18 | + ><p :style="{ color: theme === 'dark' ? '#D4D4D4' : '#868F9C' }">{{ $t('sql.mostCostPosi') }}</p></template | ||
| 19 | + > | ||
| 20 | + <el-button size="small" @click="getMostValueRow('singleCost')">{{ $t('sql.mostCost') }}</el-button> | ||
| 21 | + </el-tooltip> | ||
| 22 | + </div> | ||
| 23 | + <div class="i-p-table" v-loading="planDataLoading"> | ||
| 24 | + <el-table | ||
| 25 | + ref="singleTableRef" | ||
| 26 | + :data="data.planData" | ||
| 27 | + :style="{ width: '100%', marginBottom: '20px' }" | ||
| 28 | + row-key="id" | ||
| 29 | + :row-class-name="tableRowClassName" | ||
| 30 | + height="340" | ||
| 31 | + default-expand-all | ||
| 32 | + border | ||
| 33 | + > | ||
| 34 | + <el-table-column type="index" /> | ||
| 35 | + <el-table-column prop="nodeType" label="operation" /> | ||
| 36 | + <el-table-column prop="alias" label="object" width="150" /> | ||
| 37 | + <el-table-column label="cost" width="300"> | ||
| 38 | + <template #default="{ row }"> | ||
| 39 | + <div class="i-p-table-cost"> | ||
| 40 | + <div style="flex: 1; position: relative; height: 10px"> | ||
| 41 | + <my-progress | ||
| 42 | + :data="[ | ||
| 43 | + { label: $t('report.singleStepOperationCost'), value: row.singleCost, color: '#37D4D1' }, | ||
| 44 | + { label: $t('report.totalCost'), value: totalSingleCost, total: true }, | ||
| 45 | + ]" | ||
| 46 | + :style="{ | ||
| 47 | + position: 'absolute', | ||
| 48 | + zIndex: | ||
| 49 | + row.singleCost / totalSingleCost <= row.totalCost / totalCost && row.nodeType !== 'Limit' ? 1 : 0, | ||
| 50 | + }" | ||
| 51 | + width="100%" | ||
| 52 | + height="10px" | ||
| 53 | + :fixTotal="row.totalCost" | ||
| 54 | + :fixColor="['#37D4D1', '#0093FF']" | ||
| 55 | + /> | ||
| 56 | + <my-progress | ||
| 57 | + :data="[ | ||
| 58 | + { | ||
| 59 | + label: $t('report.singleStepOperationCost'), | ||
| 60 | + value: row.totalCost, | ||
| 61 | + color: '#0093FF', | ||
| 62 | + hide: row.nodeType === 'Limit', | ||
| 63 | + }, | ||
| 64 | + { label: $t('report.totalCost'), value: totalCost, total: true }, | ||
| 65 | + ]" | ||
| 66 | + style="position: absolute" | ||
| 67 | + width="100%" | ||
| 68 | + height="10px" | ||
| 69 | + :fixTotal="row.totalCost" | ||
| 70 | + :fixColor="['#37D4D1', '#0093FF']" | ||
| 71 | + /> | ||
| 72 | + </div> | ||
| 73 | + <p>{{ row.totalCost }}</p> | ||
| 74 | + </div> | ||
| 75 | + </template> | ||
| 76 | + </el-table-column> | ||
| 77 | + <el-table-column label="rows"> | ||
| 78 | + <template #default="{ row }"> | ||
| 79 | + <div class="i-p-table-cost"> | ||
| 80 | + <my-progress | ||
| 81 | + :data="[ | ||
| 82 | + { label: 'rows', value: row.planRows ?? 0, color: '#0093FF' }, | ||
| 83 | + { label: '', value: data.total.totalPlanRows, total: true }, | ||
| 84 | + ]" | ||
| 85 | + style="flex: 1" | ||
| 86 | + width="100%" | ||
| 87 | + height="10px" | ||
| 88 | + :onlyOne="true" | ||
| 89 | + /> | ||
| 90 | + <p>{{ row.planRows }}</p> | ||
| 91 | + </div> | ||
| 92 | + </template> | ||
| 93 | + </el-table-column> | ||
| 94 | + <el-table-column label="width"> | ||
| 95 | + <template #default="{ row }"> | ||
| 96 | + <div class="i-p-table-cost"> | ||
| 97 | + <my-progress | ||
| 98 | + :data="[ | ||
| 99 | + { label: 'width', value: row.planWidth ?? 0, color: '#0093FF' }, | ||
| 100 | + { label: '', value: data.total.totalPlanWidth, total: true }, | ||
| 101 | + ]" | ||
| 102 | + style="flex: 1" | ||
| 103 | + width="100%" | ||
| 104 | + height="10px" | ||
| 105 | + :onlyOne="true" | ||
| 106 | + /> | ||
| 107 | + <p>{{ row.planWidth }}</p> | ||
| 108 | + </div> | ||
| 109 | + </template> | ||
| 110 | + </el-table-column> | ||
| 111 | + <el-table-column prop="joinType" label="condition" /> | ||
| 112 | + </el-table> | ||
| 113 | + </div> | ||
| 114 | + </div> | ||
| 115 | + <my-message | ||
| 116 | + v-if="errorInfo" | ||
| 117 | + :type="isInfoTip(errorInfo) ? 'info' : 'error'" | ||
| 118 | + :tip="$t(`sql.${errorInfo}`)" | ||
| 119 | + defaultTip="" | ||
| 120 | + :key="errorInfo" | ||
| 121 | + /> | ||
| 122 | +</template> | ||
| 123 | + | ||
| 1 | <script setup lang="ts"> | 124 | <script setup lang="ts"> |
| 2 | -import { useDebounceFn } from "@vueuse/core"; | 125 | +import { useDebounceFn } from '@vueuse/core' |
| 3 | import { ElTable } from 'element-plus' | 126 | import { ElTable } from 'element-plus' |
| 4 | -import { useRequest } from "vue-request"; | 127 | +import { useRequest } from 'vue-request' |
| 5 | -import { storeToRefs } from 'pinia'; | 128 | +import { storeToRefs } from 'pinia' |
| 6 | -import ogRequest from "../../../request"; | 129 | +import ogRequest from '@/request' |
| 7 | -import { useWindowStore } from "../../../store/window"; | 130 | +import { useWindowStore } from '@/store/window' |
| 8 | 131 | ||
| 9 | const { theme } = storeToRefs(useWindowStore()) | 132 | const { theme } = storeToRefs(useWindowStore()) |
| 10 | 133 | ||
| 11 | -const props = withDefaults(defineProps<{ | 134 | +const props = withDefaults( |
| 12 | - dbid: string | string[]; | 135 | + defineProps<{ |
| 13 | - sqlId: string | string[]; | 136 | + dbid: string | string[] |
| 14 | -}>(), { | 137 | + sqlId: string | string[] |
| 138 | + }>(), | ||
| 139 | + { | ||
| 15 | dbid: '', | 140 | dbid: '', |
| 16 | sqlId: '', | 141 | sqlId: '', |
| 17 | -}) | 142 | + } |
| 143 | +) | ||
| 18 | 144 | ||
| 19 | -const errorInfo = ref<string | undefined>(); | 145 | +const errorInfo = ref<string | undefined>() |
| 20 | 146 | ||
| 21 | const data = reactive<{ | 147 | const data = reactive<{ |
| 22 | - planData: Array<any>, | 148 | + planData: Array<any> |
| 23 | - total: { | 149 | + total: { |
| 24 | - totalPlanRows: number, | 150 | + totalPlanRows: number |
| 25 | - totalPlanWidth: number | 151 | + totalPlanWidth: number |
| 26 | - } | 152 | + } |
| 27 | }>({ | 153 | }>({ |
| 28 | - planData: [], | 154 | + planData: [], |
| 29 | - total: { | 155 | + total: { |
| 30 | - totalPlanRows: 1, | 156 | + totalPlanRows: 1, |
| 31 | - totalPlanWidth: 1 | 157 | + totalPlanWidth: 1, |
| 32 | - } | 158 | + }, |
| 33 | -}); | 159 | +}) |
| 34 | 160 | ||
| 35 | const recordMaxRowData = reactive({ | 161 | const recordMaxRowData = reactive({ |
| 36 | - id: '', | 162 | + id: '', |
| 37 | - value: Number.MIN_VALUE | 163 | + value: Number.MIN_VALUE, |
| 38 | -}); | 164 | +}) |
| 39 | 165 | ||
| 40 | const maxRowData = reactive({ | 166 | const maxRowData = reactive({ |
| 41 | - id: '', | 167 | + id: '', |
| 42 | - value: Number.MIN_VALUE | 168 | + value: Number.MIN_VALUE, |
| 43 | -}); | 169 | +}) |
| 44 | 170 | ||
| 45 | -const { | 171 | +const { run: requesPlanDataRes, loading: planDataLoading } = useRequest( |
| 46 | - run: requesPlanDataRes, | 172 | + (sqlId: string | string[], dbid: string | string[]) => { |
| 47 | - loading: planDataLoading | ||
| 48 | -} = useRequest((sqlId: string | string[], dbid: string | string[]) => { | ||
| 49 | const res = new Promise((resolve, reject) => { | 173 | const res = new Promise((resolve, reject) => { |
| 50 | - const result = ogRequest.getNative(`/observability/v1/topsql/plan?id=${dbid}&sqlId=${sqlId}`); | 174 | + const result = ogRequest.getNative(`/observability/v1/topsql/plan?id=${dbid}&sqlId=${sqlId}`) |
| 51 | - result ? resolve(result) : reject(result); | 175 | + result ? resolve(result) : reject(result) |
| 52 | - }).then((r: any) => { | ||
| 53 | - const code = r?.data?.code; | ||
| 54 | - const list = r?.data?.data?.data; | ||
| 55 | - const total = r?.data?.data?.total; | ||
| 56 | - if (code === "602") { | ||
| 57 | - errorInfo.value = 'executionParamTip'; | ||
| 58 | - } else if (code === "200" && Array.isArray(list) && list.length > 0) { | ||
| 59 | - calc(list) | ||
| 60 | - totalCost.value = list[0].totalCost | ||
| 61 | - data.planData = list; | ||
| 62 | - data.total = total; | ||
| 63 | - } else if (code === 500) { | ||
| 64 | - errorInfo.value = r?.data?.msg || 'failGetExecutionPlan'; | ||
| 65 | - } | ||
| 66 | - }).catch((e) => { | ||
| 67 | - errorInfo.value = e; | ||
| 68 | }) | 176 | }) |
| 69 | - return res; | 177 | + .then((r: any) => { |
| 70 | -}, { manual: true } | 178 | + const code = r?.data?.code |
| 179 | + const list = r?.data?.data?.data | ||
| 180 | + const total = r?.data?.data?.total | ||
| 181 | + if (code === 602) { | ||
| 182 | + errorInfo.value = 'executionParamTip' | ||
| 183 | + } else if (code === 200 && Array.isArray(list) && list.length > 0) { | ||
| 184 | + calc(list) | ||
| 185 | + totalCost.value = list[0].totalCost | ||
| 186 | + data.planData = list | ||
| 187 | + data.total = total | ||
| 188 | + } else if (code === 500) { | ||
| 189 | + errorInfo.value = r?.data?.msg || 'failGetExecutionPlan' | ||
| 190 | + } | ||
| 191 | + }) | ||
| 192 | + .catch((e) => { | ||
| 193 | + errorInfo.value = e | ||
| 194 | + }) | ||
| 195 | + return res | ||
| 196 | + }, | ||
| 197 | + { manual: true } | ||
| 71 | ) | 198 | ) |
| 72 | 199 | ||
| 73 | onMounted(() => { | 200 | onMounted(() => { |
| 74 | - requesPlanDataRes(props.sqlId, props.dbid); | 201 | + requesPlanDataRes(props.sqlId, props.dbid) |
| 75 | -}); | 202 | +}) |
| 76 | -const totalSingleCost = ref(0); | 203 | +const totalSingleCost = ref(0) |
| 77 | -const totalCost = ref(0); | 204 | +const totalCost = ref(0) |
| 78 | const calc = (nodes: any[]) => { | 205 | const calc = (nodes: any[]) => { |
| 79 | - nodes.forEach(d => { | 206 | + nodes.forEach((d) => { |
| 80 | - if (d.children && d.children.length) { | 207 | + if (d.children && d.children.length) { |
| 81 | - if (d.nodeType !== 'Limit') { | 208 | + if (d.nodeType !== 'Limit') { |
| 82 | - let c = d.totalCost | 209 | + let c = d.totalCost |
| 83 | - d.children.forEach((child: any) => { | 210 | + d.children.forEach((child: any) => { |
| 84 | - c = Number.parseFloat((c - child.totalCost).toFixed(2)) | 211 | + c = Number.parseFloat((c - child.totalCost).toFixed(2)) |
| 85 | - }) | 212 | + }) |
| 86 | - d.singleCost = c | 213 | + d.singleCost = c |
| 87 | - } else { | 214 | + } else { |
| 88 | - d.singleCost = 0 | 215 | + d.singleCost = 0 |
| 89 | - } | 216 | + } |
| 90 | - calc(d.children) | 217 | + calc(d.children) |
| 91 | - } else { | 218 | + } else { |
| 92 | - d.singleCost = d.totalCost | 219 | + d.singleCost = d.totalCost |
| 93 | - } | 220 | + } |
| 94 | - totalSingleCost.value += d.singleCost | 221 | + totalSingleCost.value += d.singleCost |
| 95 | - }) | 222 | + }) |
| 96 | } | 223 | } |
| 97 | watch(recordMaxRowData, () => { | 224 | watch(recordMaxRowData, () => { |
| 98 | - if (recordMaxRowData.id !== '') { | 225 | + if (recordMaxRowData.id !== '') { |
| 99 | - maxRowData.value = recordMaxRowData.value; | 226 | + maxRowData.value = recordMaxRowData.value |
| 100 | - maxRowData.id = recordMaxRowData.id; | 227 | + maxRowData.id = recordMaxRowData.id |
| 101 | - } | 228 | + } |
| 102 | -}); | 229 | +}) |
| 103 | 230 | ||
| 104 | const getMostValueRow = (type: string) => { | 231 | const getMostValueRow = (type: string) => { |
| 105 | - maxRowData.value = Number.MIN_VALUE; | 232 | + maxRowData.value = Number.MIN_VALUE |
| 106 | - maxRowData.id = ''; | 233 | + maxRowData.id = '' |
| 107 | - recordMaxRowData.value = Number.MIN_VALUE; | 234 | + recordMaxRowData.value = Number.MIN_VALUE |
| 108 | - recordMaxRowData.id = ''; | 235 | + recordMaxRowData.id = '' |
| 109 | - TraversalTree(data.planData, type); | 236 | + TraversalTree(data.planData, type) |
| 110 | } | 237 | } |
| 111 | 238 | ||
| 112 | const TraversalTree = useDebounceFn((treeData: Array<any>, type: string) => { | 239 | const TraversalTree = useDebounceFn((treeData: Array<any>, type: string) => { |
| 113 | - treeData.forEach(item => { | 240 | + treeData.forEach((item) => { |
| 114 | - if (item[type] > recordMaxRowData.value) { | 241 | + if (item[type] > recordMaxRowData.value) { |
| 115 | - recordMaxRowData.value = item[type]; | 242 | + recordMaxRowData.value = item[type] |
| 116 | - recordMaxRowData.id = item.id; | 243 | + recordMaxRowData.id = item.id |
| 117 | - } | 244 | + } |
| 118 | - if (Array.isArray(item.children) && item.children.length > 0) { | 245 | + if (Array.isArray(item.children) && item.children.length > 0) { |
| 119 | - TraversalTree(item.children, type) | 246 | + TraversalTree(item.children, type) |
| 120 | - } | 247 | + } |
| 121 | - }); | 248 | + }) |
| 122 | }, 0) | 249 | }, 0) |
| 123 | 250 | ||
| 124 | const isInfoTip = (value: string | undefined) => { | 251 | const isInfoTip = (value: string | undefined) => { |
| 125 | - return value === 'failGetExecutionPlan' || value === 'failResolveExecutionPlan' | 252 | + return value === 'failGetExecutionPlan' || value === 'failResolveExecutionPlan' |
| 126 | } | 253 | } |
| 127 | 254 | ||
| 128 | let timer: any | 255 | let timer: any |
| 129 | const tableRowClassName = ({ row }: { row: { id: string } }) => { | 256 | const tableRowClassName = ({ row }: { row: { id: string } }) => { |
| 130 | - if (row.id === maxRowData.id) { | 257 | + if (row.id === maxRowData.id) { |
| 131 | - let observer: IntersectionObserver; | 258 | + let observer: IntersectionObserver |
| 132 | - let el: HTMLElement; | 259 | + let el: HTMLElement |
| 133 | - let top: number = 0; | 260 | + let top: number = 0 |
| 134 | - // clear high light | 261 | + // clear high light |
| 135 | - if (timer) { | 262 | + if (timer) { |
| 136 | - clearTimeout(timer) | 263 | + clearTimeout(timer) |
| 137 | - } | ||
| 138 | - timer = setTimeout(() => { | ||
| 139 | - observer.unobserve(el) | ||
| 140 | - maxRowData.value = Number.MIN_VALUE; | ||
| 141 | - maxRowData.id = ''; | ||
| 142 | - recordMaxRowData.value = Number.MIN_VALUE; | ||
| 143 | - recordMaxRowData.id = ''; | ||
| 144 | - if (timer) { | ||
| 145 | - clearTimeout(timer) | ||
| 146 | - } | ||
| 147 | - }, 3000); | ||
| 148 | - | ||
| 149 | - nextTick(() => { | ||
| 150 | - el = document.querySelector('.warning-row') as HTMLElement | ||
| 151 | - if (el) { | ||
| 152 | - observer = new IntersectionObserver((entries) => { | ||
| 153 | - if (!entries[0].isIntersecting) { | ||
| 154 | - document.querySelector('.i-p-table .el-scrollbar__wrap')?.scrollTo(0, top) | ||
| 155 | - observer.unobserve(el) | ||
| 156 | - } | ||
| 157 | - }, { | ||
| 158 | - threshold: 1, | ||
| 159 | - root: document.querySelector('.i-p-table .el-scrollbar__wrap') | ||
| 160 | - }) | ||
| 161 | - observer.observe(el) | ||
| 162 | - top = el.offsetTop | ||
| 163 | - let current = el.offsetParent as HTMLElement | null | ||
| 164 | - while (current !== null && !current.classList.contains('el-scrollbar')) { | ||
| 165 | - top += current.offsetTop | ||
| 166 | - current = current.offsetParent as HTMLElement | null | ||
| 167 | - } | ||
| 168 | - } | ||
| 169 | - }) | ||
| 170 | - return 'warning-row' | ||
| 171 | } | 264 | } |
| 172 | - return '' | 265 | + timer = setTimeout(() => { |
| 173 | -} | 266 | + observer.unobserve(el) |
| 267 | + maxRowData.value = Number.MIN_VALUE | ||
| 268 | + maxRowData.id = '' | ||
| 269 | + recordMaxRowData.value = Number.MIN_VALUE | ||
| 270 | + recordMaxRowData.id = '' | ||
| 271 | + if (timer) { | ||
| 272 | + clearTimeout(timer) | ||
| 273 | + } | ||
| 274 | + }, 3000) | ||
| 174 | 275 | ||
| 276 | + nextTick(() => { | ||
| 277 | + el = document.querySelector('.warning-row') as HTMLElement | ||
| 278 | + if (el) { | ||
| 279 | + observer = new IntersectionObserver( | ||
| 280 | + (entries) => { | ||
| 281 | + if (!entries[0].isIntersecting) { | ||
| 282 | + document.querySelector('.i-p-table .el-scrollbar__wrap')?.scrollTo(0, top) | ||
| 283 | + observer.unobserve(el) | ||
| 284 | + } | ||
| 285 | + }, | ||
| 286 | + { | ||
| 287 | + threshold: 1, | ||
| 288 | + root: document.querySelector('.i-p-table .el-scrollbar__wrap'), | ||
| 289 | + } | ||
| 290 | + ) | ||
| 291 | + observer.observe(el) | ||
| 292 | + top = el.offsetTop | ||
| 293 | + let current = el.offsetParent as HTMLElement | null | ||
| 294 | + while (current !== null && !current.classList.contains('el-scrollbar')) { | ||
| 295 | + top += current.offsetTop | ||
| 296 | + current = current.offsetParent as HTMLElement | null | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + }) | ||
| 300 | + return 'warning-row' | ||
| 301 | + } | ||
| 302 | + return '' | ||
| 303 | +} | ||
| 175 | </script> | 304 | </script> |
| 176 | 305 | ||
| 177 | -<template> | ||
| 178 | - <div class="implementation-plan" v-if="!errorInfo"> | ||
| 179 | - <div class="i-p-filter"> | ||
| 180 | - <el-tooltip | ||
| 181 | - effect="light" | ||
| 182 | - placement="bottom-end" | ||
| 183 | - style="color: #fff" | ||
| 184 | - > | ||
| 185 | - <template #content><p :style="{color: theme === 'dark' ? '#D4D4D4' : '#868F9C'}">{{ $t('sql.mostWidthPosi') }}</p></template> | ||
| 186 | - <el-button size="small" @click="getMostValueRow('planWidth')">{{ $t('sql.mostWidth') }}</el-button> | ||
| 187 | - </el-tooltip> | ||
| 188 | - <el-tooltip | ||
| 189 | - effect="light" | ||
| 190 | - placement="bottom" | ||
| 191 | - > | ||
| 192 | - <template #content><p :style="{color: theme === 'dark' ? '#D4D4D4' : '#868F9C'}">{{ $t('sql.mostRowsPosi') }}</p></template> | ||
| 193 | - <el-button size="small" @click="getMostValueRow('planRows')">{{ $t('sql.mostRows') }}</el-button> | ||
| 194 | - </el-tooltip> | ||
| 195 | - <el-tooltip | ||
| 196 | - effect="light" | ||
| 197 | - placement="bottom-start" | ||
| 198 | - > | ||
| 199 | - <template #content><p :style="{color: theme === 'dark' ? '#D4D4D4' : '#868F9C'}">{{ $t('sql.mostCostPosi') }}</p></template> | ||
| 200 | - <el-button size="small" @click="getMostValueRow('singleCost')">{{ $t('sql.mostCost') }}</el-button> | ||
| 201 | - </el-tooltip> | ||
| 202 | - </div> | ||
| 203 | - <div class="i-p-table" v-loading="planDataLoading"> | ||
| 204 | - <el-table | ||
| 205 | - ref="singleTableRef" | ||
| 206 | - :data="data.planData" | ||
| 207 | - :style="{ width: '100%', marginBottom: '20px' }" | ||
| 208 | - row-key="id" | ||
| 209 | - :row-class-name="tableRowClassName" | ||
| 210 | - height="340" | ||
| 211 | - default-expand-all | ||
| 212 | - border | ||
| 213 | - > | ||
| 214 | - <el-table-column type="index" /> | ||
| 215 | - <el-table-column prop="nodeType" label="operation" /> | ||
| 216 | - <el-table-column prop="alias" label="object" width="150" /> | ||
| 217 | - <el-table-column label="cost" width="300"> | ||
| 218 | - <template #default="{row}"> | ||
| 219 | - <div class="i-p-table-cost"> | ||
| 220 | - <div style="flex: 1;position: relative;height: 10px;"> | ||
| 221 | - <my-progress :data="[ | ||
| 222 | - { label: $t('report.singleStepOperationCost'), value: row.singleCost, color: '#37D4D1' }, | ||
| 223 | - { label: $t('report.totalCost'), value: totalSingleCost, total: true } | ||
| 224 | - ]" | ||
| 225 | - :style="{position: 'absolute', zIndex: ((row.singleCost / totalSingleCost) <= (row.totalCost / totalCost)) && row.nodeType !== 'Limit' ? 1 : 0}" | ||
| 226 | - width="100%" | ||
| 227 | - height="10px" | ||
| 228 | - :fixTotal="row.totalCost" | ||
| 229 | - :fixColor="['#37D4D1', '#0093FF']" | ||
| 230 | - /> | ||
| 231 | - <my-progress :data="[ | ||
| 232 | - { label: $t('report.singleStepOperationCost'), value: row.totalCost, color: '#0093FF', hide: row.nodeType === 'Limit' }, | ||
| 233 | - { label: $t('report.totalCost'), value: totalCost, total: true } | ||
| 234 | - ]" | ||
| 235 | - style="position: absolute;" | ||
| 236 | - width="100%" | ||
| 237 | - height="10px" | ||
| 238 | - :fixTotal="row.totalCost" | ||
| 239 | - :fixColor="['#37D4D1', '#0093FF']" | ||
| 240 | - /> | ||
| 241 | - </div> | ||
| 242 | - <p>{{ row.totalCost }}</p> | ||
| 243 | - </div> | ||
| 244 | - </template> | ||
| 245 | - </el-table-column> | ||
| 246 | - <el-table-column label="rows"> | ||
| 247 | - <template #default="{row}"> | ||
| 248 | - <div class="i-p-table-cost"> | ||
| 249 | - <my-progress | ||
| 250 | - :data="[ | ||
| 251 | - { label: 'rows', value: row.planRows ?? 0, color: '#0093FF' }, | ||
| 252 | - { label: '', value: data.total.totalPlanRows, total: true } | ||
| 253 | - ]" | ||
| 254 | - style="flex: 1;" | ||
| 255 | - width="100%" | ||
| 256 | - height="10px" | ||
| 257 | - :onlyOne="true" | ||
| 258 | - /> | ||
| 259 | - <p>{{ row.planRows }}</p> | ||
| 260 | - </div> | ||
| 261 | - </template> | ||
| 262 | - </el-table-column> | ||
| 263 | - <el-table-column label="width"> | ||
| 264 | - <template #default="{row}"> | ||
| 265 | - <div class="i-p-table-cost"> | ||
| 266 | - <my-progress | ||
| 267 | - :data="[ | ||
| 268 | - { label: 'width', value: row.planWidth ?? 0, color: '#0093FF' }, | ||
| 269 | - { label: '', value: data.total.totalPlanWidth, total: true } | ||
| 270 | - ]" | ||
| 271 | - style="flex: 1;" | ||
| 272 | - width="100%" | ||
| 273 | - height="10px" | ||
| 274 | - :onlyOne="true" | ||
| 275 | - /> | ||
| 276 | - <p>{{ row.planWidth }}</p> | ||
| 277 | - </div> | ||
| 278 | - </template> | ||
| 279 | - </el-table-column> | ||
| 280 | - <el-table-column prop="joinType" label="condition" /> | ||
| 281 | - </el-table> | ||
| 282 | - </div> | ||
| 283 | - </div> | ||
| 284 | - <my-message | ||
| 285 | - v-if="errorInfo" | ||
| 286 | - :type="isInfoTip(errorInfo) ? 'info' : 'error'" | ||
| 287 | - :tip="$t(`sql.${errorInfo}`)" | ||
| 288 | - defaultTip="" | ||
| 289 | - :key="errorInfo" | ||
| 290 | - /> | ||
| 291 | -</template> | ||
| 292 | - | ||
| 293 | <style scoped lang="scss"> | 306 | <style scoped lang="scss"> |
| 294 | - | ||
| 295 | .implementation-plan { | 307 | .implementation-plan { |
| 296 | - | 308 | + .i-p-filter { |
| 297 | - .i-p-filter { | 309 | + display: flex; |
| 298 | - display: flex; | 310 | + flex-direction: row-reverse; |
| 299 | - flex-direction: row-reverse; | 311 | + margin-bottom: 8px; |
| 300 | - margin-bottom: 8px; | ||
| 301 | 312 | ||
| 302 | - &:deep(.el-button) { | 313 | + &:deep(.el-button) { |
| 303 | - margin: 0 0 0 8px; | 314 | + margin: 0 0 0 8px; |
| 304 | - background-color: var(--el-button-color-small); | 315 | + background-color: var(--el-button-color-small); |
| 305 | - border: 1px solid #353535; | 316 | + border: 1px solid #353535; |
| 306 | - color: var(--el-text-color-og); | 317 | + color: var(--el-text-color-og); |
| 307 | - } | ||
| 308 | - | ||
| 309 | - &:deep(.el-button:hover) { | ||
| 310 | - color: var(--el-text-color-og); | ||
| 311 | - } | ||
| 312 | } | 318 | } |
| 313 | 319 | ||
| 314 | - .i-p-table { | 320 | + &:deep(.el-button:hover) { |
| 315 | - | 321 | + color: var(--el-text-color-og); |
| 316 | - overflow-y: auto; | 322 | + } |
| 323 | + } | ||
| 317 | 324 | ||
| 318 | - &-cost { | 325 | + .i-p-table { |
| 319 | - height: 20px; | 326 | + overflow-y: auto; |
| 320 | - display: flex; | ||
| 321 | - align-items: center; | ||
| 322 | - justify-content: space-between; | ||
| 323 | - > p { | ||
| 324 | - margin-left: 8px; | ||
| 325 | - } | ||
| 326 | - } | ||
| 327 | 327 | ||
| 328 | - &:deep(.el-table .warning-row) { | 328 | + &-cost { |
| 329 | - --el-table-tr-bg-color: var(--el-color-table-row-bg-color); | 329 | + height: 20px; |
| 330 | - } | 330 | + display: flex; |
| 331 | + align-items: center; | ||
| 332 | + justify-content: space-between; | ||
| 333 | + > p { | ||
| 334 | + margin-left: 8px; | ||
| 335 | + } | ||
| 331 | } | 336 | } |
| 332 | 337 | ||
| 338 | + &:deep(.el-table .warning-row) { | ||
| 339 | + --el-table-tr-bg-color: var(--el-color-table-row-bg-color); | ||
| 340 | + } | ||
| 341 | + } | ||
| 333 | } | 342 | } |
| 334 | </style> | 343 | </style> |
Mplugins/observability-instance/web-ui/src/pages/sql_detail/statistical_information/Index.vue+284-272
| @@ -1,307 +1,319 @@ | |||
| 1 | +<template> | ||
| 2 | + <div class="statistical-information" v-loading="props.loading"> | ||
| 3 | + <div class="s-i-row"> | ||
| 4 | + <div class="s-i-col-left"> | ||
| 5 | + <my-card height="280" :title="$t('sql.baseInfoTitle')" :bodyPadding="false"> | ||
| 6 | + <div class="s-i-base"> | ||
| 7 | + <p class="s-i-base-item" v-for="item in baseInfoOption" :key="item.value"> | ||
| 8 | + {{ $t(`sql.baseInfoOption.${item.label}`) }} | ||
| 9 | + {{ `:${getValue(item.value, props.data)}` }} | ||
| 10 | + </p> | ||
| 11 | + </div> | ||
| 12 | + </my-card> | ||
| 13 | + </div> | ||
| 14 | + <div class="s-i-col-right"> | ||
| 15 | + <my-card height="280" :title="$t('sql.executionStatisticTitle')" :bodyPadding="false"> | ||
| 16 | + <div class="s-i-execute"> | ||
| 17 | + <el-row v-for="(item, index) in executeOption" :key="index"> | ||
| 18 | + <el-col class="s-i-el-col" :span="5">{{ $t(`sql.executeOption.${item[0].label}`) }}</el-col> | ||
| 19 | + <el-col :span="5">{{ getValue(item[0].value, props.data) }}</el-col> | ||
| 20 | + <el-col class="s-i-el-col" :span="8">{{ $t(`sql.executeOption.${item[1].label}`) }}</el-col> | ||
| 21 | + <el-col :span="6">{{ getValue(item[1].value, props.data) }}</el-col> | ||
| 22 | + </el-row> | ||
| 23 | + </div> | ||
| 24 | + </my-card> | ||
| 25 | + </div> | ||
| 26 | + </div> | ||
| 27 | + <div class="s-i-row"> | ||
| 28 | + <div class="s-i-col-left"> | ||
| 29 | + <my-card height="300" :title="$t('sql.consumptionStatisticTitle')" :bodyPadding="false"> | ||
| 30 | + <div class="s-i-statistics"> | ||
| 31 | + <div class="s-i-statistics-box"> | ||
| 32 | + <div class="s-i-statistics-pie"> | ||
| 33 | + <my-pie | ||
| 34 | + :showLegend="false" | ||
| 35 | + :center="['50%', '50%']" | ||
| 36 | + :data="data.useTimeStatistical" | ||
| 37 | + :color="['#3DC94C', '#DA864C']" | ||
| 38 | + :theme="theme" | ||
| 39 | + :key="theme" | ||
| 40 | + /> | ||
| 41 | + </div> | ||
| 42 | + <div class="s-i-statistics-legend"> | ||
| 43 | + <div class="s-i-statistics-item" v-for="item in data.useTimeStatistical" :key="item.name"> | ||
| 44 | + <span :style="`background-color: ${item.color}`" class="s-i-statistics-item-block"></span> | ||
| 45 | + <span>{{ $t(`sql.${item.name}`) }} {{ `(${item.value.toFixed(2)}%)` }}</span> | ||
| 46 | + </div> | ||
| 47 | + </div> | ||
| 48 | + </div> | ||
| 49 | + <div class="s-i-statistics-list"> | ||
| 50 | + <p class="s-i-statistics-text">{{ `${$t('sql.dbTimeLabel')}:${props.data['db_time']} ms` }}</p> | ||
| 51 | + <p class="s-i-statistics-text">{{ `${$t('sql.cpuTimeLabel')}:${props.data['cpu_time']} ms` }}</p> | ||
| 52 | + <p class="s-i-statistics-text">{{ `${$t('sql.waitTimeLabel')}:${props.data['wait_time']} ms` }}</p> | ||
| 53 | + </div> | ||
| 54 | + </div> | ||
| 55 | + </my-card> | ||
| 56 | + </div> | ||
| 57 | + <div class="s-i-col-right"> | ||
| 58 | + <my-card height="300" :title="$t('sql.consumingBreakdownTitle')" :bodyPadding="false"> | ||
| 59 | + <div class="s-i-consuming"> | ||
| 60 | + <div class="s-i-consuming-pie"> | ||
| 61 | + <my-pie | ||
| 62 | + :showLegend="false" | ||
| 63 | + :center="['50%', '50%']" | ||
| 64 | + :data="data.consumingPieData" | ||
| 65 | + :color="data.consumingPieColor" | ||
| 66 | + :theme="theme" | ||
| 67 | + :key="theme" | ||
| 68 | + /> | ||
| 69 | + </div> | ||
| 70 | + <div class="s-i-consuming-legend"> | ||
| 71 | + <div class="s-i-consuming-item" v-for="item in consumingOption" :key="item.value"> | ||
| 72 | + <span :style="`background-color: ${item.color}`" class="s-i-consuming-item-block"></span> | ||
| 73 | + <span class="s-i-consuming-item-label">{{ $t(`sql.consumingOption.${item.label}`) }}:</span> | ||
| 74 | + <span class="s-i-consuming-item-value">{{ `${getValue(item.value, props.data)} ms` }}</span> | ||
| 75 | + </div> | ||
| 76 | + </div> | ||
| 77 | + </div> | ||
| 78 | + </my-card> | ||
| 79 | + </div> | ||
| 80 | + </div> | ||
| 81 | + </div> | ||
| 82 | +</template> | ||
| 83 | + | ||
| 1 | <script setup lang="ts"> | 84 | <script setup lang="ts"> |
| 2 | -import { storeToRefs } from 'pinia'; | 85 | +import { storeToRefs } from 'pinia' |
| 3 | -import { baseInfoOption, executeOption, consumingOption } from './common'; | 86 | +import { baseInfoOption, executeOption, consumingOption } from '@/pages/sql_detail/statistical_information/common' |
| 4 | -import { useWindowStore } from "../../../store/window"; | 87 | +import { useWindowStore } from '@/store/window' |
| 5 | 88 | ||
| 6 | const { theme } = storeToRefs(useWindowStore()) | 89 | const { theme } = storeToRefs(useWindowStore()) |
| 7 | 90 | ||
| 8 | -const props = withDefaults(defineProps<{ | 91 | +const props = withDefaults( |
| 9 | - data: Record<string, string>, | 92 | + defineProps<{ |
| 93 | + data: Record<string, string> | ||
| 10 | loading: boolean | 94 | loading: boolean |
| 11 | -}>(), { | 95 | + }>(), |
| 12 | - loading: false | 96 | + { |
| 13 | -}) | 97 | + loading: false, |
| 98 | + } | ||
| 99 | +) | ||
| 14 | const data = reactive<{ | 100 | const data = reactive<{ |
| 15 | - useTimeStatistical: Array<{ name: string, value: number, color?: string }>, | 101 | + useTimeStatistical: Array<{ name: string; value: number; color?: string }> |
| 16 | - consumingPieData: Array<{ name: string, value: number }>, | 102 | + consumingPieData: Array<{ name: string; value: number }> |
| 17 | - consumingPieColor: Array<string> | 103 | + consumingPieColor: Array<string> |
| 18 | }>({ | 104 | }>({ |
| 19 | - useTimeStatistical: [], | 105 | + useTimeStatistical: [], |
| 20 | - consumingPieData: [], | 106 | + consumingPieData: [], |
| 21 | - consumingPieColor: [] | 107 | + consumingPieColor: [], |
| 22 | -}); | 108 | +}) |
| 23 | 109 | ||
| 24 | const getValue = (key: string, curData: Record<string, string>) => { | 110 | const getValue = (key: string, curData: Record<string, string>) => { |
| 25 | - if (curData != null) { | 111 | + if (curData != null) { |
| 26 | - return curData[key] || '-'; | 112 | + if (typeof curData[key] === 'object') return curData[key].value |
| 27 | - } | 113 | + else return curData[key] || '-' |
| 28 | - return '-'; | 114 | + } |
| 115 | + return '-' | ||
| 29 | } | 116 | } |
| 30 | 117 | ||
| 31 | -watch(() => props.data, (res) => { | 118 | +watch( |
| 32 | - // eslint-disable-next-line camelcase | 119 | + () => props.data, |
| 33 | - const { cpu_time, wait_time, db_time } = res; | 120 | + (res) => { |
| 34 | - try { | 121 | + // clean data |
| 35 | - const cpuTimeDb = Number.parseInt(db_time) !== 0 ? Number.parseInt(cpu_time) / Number.parseInt(db_time) * 100 : 0; | 122 | + data.useTimeStatistical = [] |
| 36 | - const waitTimeDb = Number.parseInt(db_time) !== 0 ? Number.parseInt(wait_time) / Number.parseInt(db_time) * 100 : 0; | ||
| 37 | - data.useTimeStatistical = [{ | ||
| 38 | - name: 'waitTimeLabel', | ||
| 39 | - value: waitTimeDb, | ||
| 40 | - color: '#3DC94C' | ||
| 41 | - }, { | ||
| 42 | - name: 'cpuTimeLabel', | ||
| 43 | - value: cpuTimeDb, | ||
| 44 | - color: '#DA864C' | ||
| 45 | - }] | ||
| 46 | - consumingOption.forEach(item => { | ||
| 47 | - const value = Number.parseInt(getValue(item.value, props.data)); | ||
| 48 | - if (value > 0) { | ||
| 49 | - data.consumingPieColor.push(item.color as string); | ||
| 50 | - data.consumingPieData.push({ | ||
| 51 | - name: item.label, | ||
| 52 | - value: Number.parseInt(getValue(item.value, props.data)) | ||
| 53 | - }); | ||
| 54 | - } | ||
| 55 | - }) | ||
| 56 | - } catch (e) { | ||
| 57 | - data.useTimeStatistical = []; | ||
| 58 | - }; | ||
| 59 | -}, { deep: true }) | ||
| 60 | 123 | ||
| 124 | + // eslint-disable-next-line camelcase | ||
| 125 | + const { cpu_time, wait_time, db_time } = res | ||
| 126 | + try { | ||
| 127 | + const cpuTimeDb = | ||
| 128 | + Number.parseInt(db_time) !== 0 ? (Number.parseInt(cpu_time) / Number.parseInt(db_time)) * 100 : 0 | ||
| 129 | + const waitTimeDb = | ||
| 130 | + Number.parseInt(db_time) !== 0 ? (Number.parseInt(wait_time) / Number.parseInt(db_time)) * 100 : 0 | ||
| 131 | + data.useTimeStatistical = [ | ||
| 132 | + { | ||
| 133 | + name: 'waitTimeLabel', | ||
| 134 | + value: waitTimeDb, | ||
| 135 | + color: '#3DC94C', | ||
| 136 | + }, | ||
| 137 | + { | ||
| 138 | + name: 'cpuTimeLabel', | ||
| 139 | + value: cpuTimeDb, | ||
| 140 | + color: '#DA864C', | ||
| 141 | + }, | ||
| 142 | + ] | ||
| 143 | + consumingOption.forEach((item: any) => { | ||
| 144 | + const value = Number.parseInt(getValue(item.value, props.data)) | ||
| 145 | + if (value > 0) { | ||
| 146 | + data.consumingPieColor.push(item.color as string) | ||
| 147 | + data.consumingPieData.push({ | ||
| 148 | + name: item.label, | ||
| 149 | + value: Number.parseInt(getValue(item.value, props.data)), | ||
| 150 | + }) | ||
| 151 | + } | ||
| 152 | + }) | ||
| 153 | + } catch (e) { | ||
| 154 | + data.useTimeStatistical = [] | ||
| 155 | + } | ||
| 156 | + }, | ||
| 157 | + { deep: true } | ||
| 158 | +) | ||
| 61 | </script> | 159 | </script> |
| 62 | 160 | ||
| 63 | -<template> | ||
| 64 | - <div class="statistical-information" v-loading="props.loading"> | ||
| 65 | - <div class="s-i-row"> | ||
| 66 | - <div class="s-i-col-left"> | ||
| 67 | - <my-card height="280" :title="$t('sql.baseInfoTitle')" :bodyPadding="false"> | ||
| 68 | - <div class="s-i-base"> | ||
| 69 | - <p class="s-i-base-item" v-for="item in baseInfoOption" :key="item.value"> | ||
| 70 | - {{ $t(`sql.baseInfoOption.${item.label}`) }} | ||
| 71 | - {{ `:${ getValue(item.value, props.data) }` }} | ||
| 72 | - </p> | ||
| 73 | - </div> | ||
| 74 | - </my-card> | ||
| 75 | - </div> | ||
| 76 | - <div class="s-i-col-right"> | ||
| 77 | - <my-card height="280" :title="$t('sql.executionStatisticTitle')" :bodyPadding="false"> | ||
| 78 | - <div class="s-i-execute"> | ||
| 79 | - <el-row v-for="(item, index) in executeOption" :key="index"> | ||
| 80 | - <el-col class="s-i-el-col" :span="5">{{ $t(`sql.executeOption.${item[0].label}`) }}</el-col> | ||
| 81 | - <el-col :span="5">{{ getValue(item[0].value, props.data) }}</el-col> | ||
| 82 | - <el-col class="s-i-el-col" :span="8">{{ $t(`sql.executeOption.${item[1].label}`) }}</el-col> | ||
| 83 | - <el-col :span="6">{{ getValue(item[1].value, props.data) }}</el-col> | ||
| 84 | - </el-row> | ||
| 85 | - </div> | ||
| 86 | - </my-card> | ||
| 87 | - </div> | ||
| 88 | - </div> | ||
| 89 | - <div class="s-i-row"> | ||
| 90 | - <div class="s-i-col-left"> | ||
| 91 | - <my-card height="300" :title="$t('sql.consumptionStatisticTitle')" :bodyPadding="false"> | ||
| 92 | - <div class="s-i-statistics"> | ||
| 93 | - <div class="s-i-statistics-box"> | ||
| 94 | - <div class="s-i-statistics-pie"> | ||
| 95 | - <my-pie | ||
| 96 | - :showLegend="false" | ||
| 97 | - :center="['50%', '50%']" | ||
| 98 | - :data="data.useTimeStatistical" | ||
| 99 | - :color="['#3DC94C', '#DA864C']" | ||
| 100 | - :theme="theme" | ||
| 101 | - :key="theme" | ||
| 102 | - /> | ||
| 103 | - </div> | ||
| 104 | - <div class="s-i-statistics-legend"> | ||
| 105 | - <div class="s-i-statistics-item" v-for="item in data.useTimeStatistical" :key="item.value"> | ||
| 106 | - <span :style="`background-color: ${item.color}`" class="s-i-statistics-item-block"></span> | ||
| 107 | - <span>{{ $t(`sql.${item.name}`) }} {{ `(${item.value.toFixed(2)}%)` }}</span> | ||
| 108 | - </div> | ||
| 109 | - </div> | ||
| 110 | - </div> | ||
| 111 | - <div class="s-i-statistics-list"> | ||
| 112 | - <p class="s-i-statistics-text">{{ `${$t('sql.dbTimeLabel')}:${props.data['db_time']} ms` }}</p> | ||
| 113 | - <p class="s-i-statistics-text">{{ `${$t('sql.cpuTimeLabel')}:${props.data['cpu_time']} ms` }}</p> | ||
| 114 | - <p class="s-i-statistics-text">{{ `${$t('sql.waitTimeLabel')}:${props.data['wait_time']} ms` }}</p> | ||
| 115 | - </div> | ||
| 116 | - </div> | ||
| 117 | - </my-card> | ||
| 118 | - </div> | ||
| 119 | - <div class="s-i-col-right"> | ||
| 120 | - <my-card height="300" :title="$t('sql.consumingBreakdownTitle')" :bodyPadding="false"> | ||
| 121 | - <div class="s-i-consuming"> | ||
| 122 | - <div class="s-i-consuming-pie"> | ||
| 123 | - <my-pie | ||
| 124 | - :showLegend="false" | ||
| 125 | - :center="['50%', '50%']" | ||
| 126 | - :data="data.consumingPieData" | ||
| 127 | - :color="data.consumingPieColor" | ||
| 128 | - :theme="theme" | ||
| 129 | - :key="theme" | ||
| 130 | - /> | ||
| 131 | - </div> | ||
| 132 | - <div class="s-i-consuming-legend"> | ||
| 133 | - <div class="s-i-consuming-item" v-for="item in consumingOption" :key="item.value"> | ||
| 134 | - <span :style="`background-color: ${item.color}`" class="s-i-consuming-item-block"></span> | ||
| 135 | - <span class="s-i-consuming-item-label">{{ $t(`sql.consumingOption.${item.label}`) }}:</span> | ||
| 136 | - <span class="s-i-consuming-item-value">{{ `${getValue(item.value, props.data)} ms` }}</span> | ||
| 137 | - </div> | ||
| 138 | - </div> | ||
| 139 | - </div> | ||
| 140 | - </my-card> | ||
| 141 | - </div> | ||
| 142 | - </div> | ||
| 143 | - </div> | ||
| 144 | -</template> | ||
| 145 | - | ||
| 146 | <style scoped lang="scss"> | 161 | <style scoped lang="scss"> |
| 147 | - | ||
| 148 | .statistical-information { | 162 | .statistical-information { |
| 149 | - font-size: 14px; | 163 | + font-size: 14px; |
| 150 | - // border-top: 1px solid $og-border-color; | 164 | + // border-top: 1px solid $og-border-color; |
| 151 | 165 | ||
| 152 | - .s-i-row { | 166 | + .s-i-row { |
| 153 | - width: 100%; | 167 | + width: 100%; |
| 154 | - display: flex; | 168 | + display: flex; |
| 155 | - justify-content: space-between; | 169 | + justify-content: space-between; |
| 156 | - margin-bottom: 18px; | 170 | + margin-bottom: 18px; |
| 171 | + } | ||
| 172 | + | ||
| 173 | + .s-i-col-left { | ||
| 174 | + height: inherit; | ||
| 175 | + width: 40%; | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + .s-i-col-right { | ||
| 179 | + height: inherit; | ||
| 180 | + width: 58%; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + .s-i-base { | ||
| 184 | + height: inherit; | ||
| 185 | + box-sizing: border-box; | ||
| 186 | + display: flex; | ||
| 187 | + flex-direction: column; | ||
| 188 | + justify-content: space-between; | ||
| 189 | + padding: 18px 40px; | ||
| 190 | + overflow-y: auto; | ||
| 191 | + | ||
| 192 | + &-item { | ||
| 193 | + margin: 3px 0; | ||
| 194 | + } | ||
| 195 | + &:deep(.el-row) { | ||
| 196 | + line-height: 39px; | ||
| 197 | + border: 1px solid $og-border-color; | ||
| 198 | + border-top: none; | ||
| 199 | + border-right: none; | ||
| 157 | } | 200 | } |
| 158 | 201 | ||
| 159 | - .s-i-col-left { | 202 | + &:deep(.el-col) { |
| 160 | - height: inherit; | 203 | + padding-left: 5px; |
| 161 | - width: 40%; | 204 | + border-right: 1px solid $og-border-color; |
| 205 | + } | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + .s-i-execute { | ||
| 209 | + height: inherit; | ||
| 210 | + margin-top: 5px; | ||
| 211 | + border-top: 1px solid var(--el-color--col-border-color); | ||
| 212 | + overflow-y: scroll; | ||
| 213 | + .s-i-el-col { | ||
| 214 | + background-color: var(--el-color-card-header-color); | ||
| 162 | } | 215 | } |
| 163 | 216 | ||
| 164 | - .s-i-col-right { | 217 | + &:deep(.el-row) { |
| 165 | - height: inherit; | 218 | + line-height: 39px; |
| 166 | - width: 58%; | 219 | + border: 1px solid var(--el-color--col-border-color); |
| 220 | + border-top: none; | ||
| 167 | } | 221 | } |
| 168 | 222 | ||
| 169 | - .s-i-base { | 223 | + &:deep(.el-row:first-child) { |
| 170 | - height: inherit; | 224 | + border-right: 1px solid var(--el-color--col-border-color); |
| 171 | - box-sizing: border-box; | ||
| 172 | - display: flex; | ||
| 173 | - flex-direction: column; | ||
| 174 | - justify-content: space-between; | ||
| 175 | - padding: 18px 40px; | ||
| 176 | - overflow-y: auto; | ||
| 177 | - | ||
| 178 | - &-item { | ||
| 179 | - margin: 3px 0; | ||
| 180 | - } | ||
| 181 | - &:deep(.el-row) { | ||
| 182 | - line-height: 39px; | ||
| 183 | - border: 1px solid $og-border-color; | ||
| 184 | - border-top: none; | ||
| 185 | - border-right: none; | ||
| 186 | - } | ||
| 187 | - | ||
| 188 | - &:deep(.el-col) { | ||
| 189 | - padding-left: 5px; | ||
| 190 | - border-right: 1px solid $og-border-color; | ||
| 191 | - } | ||
| 192 | } | 225 | } |
| 193 | 226 | ||
| 194 | - .s-i-execute { | 227 | + &:deep(.el-col) { |
| 195 | - height: inherit; | 228 | + padding-left: 5px; |
| 196 | - margin-top: 5px; | 229 | + // border-top: 1px solid #4A4A4A; |
| 197 | - border-top: 1px solid var(--el-color--col-border-color); | 230 | + } |
| 198 | - overflow-y: scroll; | 231 | + } |
| 199 | - .s-i-el-col { | ||
| 200 | - background-color: var(--el-color-card-header-color); | ||
| 201 | - } | ||
| 202 | 232 | ||
| 203 | - &:deep(.el-row) { | 233 | + .s-i-statistics { |
| 204 | - line-height: 39px; | 234 | + height: inherit; |
| 205 | - border: 1px solid var(--el-color--col-border-color); | 235 | + display: flex; |
| 206 | - border-top: none; | 236 | + align-items: center; |
| 207 | - } | 237 | + overflow-y: auto; |
| 208 | 238 | ||
| 209 | - &:deep(.el-row:first-child) { | 239 | + &-box { |
| 210 | - border-right: 1px solid var(--el-color--col-border-color); | 240 | + display: flex; |
| 211 | - } | 241 | + width: 80%; |
| 212 | - | ||
| 213 | - &:deep(.el-col) { | ||
| 214 | - padding-left: 5px; | ||
| 215 | - // border-top: 1px solid #4A4A4A; | ||
| 216 | - | ||
| 217 | - } | ||
| 218 | } | 242 | } |
| 219 | 243 | ||
| 220 | - .s-i-statistics { | 244 | + &-pie { |
| 221 | - height: inherit; | 245 | + height: 180px; |
| 222 | - display: flex; | 246 | + width: 55%; |
| 223 | - align-items: center; | ||
| 224 | - overflow-y: auto; | ||
| 225 | - | ||
| 226 | - &-box { | ||
| 227 | - display: flex; | ||
| 228 | - width: 80%; | ||
| 229 | - } | ||
| 230 | - | ||
| 231 | - &-pie { | ||
| 232 | - height: 180px; | ||
| 233 | - width: 55%; | ||
| 234 | - } | ||
| 235 | - | ||
| 236 | - &-legend { | ||
| 237 | - width: calc(100% - 120px); | ||
| 238 | - // height: 220px; | ||
| 239 | - display: flex; | ||
| 240 | - flex-direction: column; | ||
| 241 | - justify-content: center; | ||
| 242 | - } | ||
| 243 | - | ||
| 244 | - &-item { | ||
| 245 | - font-size: 12px; | ||
| 246 | - display: flex; | ||
| 247 | - align-items: center; | ||
| 248 | - margin-bottom: 10px; | ||
| 249 | - | ||
| 250 | - &-block { | ||
| 251 | - display: inline-block; | ||
| 252 | - width: 10px; | ||
| 253 | - height: 10px; | ||
| 254 | - margin-right: 3px; | ||
| 255 | - } | ||
| 256 | - } | ||
| 257 | - | ||
| 258 | - &-list { | ||
| 259 | - font-size: 12px; | ||
| 260 | - width: 45%; | ||
| 261 | - } | ||
| 262 | } | 247 | } |
| 263 | 248 | ||
| 264 | - .s-i-consuming { | 249 | + &-legend { |
| 265 | - height: inherit; | 250 | + width: calc(100% - 120px); |
| 266 | - display: flex; | 251 | + // height: 220px; |
| 267 | - align-items: center; | 252 | + display: flex; |
| 268 | - padding: 0 0; | 253 | + flex-direction: column; |
| 269 | - overflow-y: auto; | 254 | + justify-content: center; |
| 270 | - | ||
| 271 | - &-pie { | ||
| 272 | - height: 180px; | ||
| 273 | - width: 180px; | ||
| 274 | - } | ||
| 275 | - | ||
| 276 | - &-legend { | ||
| 277 | - width: calc(100% - 180px); | ||
| 278 | - height: 220px; | ||
| 279 | - display: flex; | ||
| 280 | - flex-wrap: wrap; | ||
| 281 | - padding-left: 10px; | ||
| 282 | - } | ||
| 283 | - | ||
| 284 | - &-item { | ||
| 285 | - font-size: 12px; | ||
| 286 | - display: flex; | ||
| 287 | - align-items: center; | ||
| 288 | - | ||
| 289 | - &:nth-child(1n) { | ||
| 290 | - width: 43%; | ||
| 291 | - } | ||
| 292 | - | ||
| 293 | - &:nth-child(2n) { | ||
| 294 | - width: 57%; | ||
| 295 | - } | ||
| 296 | - | ||
| 297 | - &-block { | ||
| 298 | - display: inline-block; | ||
| 299 | - width: 10px; | ||
| 300 | - height: 10px; | ||
| 301 | - margin-right: 3px; | ||
| 302 | - } | ||
| 303 | - } | ||
| 304 | } | 255 | } |
| 305 | 256 | ||
| 257 | + &-item { | ||
| 258 | + font-size: 12px; | ||
| 259 | + display: flex; | ||
| 260 | + align-items: center; | ||
| 261 | + margin-bottom: 10px; | ||
| 262 | + | ||
| 263 | + &-block { | ||
| 264 | + display: inline-block; | ||
| 265 | + width: 10px; | ||
| 266 | + height: 10px; | ||
| 267 | + margin-right: 3px; | ||
| 268 | + } | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + &-list { | ||
| 272 | + font-size: 12px; | ||
| 273 | + width: 45%; | ||
| 274 | + } | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + .s-i-consuming { | ||
| 278 | + height: inherit; | ||
| 279 | + display: flex; | ||
| 280 | + align-items: center; | ||
| 281 | + padding: 0 0; | ||
| 282 | + overflow-y: auto; | ||
| 283 | + | ||
| 284 | + &-pie { | ||
| 285 | + height: 180px; | ||
| 286 | + width: 180px; | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + &-legend { | ||
| 290 | + width: calc(100% - 180px); | ||
| 291 | + height: 220px; | ||
| 292 | + display: flex; | ||
| 293 | + flex-wrap: wrap; | ||
| 294 | + padding-left: 10px; | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | + &-item { | ||
| 298 | + font-size: 12px; | ||
| 299 | + display: flex; | ||
| 300 | + align-items: center; | ||
| 301 | + | ||
| 302 | + &:nth-child(1n) { | ||
| 303 | + width: 43%; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + &:nth-child(2n) { | ||
| 307 | + width: 57%; | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + &-block { | ||
| 311 | + display: inline-block; | ||
| 312 | + width: 10px; | ||
| 313 | + height: 10px; | ||
| 314 | + margin-right: 3px; | ||
| 315 | + } | ||
| 316 | + } | ||
| 317 | + } | ||
| 306 | } | 318 | } |
| 307 | </style> | 319 | </style> |
| @@ -1,165 +1,352 @@ | |||
| 1 | -<script setup lang="ts"> | 1 | +<template> |
| 2 | -import moment from 'moment'; | 2 | + <div class="system-source"> |
| 3 | -import LazyLine from '../../dashboard/LazyLine.vue'; | 3 | + <my-message |
| 4 | -import { toFixed } from '../../../shared'; | 4 | + type="info" |
| 5 | -import { i18n } from '../../../i18n'; | 5 | + :tip="`${$t('dashboard.rangeTimeTip')}(${getRangeTime()})`" |
| 6 | -import { getDatabaseMetrics } from '../../../api/prometheus'; | 6 | + style="margin-bottom: 8px" |
| 7 | + :key="i18n.global.locale.value" | ||
| 8 | + /> | ||
| 9 | + <div class="s-i-row"> | ||
| 10 | + <div class="s-i-col"> | ||
| 11 | + <my-card :title="$t('dashboard.cpuUseSituation')" height="255" :bodyPadding="false"> | ||
| 12 | + <div id="system_source_0" style="height: 100%"> | ||
| 13 | + <LazyLine | ||
| 14 | + :tabId="uuid()" | ||
| 15 | + :formatter="toFixed" | ||
| 16 | + :data="metricsData.cpu" | ||
| 17 | + :xData="metricsData.time" | ||
| 18 | + :max="100" | ||
| 19 | + :min="0" | ||
| 20 | + :interval="25" | ||
| 21 | + :unit="'%'" | ||
| 22 | + /> | ||
| 23 | + </div> | ||
| 24 | + </my-card> | ||
| 25 | + </div> | ||
| 26 | + <div class="s-i-col"> | ||
| 27 | + <my-card :title="$t('dashboard.memoryUsage')" height="255" :bodyPadding="false"> | ||
| 28 | + <div id="system_source_1" style="height: 100%"> | ||
| 29 | + <LazyLine | ||
| 30 | + :tabId="uuid()" | ||
| 31 | + :formatter="toFixed" | ||
| 32 | + :data="metricsData.memoryUsed" | ||
| 33 | + :xData="metricsData.time" | ||
| 34 | + :max="100" | ||
| 35 | + :min="0" | ||
| 36 | + :interval="25" | ||
| 37 | + :unit="'%'" | ||
| 38 | + /> | ||
| 39 | + </div> | ||
| 40 | + </my-card> | ||
| 41 | + </div> | ||
| 42 | + </div> | ||
| 43 | + <div class="s-i-row"> | ||
| 44 | + <div class="s-i-col"> | ||
| 45 | + <my-card :title="$t('dashboard.networkTransmissionRate')" height="255" :bodyPadding="false"> | ||
| 46 | + <div id="system_source_2" style="height: 100%"> | ||
| 47 | + <LazyLine | ||
| 48 | + :tabId="uuid()" | ||
| 49 | + :formatter="toFixed" | ||
| 50 | + :data="metricsData.network" | ||
| 51 | + :xData="metricsData.time" | ||
| 52 | + :unit="'M/S'" | ||
| 53 | + /> | ||
| 54 | + </div> | ||
| 55 | + </my-card> | ||
| 56 | + </div> | ||
| 57 | + <div class="s-i-col"> | ||
| 58 | + <my-card | ||
| 59 | + :title="$t('resourceMonitor.io.ioUsage')" | ||
| 60 | + height="255" | ||
| 61 | + :legend="[ | ||
| 62 | + { color: '#00C7F9', name: $t('metric.read') }, | ||
| 63 | + { color: '#37D4D1', name: $t('metric.write') }, | ||
| 64 | + ]" | ||
| 65 | + :bodyPadding="false" | ||
| 66 | + > | ||
| 67 | + <div id="system_source_3" style="height: 100%"> | ||
| 68 | + <LazyLine | ||
| 69 | + :tabId="uuid()" | ||
| 70 | + :formatter="toFixed" | ||
| 71 | + :data="metricsData.ioUse" | ||
| 72 | + :xData="metricsData.time" | ||
| 73 | + :max="100" | ||
| 74 | + :min="0" | ||
| 75 | + :interval="25" | ||
| 76 | + :unit="'%'" | ||
| 77 | + :tool-tips-sort="'desc'" | ||
| 78 | + :tool-tips-exclude-zero="true" | ||
| 79 | + /> | ||
| 80 | + </div> | ||
| 81 | + </my-card> | ||
| 82 | + </div> | ||
| 83 | + </div> | ||
| 84 | + </div> | ||
| 85 | +</template> | ||
| 7 | 86 | ||
| 8 | -const props = withDefaults(defineProps<{ | 87 | +<script setup lang="ts"> |
| 9 | - fixedRangeTime?: string[], | 88 | +import moment from 'moment' |
| 10 | -}>(), { | 89 | +import LazyLine from '@/components/echarts/LazyLine.vue' |
| 11 | - fixedRangeTime: () => [], | 90 | +import { toFixed, uuid } from '@/shared' |
| 91 | +import { i18n } from '@/i18n' | ||
| 92 | +import { getSQLMetrics } from '@/api/sqlDetail' | ||
| 93 | +import { useRequest } from 'vue-request' | ||
| 94 | +import dayjs from 'dayjs' | ||
| 95 | +import utc from 'dayjs/plugin/utc' | ||
| 96 | +import timezone from 'dayjs/plugin/timezone' | ||
| 97 | +import { useI18n } from 'vue-i18n' | ||
| 98 | +const { t } = useI18n() | ||
| 99 | + | ||
| 100 | +dayjs.extend(utc) | ||
| 101 | +dayjs.extend(timezone) | ||
| 102 | + | ||
| 103 | +interface LineData { | ||
| 104 | + name: string | ||
| 105 | + data: any[] | ||
| 106 | + [other: string]: any | ||
| 107 | +} | ||
| 108 | +interface MetricsData { | ||
| 109 | + cpu: LineData[] | ||
| 110 | + memoryUsed: LineData[] | ||
| 111 | + network: LineData[] | ||
| 112 | + ioUse: LineData[] | ||
| 113 | + time: string[] | ||
| 114 | +} | ||
| 115 | +const metricsData = ref<MetricsData>({ | ||
| 116 | + cpu: [], | ||
| 117 | + memoryUsed: [], | ||
| 118 | + network: [], | ||
| 119 | + ioUse: [], | ||
| 120 | + time: [], | ||
| 12 | }) | 121 | }) |
| 122 | +const props = withDefaults( | ||
| 123 | + defineProps<{ | ||
| 124 | + dbid: string | ||
| 125 | + fixedRangeTime?: string[] | ||
| 126 | + }>(), | ||
| 127 | + { | ||
| 128 | + dbid: '', | ||
| 129 | + fixedRangeTime: () => [], | ||
| 130 | + } | ||
| 131 | +) | ||
| 13 | 132 | ||
| 14 | const dealTime = (value: string) => { | 133 | const dealTime = (value: string) => { |
| 15 | - return moment(value).format('HH:mm:ss') | 134 | + return moment(value).format('HH:mm:ss') |
| 16 | } | 135 | } |
| 17 | 136 | ||
| 18 | const getRangeTime = () => { | 137 | const getRangeTime = () => { |
| 19 | - return `${dealTime(props.fixedRangeTime[0])} ~ ${dealTime(props.fixedRangeTime[1])}` | 138 | + return `${dealTime(props.fixedRangeTime[0])} ~ ${dealTime(props.fixedRangeTime[1])}` |
| 20 | } | 139 | } |
| 21 | 140 | ||
| 22 | onMounted(() => { | 141 | onMounted(() => { |
| 23 | - getDatabaseMetrics() | 142 | + requestData( |
| 24 | -}); | 143 | + props.dbid, |
| 144 | + Math.floor(moment(props.fixedRangeTime[0]).valueOf() / 1000).toString(), | ||
| 145 | + Math.floor(moment(props.fixedRangeTime[1]).valueOf() / 1000).toString(), | ||
| 146 | + '60' | ||
| 147 | + ) | ||
| 148 | +}) | ||
| 25 | 149 | ||
| 150 | +const { data: indexData, run: requestData } = useRequest(getSQLMetrics, { manual: true }) | ||
| 151 | +watch( | ||
| 152 | + indexData, | ||
| 153 | + () => { | ||
| 154 | + // clear data | ||
| 155 | + metricsData.value.cpu = [] | ||
| 156 | + metricsData.value.memoryUsed = [] | ||
| 157 | + metricsData.value.network = [] | ||
| 158 | + metricsData.value.ioUse = [] | ||
| 159 | + | ||
| 160 | + const baseData = indexData.value | ||
| 161 | + if (!baseData) return | ||
| 162 | + | ||
| 163 | + // CPU | ||
| 164 | + { | ||
| 165 | + let tempData: string[] = [] | ||
| 166 | + baseData.CPU_DB.forEach((d: number) => { | ||
| 167 | + tempData.push(toFixed(d)) | ||
| 168 | + }) | ||
| 169 | + metricsData.value.cpu.push({ data: tempData, name: t('resourceMonitor.cpu.dbThread') }) | ||
| 170 | + } | ||
| 171 | + { | ||
| 172 | + let tempData: string[] = [] | ||
| 173 | + baseData.CPU_TOTAL.forEach((d: number) => { | ||
| 174 | + tempData.push(toFixed(d)) | ||
| 175 | + }) | ||
| 176 | + metricsData.value.cpu.push({ data: tempData, name: 'Total' }) | ||
| 177 | + } | ||
| 178 | + { | ||
| 179 | + let tempData: string[] = [] | ||
| 180 | + baseData.CPU_USER.forEach((d: number) => { | ||
| 181 | + tempData.push(toFixed(d)) | ||
| 182 | + }) | ||
| 183 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'User' }) | ||
| 184 | + } | ||
| 185 | + { | ||
| 186 | + let tempData: string[] = [] | ||
| 187 | + baseData.CPU_SYSTEM.forEach((d: number) => { | ||
| 188 | + tempData.push(toFixed(d)) | ||
| 189 | + }) | ||
| 190 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'System' }) | ||
| 191 | + } | ||
| 192 | + { | ||
| 193 | + let tempData: string[] = [] | ||
| 194 | + baseData.CPU_IOWAIT.forEach((d: number) => { | ||
| 195 | + tempData.push(toFixed(d)) | ||
| 196 | + }) | ||
| 197 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'IOWait' }) | ||
| 198 | + } | ||
| 199 | + { | ||
| 200 | + let tempData: string[] = [] | ||
| 201 | + baseData.CPU_NICE.forEach((d: number) => { | ||
| 202 | + tempData.push(toFixed(d)) | ||
| 203 | + }) | ||
| 204 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Nice' }) | ||
| 205 | + } | ||
| 206 | + { | ||
| 207 | + let tempData: string[] = [] | ||
| 208 | + baseData.CPU_IRQ.forEach((d: number) => { | ||
| 209 | + tempData.push(toFixed(d)) | ||
| 210 | + }) | ||
| 211 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'IRQ' }) | ||
| 212 | + } | ||
| 213 | + { | ||
| 214 | + let tempData: string[] = [] | ||
| 215 | + baseData.CPU_SOFTIRQ.forEach((d: number) => { | ||
| 216 | + tempData.push(toFixed(d)) | ||
| 217 | + }) | ||
| 218 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Soft IRQ' }) | ||
| 219 | + } | ||
| 220 | + { | ||
| 221 | + let tempData: string[] = [] | ||
| 222 | + baseData.CPU_STEAL.forEach((d: number) => { | ||
| 223 | + tempData.push(toFixed(d)) | ||
| 224 | + }) | ||
| 225 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Steal' }) | ||
| 226 | + } | ||
| 227 | + { | ||
| 228 | + let tempData: string[] = [] | ||
| 229 | + baseData.CPU_IDLE.forEach((d: number) => { | ||
| 230 | + tempData.push(toFixed(d)) | ||
| 231 | + }) | ||
| 232 | + metricsData.value.cpu.push({ data: tempData, areaStyle: {}, stack: 'Total', name: 'Idle' }) | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + // memory | ||
| 236 | + if (baseData.MEMORY_USED) { | ||
| 237 | + let tempData: string[] = [] | ||
| 238 | + baseData.MEMORY_USED.forEach((d: number) => { | ||
| 239 | + tempData.push(toFixed(d)) | ||
| 240 | + }) | ||
| 241 | + metricsData.value.memoryUsed.push({ | ||
| 242 | + data: tempData, | ||
| 243 | + areaStyle: {}, | ||
| 244 | + name: t('resourceMonitor.memory.memoryUse'), | ||
| 245 | + }) | ||
| 246 | + } | ||
| 247 | + if (baseData.MEMORY_DB_USED) { | ||
| 248 | + let tempData: string[] = [] | ||
| 249 | + baseData.MEMORY_DB_USED.forEach((d: number) => { | ||
| 250 | + tempData.push(toFixed(d)) | ||
| 251 | + }) | ||
| 252 | + metricsData.value.memoryUsed.push({ | ||
| 253 | + data: tempData, | ||
| 254 | + areaStyle: {}, | ||
| 255 | + name: t('resourceMonitor.memory.memoryDBUse'), | ||
| 256 | + }) | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + // Network | ||
| 260 | + if (baseData.NETWORK_OUT_TOTAL && baseData.NETWORK_OUT_TOTAL.length > 0) { | ||
| 261 | + let tempData: string[] = [] | ||
| 262 | + baseData.NETWORK_OUT_TOTAL.forEach((d: number) => { | ||
| 263 | + tempData.push(toFixed(d / 1024 / 1024, 1)) | ||
| 264 | + }) | ||
| 265 | + metricsData.value.network.push({ | ||
| 266 | + data: tempData, | ||
| 267 | + areaStyle: {}, | ||
| 268 | + stack: 'Total', | ||
| 269 | + name: 'Out', | ||
| 270 | + lineStyle: { | ||
| 271 | + color: '#0E78DA', | ||
| 272 | + }, | ||
| 273 | + }) | ||
| 274 | + } | ||
| 275 | + if (baseData.NETWORK_IN_TOTAL && baseData.NETWORK_IN_TOTAL.length > 0) { | ||
| 276 | + let tempData: string[] = [] | ||
| 277 | + baseData.NETWORK_IN_TOTAL.forEach((d: number) => { | ||
| 278 | + tempData.push(toFixed(d / 1024 / 1024, 1)) | ||
| 279 | + }) | ||
| 280 | + metricsData.value.network.push({ | ||
| 281 | + data: tempData, | ||
| 282 | + areaStyle: {}, | ||
| 283 | + stack: 'Total', | ||
| 284 | + name: 'In', | ||
| 285 | + lineStyle: { | ||
| 286 | + color: '#83CBFF', | ||
| 287 | + }, | ||
| 288 | + }) | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + // io use | ||
| 292 | + for (let key in baseData.IO_UTIL) { | ||
| 293 | + let tempData: string[] = [] | ||
| 294 | + baseData.IO_UTIL[key].forEach((element: any) => { | ||
| 295 | + tempData.push(toFixed(element)) | ||
| 296 | + }) | ||
| 297 | + metricsData.value.ioUse.push({ data: tempData, name: key, key }) | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + // time | ||
| 301 | + metricsData.value.time = baseData.time | ||
| 302 | + }, | ||
| 303 | + { deep: true } | ||
| 304 | +) | ||
| 26 | </script> | 305 | </script> |
| 27 | 306 | ||
| 28 | -<template> | ||
| 29 | - <div class="system-source"> | ||
| 30 | - <my-message | ||
| 31 | - type="info" | ||
| 32 | - :tip="`${$t('dashboard.rangeTimeTip')}(${getRangeTime()})`" | ||
| 33 | - style="margin-bottom: 8px;" | ||
| 34 | - :key="i18n.global.locale.value" | ||
| 35 | - /> | ||
| 36 | - <div class="s-i-row"> | ||
| 37 | - <div class="s-i-col"> | ||
| 38 | - <my-card :title="$t('dashboard.cpuUseSituation')" height="255" :legend="[ | ||
| 39 | - {color: '#9CCC65', name: $t('metric.totalCoreNum')}, | ||
| 40 | - {color: '#00C7F9', name: $t('metric.totalAverageUtilization')} | ||
| 41 | - ]" :bodyPadding="false"> | ||
| 42 | - <div class="linename"> | ||
| 43 | - <div>{{ $t('metric.totalCoreNum') }}</div> | ||
| 44 | - <div id="system_source_0" style="height: 100%;"> | ||
| 45 | - <LazyLine | ||
| 46 | - :color="['#9CCC65', '#00C7F9']" | ||
| 47 | - :names="['totalCoreNum', 'totalAverageUtilization']" | ||
| 48 | - :name-indexs="[1]" | ||
| 49 | - name-fix="1" | ||
| 50 | - hasScatterData | ||
| 51 | - scatterUnit="%" | ||
| 52 | - :scatterOpts="{type: 'line', symbol: 'none'}" | ||
| 53 | - :defaultBrushArea="props.fixedRangeTime" | ||
| 54 | - :countByDataTimePicker="false" | ||
| 55 | - /> | ||
| 56 | - </div> | ||
| 57 | - <div>{{ $t('metric.totalAverageUtilization') }}</div> | ||
| 58 | - </div> | ||
| 59 | - </my-card> | ||
| 60 | - </div> | ||
| 61 | - <div class="s-i-col"> | ||
| 62 | - <my-card :title="$t('dashboard.memoryUsage')" height="255" :legend="[ | ||
| 63 | - {color: '#00C7F9', name: $t('metric.totalAverageUtilization')} | ||
| 64 | - ]" :bodyPadding="false"> | ||
| 65 | - <div id="system_source_1" style="height: 100%;"> | ||
| 66 | - <LazyLine | ||
| 67 | - :color="['#00C7F9']" | ||
| 68 | - :names="['totalAverageUtilization']" | ||
| 69 | - :name-indexs="[0]" | ||
| 70 | - name-fix="2" | ||
| 71 | - unit="%" | ||
| 72 | - :defaultBrushArea="props.fixedRangeTime" | ||
| 73 | - :countByDataTimePicker="false" | ||
| 74 | - /> | ||
| 75 | - </div> | ||
| 76 | - </my-card> | ||
| 77 | - </div> | ||
| 78 | - </div> | ||
| 79 | - <div class="s-i-row"> | ||
| 80 | - <div class="s-i-col"> | ||
| 81 | - <my-card :title="$t('dashboard.networkTransmissionRate')" height="255" :legend="[ | ||
| 82 | - {color: '#00C7F9', name: $t('metric.upload')}, | ||
| 83 | - {color: '#37D4D1', name: $t('metric.download')} | ||
| 84 | - ]" :bodyPadding="false"> | ||
| 85 | - <div id="system_source_2" style="height: 100%;"> | ||
| 86 | - <LazyLine | ||
| 87 | - :color="['#00C7F9', '#37D4D1']" | ||
| 88 | - :names="['upload', 'download']" | ||
| 89 | - unit="MB/s" | ||
| 90 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1048576))" | ||
| 91 | - :defaultBrushArea="props.fixedRangeTime" | ||
| 92 | - :countByDataTimePicker="false" | ||
| 93 | - /> | ||
| 94 | - </div> | ||
| 95 | - </my-card> | ||
| 96 | - </div> | ||
| 97 | - <div class="s-i-col"> | ||
| 98 | - <my-card :title="$t('dashboard.diskReadAndWriteRate2')" height="255" :legend="[ | ||
| 99 | - {color: '#00C7F9', name: $t('metric.read')}, | ||
| 100 | - {color: '#37D4D1', name: $t('metric.write')} | ||
| 101 | - ]" :bodyPadding="false"> | ||
| 102 | - <div id="system_source_3" style="height: 100%;"> | ||
| 103 | - <LazyLine | ||
| 104 | - :color="['#00C7F9', '#37D4D1']" | ||
| 105 | - :names="['read', 'write']" | ||
| 106 | - :name-indexs="[0, 1]" | ||
| 107 | - name-fix="1" | ||
| 108 | - :formatter="(d: string) => toFixed((Number.parseFloat(d) / 1024))" | ||
| 109 | - unit="KB/s" | ||
| 110 | - :defaultBrushArea="props.fixedRangeTime" | ||
| 111 | - :countByDataTimePicker="false" | ||
| 112 | - /> | ||
| 113 | - </div> | ||
| 114 | - </my-card> | ||
| 115 | - </div> | ||
| 116 | - </div> | ||
| 117 | - </div> | ||
| 118 | -</template> | ||
| 119 | - | ||
| 120 | <style scoped lang="scss"> | 307 | <style scoped lang="scss"> |
| 121 | .linename { | 308 | .linename { |
| 122 | - display: flex; | 309 | + display: flex; |
| 123 | - width: 100%; | 310 | + width: 100%; |
| 311 | + height: 100%; | ||
| 312 | + align-items: center; | ||
| 313 | + position: relative; | ||
| 314 | + justify-content: center; | ||
| 315 | + > div:nth-of-type(2) { | ||
| 316 | + width: calc(100% - 60px); | ||
| 124 | height: 100%; | 317 | height: 100%; |
| 125 | - align-items: center; | 318 | + margin: 0 10px; |
| 126 | - position: relative; | 319 | + } |
| 127 | - justify-content: center; | 320 | + > div:nth-of-type(1), |
| 128 | - > div:nth-of-type(2) { | 321 | + > div:nth-of-type(3) { |
| 129 | - width: calc(100% - 60px); | 322 | + color: var(--el-color-line-text-color); |
| 130 | - height: 100%; | 323 | + font-size: 12px; |
| 131 | - margin: 0 10px; | 324 | + text-align: center; |
| 132 | - } | 325 | + position: absolute; |
| 133 | - > div:nth-of-type(1), > div:nth-of-type(3) { | 326 | + width: 200px; |
| 134 | - color: var(--el-color-line-text-color); | 327 | + height: 15px; |
| 135 | - font-size: 12px; | 328 | + } |
| 136 | - text-align: center; | 329 | + > div:nth-of-type(1) { |
| 137 | - position: absolute; | 330 | + transform: rotate(-90deg); |
| 138 | - width: 200px; | 331 | + left: -80px; |
| 139 | - height: 15px; | 332 | + } |
| 140 | - } | 333 | + > div:nth-of-type(3) { |
| 141 | - > div:nth-of-type(1) { | 334 | + transform: rotate(90deg); |
| 142 | - transform: rotate(-90deg); | 335 | + right: -80px; |
| 143 | - left: -80px; | 336 | + } |
| 144 | - } | ||
| 145 | - > div:nth-of-type(3) { | ||
| 146 | - transform: rotate(90deg); | ||
| 147 | - right: -80px; | ||
| 148 | - } | ||
| 149 | } | 337 | } |
| 150 | .system-source { | 338 | .system-source { |
| 339 | + .s-i-row { | ||
| 340 | + width: 100%; | ||
| 341 | + display: flex; | ||
| 342 | + justify-content: space-between; | ||
| 343 | + margin-bottom: 18px; | ||
| 344 | + } | ||
| 151 | 345 | ||
| 152 | - .s-i-row { | 346 | + .s-i-col { |
| 153 | - width: 100%; | 347 | + height: inherit; |
| 154 | - display: flex; | 348 | + width: 49%; |
| 155 | - justify-content: space-between; | 349 | + position: relative; |
| 156 | - margin-bottom: 18px; | 350 | + } |
| 157 | - } | ||
| 158 | - | ||
| 159 | - .s-i-col { | ||
| 160 | - height: inherit; | ||
| 161 | - width: 49%; | ||
| 162 | - position: relative; | ||
| 163 | - } | ||
| 164 | } | 351 | } |
| 165 | </style> | 352 | </style> |
| @@ -5,87 +5,116 @@ | |||
| 5 | import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' | 5 | import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' |
| 6 | 6 | ||
| 7 | declare module 'vue-router' { | 7 | declare module 'vue-router' { |
| 8 | - // eslint-disable-next-line no-unused-vars | 8 | + // eslint-disable-next-line no-unused-vars |
| 9 | - interface RouteMeta { | 9 | + interface RouteMeta { |
| 10 | - icon?: string | 10 | + icon?: string |
| 11 | - title: string | 11 | + title: string |
| 12 | - hidden?: boolean | 12 | + hidden?: boolean |
| 13 | - breadcrumb?: string[] | 13 | + breadcrumb?: string[] |
| 14 | - } | 14 | + } |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | export const routes: RouteRecordRaw[] = [ | 17 | export const routes: RouteRecordRaw[] = [ |
| 18 | - { | 18 | + { |
| 19 | - path: '/vem', | 19 | + path: '/vem', |
| 20 | - meta: { | 20 | + meta: { |
| 21 | - icon: 'vite', | 21 | + icon: 'vite', |
| 22 | - title: 'app.menuName', | 22 | + title: 'app.menuName', |
| 23 | - }, | ||
| 24 | - children: [ | ||
| 25 | - { | ||
| 26 | - path: '/vem/dashboard/instance', | ||
| 27 | - component: () => import('@/pages/dashboardV2/Index.vue'), | ||
| 28 | - meta: { | ||
| 29 | - title: 'dashboard.instance', | ||
| 30 | - breadcrumb: [], | ||
| 31 | - }, | ||
| 32 | - }, | ||
| 33 | - { | ||
| 34 | - path: '/vem/sessionDetail/:dbid/:id', | ||
| 35 | - meta: { | ||
| 36 | - icon: 'vite', | ||
| 37 | - title: 'session.tabTitle', | ||
| 38 | - breadcrumb: ['app.menuName', 'session.tabTitle'], | ||
| 39 | - hidden: true, | ||
| 40 | - }, | ||
| 41 | - name: 'SessionDetailLocal', | ||
| 42 | - component: () => import('@/pages/dashboardV2/instanceMonitor/sessionMonitor/Detail.vue'), | ||
| 43 | - }, | ||
| 44 | - { | ||
| 45 | - path: '/vem/sessionDetail', | ||
| 46 | - meta: { | ||
| 47 | - icon: 'vite', | ||
| 48 | - title: 'session.tabTitle', | ||
| 49 | - breadcrumb: ['app.menuName', 'session.tabTitle'], | ||
| 50 | - }, | ||
| 51 | - name: 'SessionDetail', | ||
| 52 | - component: () => import('@/pages/dashboardV2/instanceMonitor/sessionMonitor/Detail.vue'), | ||
| 53 | - }, | ||
| 54 | - { | ||
| 55 | - path: '/vem/sql_detail/:dbid/:sqlId', | ||
| 56 | - meta: { | ||
| 57 | - icon: 'vite', | ||
| 58 | - title: 'sql.sqlDetail', | ||
| 59 | - breadcrumb: ['app.menuName', 'dashboard.instance'], | ||
| 60 | - hidden: true, | ||
| 61 | - }, | ||
| 62 | - name: 'SqlDetailLocal', | ||
| 63 | - component: () => import('@/pages/sql_detail/Index.vue'), | ||
| 64 | - }, | ||
| 65 | - { | ||
| 66 | - path: '/vem/sql_detail', | ||
| 67 | - meta: { | ||
| 68 | - icon: 'vite', | ||
| 69 | - title: 'sql.sqlDetail', | ||
| 70 | - breadcrumb: ['app.menuName', 'dashboard.instance'], | ||
| 71 | - hidden: true, | ||
| 72 | - }, | ||
| 73 | - name: 'SqlDetail', | ||
| 74 | - component: () => import('@/pages/sql_detail/Index.vue'), | ||
| 75 | - }, | ||
| 76 | - ], | ||
| 77 | }, | 23 | }, |
| 24 | + children: [ | ||
| 25 | + { | ||
| 26 | + path: '/vem/dashboard/clusters', | ||
| 27 | + component: () => import('@/pages/clusterMonitor/Index.vue'), | ||
| 28 | + meta: { | ||
| 29 | + title: 'dashboard.clusters', | ||
| 30 | + breadcrumb: [], | ||
| 31 | + }, | ||
| 32 | + }, | ||
| 33 | + { | ||
| 34 | + path: '/vem/clusterDetail/:dbid', | ||
| 35 | + meta: { | ||
| 36 | + icon: 'vite', | ||
| 37 | + title: 'session.tabTitle', | ||
| 38 | + breadcrumb: ['app.menuName', 'session.tabTitle'], | ||
| 39 | + hidden: true, | ||
| 40 | + }, | ||
| 41 | + name: 'ClusterDetailLocal', | ||
| 42 | + component: () => import('@/pages/clusterMonitor/cluster/Index.vue'), | ||
| 43 | + }, | ||
| 44 | + { | ||
| 45 | + path: '/vem/clusterDetail', | ||
| 46 | + meta: { | ||
| 47 | + icon: 'vite', | ||
| 48 | + title: 'session.tabTitle', | ||
| 49 | + breadcrumb: ['app.menuName', 'session.tabTitle'], | ||
| 50 | + }, | ||
| 51 | + name: 'ClusterDetail', | ||
| 52 | + component: () => import('@/pages/clusterMonitor/cluster/Index.vue'), | ||
| 53 | + }, | ||
| 54 | + { | ||
| 55 | + path: '/vem/dashboard/instance', | ||
| 56 | + component: () => import('@/pages/dashboardV2/Index.vue'), | ||
| 57 | + meta: { | ||
| 58 | + title: 'dashboard.instance', | ||
| 59 | + breadcrumb: [], | ||
| 60 | + }, | ||
| 61 | + }, | ||
| 62 | + { | ||
| 63 | + path: '/vem/sessionDetail/:dbid/:id', | ||
| 64 | + meta: { | ||
| 65 | + icon: 'vite', | ||
| 66 | + title: 'session.tabTitle', | ||
| 67 | + breadcrumb: ['app.menuName', 'session.tabTitle'], | ||
| 68 | + hidden: true, | ||
| 69 | + }, | ||
| 70 | + name: 'SessionDetailLocal', | ||
| 71 | + component: () => import('@/pages/dashboardV2/instanceMonitor/sessionMonitor/Detail.vue'), | ||
| 72 | + }, | ||
| 73 | + { | ||
| 74 | + path: '/vem/sessionDetail', | ||
| 75 | + meta: { | ||
| 76 | + icon: 'vite', | ||
| 77 | + title: 'session.tabTitle', | ||
| 78 | + breadcrumb: ['app.menuName', 'session.tabTitle'], | ||
| 79 | + }, | ||
| 80 | + name: 'SessionDetail', | ||
| 81 | + component: () => import('@/pages/dashboardV2/instanceMonitor/sessionMonitor/Detail.vue'), | ||
| 82 | + }, | ||
| 83 | + { | ||
| 84 | + path: '/vem/sql_detail/:dbid/:sqlId', | ||
| 85 | + meta: { | ||
| 86 | + icon: 'vite', | ||
| 87 | + title: 'sql.sqlDetail', | ||
| 88 | + breadcrumb: ['app.menuName', 'dashboard.instance'], | ||
| 89 | + hidden: true, | ||
| 90 | + }, | ||
| 91 | + name: 'SqlDetailLocal', | ||
| 92 | + component: () => import('@/pages/sql_detail/Index.vue'), | ||
| 93 | + }, | ||
| 94 | + { | ||
| 95 | + path: '/vem/sql_detail', | ||
| 96 | + meta: { | ||
| 97 | + icon: 'vite', | ||
| 98 | + title: 'sql.sqlDetail', | ||
| 99 | + breadcrumb: ['app.menuName', 'dashboard.instance'], | ||
| 100 | + hidden: true, | ||
| 101 | + }, | ||
| 102 | + name: 'SqlDetail', | ||
| 103 | + component: () => import('@/pages/sql_detail/Index.vue'), | ||
| 104 | + }, | ||
| 105 | + ], | ||
| 106 | + }, | ||
| 78 | ] | 107 | ] |
| 79 | 108 | ||
| 80 | const router = createRouter({ | 109 | const router = createRouter({ |
| 81 | - history: createWebHashHistory(), | 110 | + history: createWebHashHistory(), |
| 82 | - routes, | 111 | + routes, |
| 83 | }) | 112 | }) |
| 84 | 113 | ||
| 85 | router.beforeEach((to, from, next) => { | 114 | router.beforeEach((to, from, next) => { |
| 86 | - if (from.path.includes(`/vem/track_detail/`) && to.path.includes(`/vem/log/track`)) { | 115 | + if (from.path.includes(`/vem/track_detail/`) && to.path.includes(`/vem/log/track`)) { |
| 87 | - sessionStorage.removeItem('nodes') | 116 | + sessionStorage.removeItem('nodes') |
| 88 | - } | 117 | + } |
| 89 | - next() | 118 | + next() |
| 90 | }) | 119 | }) |
| 91 | export default router | 120 | export default router |
| @@ -5,205 +5,210 @@ | |||
| 5 | import { defineStore } from 'pinia' | 5 | import { defineStore } from 'pinia' |
| 6 | 6 | ||
| 7 | const sourceType = { | 7 | const sourceType = { |
| 8 | - INSTANCE: 'INSTANCE', | 8 | + INSTANCE: 'INSTANCE', |
| 9 | - AUTOREFRESHTIME: 'AUTOREFRESHTIME', | 9 | + AUTOREFRESHTIME: 'AUTOREFRESHTIME', |
| 10 | - MANUALREFRESH: 'MANUALREFRESH', | 10 | + MANUALREFRESH: 'MANUALREFRESH', |
| 11 | - TABCHANGE: 'TABCHANGE', | 11 | + TABCHANGE: 'TABCHANGE', |
| 12 | - TIMETYPE: 'TIMETYPE', | 12 | + TIMETYPE: 'TIMETYPE', |
| 13 | - TIMERANGE: 'TIMERANGE', | 13 | + TIMERANGE: 'TIMERANGE', |
| 14 | } | 14 | } |
| 15 | const timeTypeSelection = { | 15 | const timeTypeSelection = { |
| 16 | - MIN15: '15m', | 16 | + MIN15: '15m', |
| 17 | - MIN30: '30m', | 17 | + MIN30: '30m', |
| 18 | - HOUR1: '1h', | 18 | + HOUR1: '1h', |
| 19 | - HOUR3: '3h', | 19 | + HOUR3: '3h', |
| 20 | - HOUR6: '6h', | 20 | + HOUR6: '6h', |
| 21 | - HOUR12: '12h', | 21 | + HOUR12: '12h', |
| 22 | - DAY1: '1d', | 22 | + DAY1: '1d', |
| 23 | - DAY2: '2d', | 23 | + DAY2: '2d', |
| 24 | - DAY7: '7d', | 24 | + DAY7: '7d', |
| 25 | - CUSTOM: 'CUSTOM', | 25 | + CUSTOM: 'CUSTOM', |
| 26 | } | 26 | } |
| 27 | interface State { | 27 | interface State { |
| 28 | - // use to refresh data | 28 | + // use to refresh data |
| 29 | - updateCounter: { | 29 | + updateCounter: { |
| 30 | - count: number | 30 | + count: number |
| 31 | - source: string | 31 | + source: string |
| 32 | - } | 32 | + } |
| 33 | - clusterId: string | 33 | + clusterId: string |
| 34 | - instanceId: string | 34 | + instanceId: string |
| 35 | - tabNow: string | 35 | + node: any |
| 36 | - autoRefreshTime: number | 36 | + tabNow: string |
| 37 | - timeType: string | 37 | + autoRefreshTime: number |
| 38 | - timeRange: string[] | 38 | + timeType: string |
| 39 | - isManualRangeSelected: boolean | 39 | + timeRange: string[] |
| 40 | + isManualRangeSelected: boolean | ||
| 40 | 41 | ||
| 41 | - databaseData: Record<string, { data: string[]; time: string[]; name: string }[]> | 42 | + databaseData: Record<string, { data: string[]; time: string[]; name: string }[]> |
| 43 | + /** | ||
| 44 | + * current tab index | ||
| 45 | + */ | ||
| 46 | + tab: number | ||
| 47 | + filters: { | ||
| 42 | /** | 48 | /** |
| 43 | - * current tab index | 49 | + * auto refresh interval |
| 44 | */ | 50 | */ |
| 45 | - tab: number | 51 | + refreshTime: number |
| 46 | - filters: { | ||
| 47 | - /** | ||
| 48 | - * auto refresh interval | ||
| 49 | - */ | ||
| 50 | - refreshTime: number | ||
| 51 | - /** | ||
| 52 | - * range time | ||
| 53 | - */ | ||
| 54 | - rangeTime: number | ||
| 55 | - /** | ||
| 56 | - * custom range time | ||
| 57 | - */ | ||
| 58 | - time: [Date, Date] | null | ||
| 59 | - }[] | ||
| 60 | - autoRefresh: boolean | ||
| 61 | - instanceTimeRange: [Date, Date] | null | ||
| 62 | /** | 52 | /** |
| 63 | - * brush select | 53 | + * range time |
| 64 | */ | 54 | */ |
| 65 | - brushRange: string[] | 55 | + rangeTime: number |
| 66 | /** | 56 | /** |
| 67 | - * topsql server | 57 | + * custom range time |
| 68 | */ | 58 | */ |
| 69 | - fixedRangeTime: Array<string> | 59 | + time: [Date, Date] | null |
| 70 | - serverData: Record<string, { data: string[]; time: string[]; name: string }[]> | 60 | + }[] |
| 71 | - promethuesStart: number | 61 | + autoRefresh: boolean |
| 72 | - promethuesEnd: number | 62 | + instanceTimeRange: [Date, Date] | null |
| 73 | - promethuesStep: number | 63 | + /** |
| 64 | + * brush select | ||
| 65 | + */ | ||
| 66 | + brushRange: string[] | ||
| 67 | + /** | ||
| 68 | + * topsql server | ||
| 69 | + */ | ||
| 70 | + fixedRangeTime: Array<string> | ||
| 71 | + serverData: Record<string, { data: string[]; time: string[]; name: string }[]> | ||
| 72 | + promethuesStart: number | ||
| 73 | + promethuesEnd: number | ||
| 74 | + promethuesStep: number | ||
| 74 | } | 75 | } |
| 75 | export const useMonitorStore = (tabId: string) => { | 76 | export const useMonitorStore = (tabId: string) => { |
| 76 | - return defineStore('monitor-' + tabId, { | 77 | + return defineStore('monitor-' + tabId, { |
| 77 | - state: (): State => ({ | 78 | + state: (): State => ({ |
| 78 | - updateCounter: { | 79 | + updateCounter: { |
| 79 | - count: 0, | 80 | + count: 0, |
| 80 | - source: '', | 81 | + source: '', |
| 81 | - }, | 82 | + }, |
| 82 | - clusterId: '', | 83 | + clusterId: '', |
| 83 | - instanceId: '', | 84 | + instanceId: '', |
| 84 | - tabNow: '', | 85 | + node: {}, |
| 85 | - autoRefreshTime: 30, | 86 | + tabNow: '', |
| 86 | - timeType: timeTypeSelection.HOUR1, | 87 | + autoRefreshTime: 30, |
| 87 | - timeRange: [], | 88 | + timeType: timeTypeSelection.HOUR1, |
| 88 | - isManualRangeSelected: false, | 89 | + timeRange: [], |
| 90 | + isManualRangeSelected: false, | ||
| 89 | 91 | ||
| 90 | - // below may not be use anymore 0525 | 92 | + // below may not be use anymore 0525 |
| 91 | - databaseData: {}, | 93 | + databaseData: {}, |
| 92 | - tab: 0, | 94 | + tab: 0, |
| 93 | - filters: [ | 95 | + filters: [ |
| 94 | - { | 96 | + { |
| 95 | - refreshTime: 30, | 97 | + refreshTime: 30, |
| 96 | - rangeTime: 1, | 98 | + rangeTime: 1, |
| 97 | - time: null, | 99 | + time: null, |
| 98 | - }, | 100 | + }, |
| 99 | - { | 101 | + { |
| 100 | - refreshTime: 30, | 102 | + refreshTime: 30, |
| 101 | - rangeTime: 1, | 103 | + rangeTime: 1, |
| 102 | - time: null, | 104 | + time: null, |
| 103 | - }, | 105 | + }, |
| 104 | - { | 106 | + { |
| 105 | - refreshTime: 30, | 107 | + refreshTime: 30, |
| 106 | - rangeTime: 1, | 108 | + rangeTime: 1, |
| 107 | - time: null, | 109 | + time: null, |
| 108 | - }, | 110 | + }, |
| 109 | - { | 111 | + { |
| 110 | - refreshTime: 30, | 112 | + refreshTime: 30, |
| 111 | - rangeTime: 1, | 113 | + rangeTime: 1, |
| 112 | - time: null, | 114 | + time: null, |
| 113 | - }, | 115 | + }, |
| 114 | - ], | 116 | + ], |
| 115 | - autoRefresh: false, | 117 | + autoRefresh: false, |
| 116 | - instanceTimeRange: null, | 118 | + instanceTimeRange: null, |
| 117 | - brushRange: [], | 119 | + brushRange: [], |
| 118 | - fixedRangeTime: [], | 120 | + fixedRangeTime: [], |
| 119 | - serverData: {}, | 121 | + serverData: {}, |
| 120 | - promethuesStart: 0, | 122 | + promethuesStart: 0, |
| 121 | - promethuesEnd: 0, | 123 | + promethuesEnd: 0, |
| 122 | - promethuesStep: 60, | 124 | + promethuesStep: 60, |
| 123 | - }), | 125 | + }), |
| 124 | - getters: { | 126 | + getters: { |
| 125 | - refreshTimeForBind: (state: State) => { | 127 | + refreshTimeForBind: (state: State) => { |
| 126 | - return state.autoRefreshTime | 128 | + return state.autoRefreshTime |
| 127 | - }, | 129 | + }, |
| 128 | 130 | ||
| 129 | - // below may not be use anymore 0525 | 131 | + // below may not be use anymore 0525 |
| 130 | - refreshTime: (state: State) => { | 132 | + refreshTime: (state: State) => { |
| 131 | - return state.filters[state.tab].refreshTime | 133 | + return state.filters[state.tab].refreshTime |
| 132 | - }, | 134 | + }, |
| 133 | - sourceType: (state: State) => { | 135 | + sourceType: (state: State) => { |
| 134 | - return sourceType | 136 | + return sourceType |
| 135 | - }, | 137 | + }, |
| 136 | - timeTypeSelection: (state: State) => { | 138 | + timeTypeSelected: (state: State) => { |
| 137 | - return timeTypeSelection | 139 | + return state.timeType |
| 138 | - }, | 140 | + }, |
| 139 | - rangeTime: (state: State) => { | 141 | + timeTypeSelection: (state: State) => { |
| 140 | - return state.filters[state.tab].rangeTime | 142 | + return timeTypeSelection |
| 141 | - }, | 143 | + }, |
| 142 | - time: (state: State) => { | 144 | + rangeTime: (state: State) => { |
| 143 | - return state.filters[state.tab].time | 145 | + return state.filters[state.tab].rangeTime |
| 144 | - }, | 146 | + }, |
| 145 | - }, | 147 | + time: (state: State) => { |
| 146 | - actions: { | 148 | + return state.filters[state.tab].time |
| 147 | - updateInstanceAndClusterId(instanceId: string, clusterId: string) { | 149 | + }, |
| 148 | - this.instanceId = instanceId | 150 | + selectedNode: (state: State) => { |
| 149 | - this.clusterId = clusterId | 151 | + return state.node |
| 150 | - this.updateCounter = { | 152 | + }, |
| 151 | - count: this.updateCounter.count + 1, | 153 | + }, |
| 152 | - source: sourceType.INSTANCE, | 154 | + actions: { |
| 153 | - } | 155 | + updateInstanceAndClusterId(instanceId: string, clusterId: string, obj: any) { |
| 154 | - }, | 156 | + this.instanceId = instanceId |
| 155 | - culRangeTimeAndStep() { | 157 | + this.clusterId = clusterId |
| 156 | - console.log('DEBUG: culRangeTimeAndStep') | 158 | + this.node = obj |
| 157 | - let start = 0 | 159 | + this.updateCounter = { |
| 158 | - let end = 0 | 160 | + count: this.updateCounter.count + 1, |
| 159 | - if (this.timeType === timeTypeSelection.CUSTOM) { | 161 | + source: sourceType.INSTANCE, |
| 160 | - start = Number.parseInt(`${new Date(this.timeRange![0]).getTime() / 1000}`) | 162 | + } |
| 161 | - end = Number.parseInt(`${new Date(this.timeRange![1]).getTime() / 1000}`) | 163 | + }, |
| 162 | - } else { | 164 | + culRangeTimeAndStep() { |
| 163 | - let min = 0 | 165 | + let start = 0 |
| 164 | - let now = new Date() | 166 | + let end = 0 |
| 165 | - if (this.timeType === timeTypeSelection.MIN15) min = 15 | 167 | + if (this.timeType === timeTypeSelection.CUSTOM) { |
| 166 | - else if (this.timeType === timeTypeSelection.MIN30) min = 30 | 168 | + start = Number.parseInt(`${new Date(this.timeRange![0]).getTime() / 1000}`) |
| 167 | - else if (this.timeType === timeTypeSelection.HOUR1) min = 1 * 60 | 169 | + end = Number.parseInt(`${new Date(this.timeRange![1]).getTime() / 1000}`) |
| 168 | - else if (this.timeType === timeTypeSelection.HOUR3) min = 3 * 60 | 170 | + } else { |
| 169 | - else if (this.timeType === timeTypeSelection.HOUR6) min = 6 * 60 | 171 | + let min = 0 |
| 170 | - else if (this.timeType === timeTypeSelection.HOUR12) min = 12 * 60 | 172 | + let now = new Date() |
| 171 | - else if (this.timeType === timeTypeSelection.DAY1) min = 1 * 24 * 60 | 173 | + if (this.timeType === timeTypeSelection.MIN15) min = 15 |
| 172 | - else if (this.timeType === timeTypeSelection.DAY2) min = 2 * 24 * 60 | 174 | + else if (this.timeType === timeTypeSelection.MIN30) min = 30 |
| 173 | - else if (this.timeType === timeTypeSelection.DAY7) min = 7 * 24 * 60 | 175 | + else if (this.timeType === timeTypeSelection.HOUR1) min = 1 * 60 |
| 174 | - start = Number.parseInt(`${(now.getTime() - 1000 * min * 60) / 1000}`) | 176 | + else if (this.timeType === timeTypeSelection.HOUR3) min = 3 * 60 |
| 175 | - end = Number.parseInt(`${now.getTime() / 1000}`) | 177 | + else if (this.timeType === timeTypeSelection.HOUR6) min = 6 * 60 |
| 176 | - } | 178 | + else if (this.timeType === timeTypeSelection.HOUR12) min = 12 * 60 |
| 177 | - console.log('DEBUG: start', start) | 179 | + else if (this.timeType === timeTypeSelection.DAY1) min = 1 * 24 * 60 |
| 178 | - console.log('DEBUG: end', end) | 180 | + else if (this.timeType === timeTypeSelection.DAY2) min = 2 * 24 * 60 |
| 179 | - console.log('(end - start) / 260', Math.round((end - start) / 260)) | 181 | + else if (this.timeType === timeTypeSelection.DAY7) min = 7 * 24 * 60 |
| 180 | - return [start, end, Math.max(14, Number.parseInt(`${Math.round((end - start) / 260)}`))] | 182 | + start = Number.parseInt(`${(now.getTime() - 1000 * min * 60) / 1000}`) |
| 181 | - }, | 183 | + end = Number.parseInt(`${now.getTime() / 1000}`) |
| 182 | - updateTabNow(tabNow: string) { | 184 | + } |
| 183 | - this.tabNow = tabNow | 185 | + return [start, end, Math.max(14, Number.parseInt(`${Math.round((end - start) / 260)}`))] |
| 184 | - this.updateCounter = { | 186 | + }, |
| 185 | - count: this.updateCounter.count + 1, | 187 | + updateTabNow(tabNow: string) { |
| 186 | - source: sourceType.TABCHANGE, | 188 | + this.tabNow = tabNow |
| 187 | - } | 189 | + this.updateCounter = { |
| 188 | - }, | 190 | + count: this.updateCounter.count + 1, |
| 189 | - increaseCounter(soucre: string) { | 191 | + source: sourceType.TABCHANGE, |
| 190 | - if (soucre === sourceType.TIMERANGE || soucre === sourceType.TIMETYPE) { | 192 | + } |
| 191 | - this.isManualRangeSelected = false | 193 | + }, |
| 192 | - } | 194 | + increaseCounter(soucre: string) { |
| 193 | - this.updateCounter = { | 195 | + if (soucre === sourceType.TIMERANGE || soucre === sourceType.TIMETYPE) { |
| 194 | - count: this.updateCounter.count + 1, | 196 | + this.isManualRangeSelected = false |
| 195 | - source: soucre, | 197 | + } |
| 196 | - } | 198 | + this.updateCounter = { |
| 197 | - }, | 199 | + count: this.updateCounter.count + 1, |
| 198 | - manualRangeSelection(timeRange: string[]) { | 200 | + source: soucre, |
| 199 | - this.isManualRangeSelected = true | 201 | + } |
| 200 | - this.timeType = timeTypeSelection.CUSTOM | 202 | + }, |
| 201 | - this.timeRange = timeRange | 203 | + manualRangeSelection(timeRange: string[]) { |
| 202 | - this.updateCounter = { | 204 | + this.isManualRangeSelected = true |
| 203 | - count: this.updateCounter.count + 1, | 205 | + this.timeType = timeTypeSelection.CUSTOM |
| 204 | - source: sourceType.TIMERANGE, | 206 | + this.timeRange = timeRange |
| 205 | - } | 207 | + this.updateCounter = { |
| 206 | - }, | 208 | + count: this.updateCounter.count + 1, |
| 207 | - }, | 209 | + source: sourceType.TIMERANGE, |
| 208 | - })() | 210 | + } |
| 211 | + }, | ||
| 212 | + }, | ||
| 213 | + })() | ||
| 209 | } | 214 | } |
| @@ -2,72 +2,73 @@ | |||
| 2 | /// Copyright (c) 2023 Huawei Technologies Co.,Ltd. | 2 | /// Copyright (c) 2023 Huawei Technologies Co.,Ltd. |
| 3 | /// | 3 | /// |
| 4 | 4 | ||
| 5 | -import { defineConfig, loadEnv } from "vite"; | 5 | +import { defineConfig, loadEnv } from 'vite' |
| 6 | -import vue from "@vitejs/plugin-vue"; | 6 | +import vue from '@vitejs/plugin-vue' |
| 7 | -import AutoImport from "unplugin-auto-import/vite"; | 7 | +import AutoImport from 'unplugin-auto-import/vite' |
| 8 | -import Components from "unplugin-vue-components/vite"; | 8 | +import Components from 'unplugin-vue-components/vite' |
| 9 | -import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; | 9 | +import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' |
| 10 | -import { createSvgIconsPlugin } from "vite-plugin-svg-icons"; | 10 | +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' |
| 11 | -import { resolve } from "path"; | 11 | +import { resolve } from 'path' |
| 12 | 12 | ||
| 13 | // https://vitejs.dev/config/ | 13 | // https://vitejs.dev/config/ |
| 14 | export default defineConfig(({ command, mode }) => { | 14 | export default defineConfig(({ command, mode }) => { |
| 15 | - loadEnv(mode, process.cwd()); | 15 | + loadEnv(mode, process.cwd()) |
| 16 | - return { | 16 | + return { |
| 17 | - base: mode === "production" ? "/static-plugin/observability-instance/" : "/", | 17 | + base: mode === 'production' ? '/static-plugin/observability-instance/' : '/', |
| 18 | - plugins: [ | 18 | + plugins: [ |
| 19 | - vue(), | 19 | + vue(), |
| 20 | - AutoImport({ | 20 | + AutoImport({ |
| 21 | - resolvers: [ElementPlusResolver()], | 21 | + resolvers: [ElementPlusResolver()], |
| 22 | - imports: ["vue", "vue-router"], | 22 | + imports: ['vue', 'vue-router'], |
| 23 | - dts: "src/auto-imports.d.ts", | 23 | + dts: 'src/auto-imports.d.ts', |
| 24 | - eslintrc: { | 24 | + eslintrc: { |
| 25 | - enabled: false, | 25 | + enabled: false, |
| 26 | - filepath: "./.eslintrc-auto-import.json", | 26 | + filepath: './.eslintrc-auto-import.json', |
| 27 | - globalsPropValue: true, | 27 | + globalsPropValue: true, |
| 28 | - }, | 28 | + }, |
| 29 | - }), | 29 | + }), |
| 30 | - Components({ | 30 | + Components({ |
| 31 | - resolvers: [ | 31 | + resolvers: [ |
| 32 | - ElementPlusResolver({ | 32 | + ElementPlusResolver({ |
| 33 | - importStyle: "sass", | 33 | + importStyle: 'sass', |
| 34 | - }), | 34 | + }), |
| 35 | - ], | ||
| 36 | - dts: "src/components.d.ts", | ||
| 37 | - dirs: ["src/components", "src/layout"], | ||
| 38 | - }), | ||
| 39 | - createSvgIconsPlugin({ | ||
| 40 | - iconDirs: [resolve(process.cwd(), "src/assets/svg")], | ||
| 41 | - symbolId: "icon-[dir]-[name]", | ||
| 42 | - inject: "body-first", | ||
| 43 | - }), | ||
| 44 | ], | 35 | ], |
| 45 | - define: { | 36 | + dts: 'src/components.d.ts', |
| 46 | - "process.env": { | 37 | + dirs: ['src/components', 'src/layout'], |
| 47 | - mode, | 38 | + }), |
| 48 | - }, | 39 | + createSvgIconsPlugin({ |
| 40 | + iconDirs: [resolve(process.cwd(), 'src/assets/svg')], | ||
| 41 | + symbolId: 'icon-[dir]-[name]', | ||
| 42 | + inject: 'body-first', | ||
| 43 | + }), | ||
| 44 | + ], | ||
| 45 | + define: { | ||
| 46 | + 'process.env': { | ||
| 47 | + mode, | ||
| 48 | + }, | ||
| 49 | + }, | ||
| 50 | + resolve: { | ||
| 51 | + alias: { | ||
| 52 | + '@': resolve(__dirname, './src/'), | ||
| 53 | + }, | ||
| 54 | + }, | ||
| 55 | + css: { | ||
| 56 | + preprocessorOptions: { | ||
| 57 | + scss: { | ||
| 58 | + additionalData: `@use "@/assets/style/theme.scss" as *;@use "@/assets/style/color.scss" as *;`, | ||
| 49 | }, | 59 | }, |
| 50 | - resolve: { | 60 | + }, |
| 51 | - alias: { | 61 | + }, |
| 52 | - "@": resolve(__dirname, "./src/"), | 62 | + server: { |
| 53 | - }, | 63 | + proxy: { |
| 54 | - }, | 64 | + '^/instanceMonitoring': 'http://192.168.110.31:9494/plugins/observability-instance', |
| 55 | - css: { | 65 | + '^/observability': 'http://192.168.110.31:9494/plugins/observability-instance', |
| 56 | - preprocessorOptions: { | 66 | + '^/sqlDiagnosis': 'http://192.168.110.31:9494/plugins/observability-instance', |
| 57 | - scss: { | 67 | + '^/wdr': 'http://192.168.110.31:9494/plugins/observability-instance', |
| 58 | - additionalData: `@use "@/assets/style/theme.scss" as *;@use "@/assets/style/color.scss" as *;`, | 68 | + '^/encryption': 'http://192.168.110.31:9494/plugins/observability-instance', |
| 59 | - }, | 69 | + '^/host': 'http://192.168.110.31:9494/', |
| 60 | - }, | 70 | + '^/hostUser': 'http://192.168.110.31:9494/', |
| 61 | - }, | 71 | + }, |
| 62 | - server: { | 72 | + }, |
| 63 | - proxy: { | 73 | + } |
| 64 | - '^/observability': 'http://192.168.110.31:9494/plugins/observability-instance', | 74 | +}) |
| 65 | - '^/sqlDiagnosis': 'http://192.168.110.31:9494/plugins/observability-instance', | ||
| 66 | - '^/wdr': 'http://192.168.110.31:9494/plugins/observability-instance', | ||
| 67 | - '^/encryption': 'http://192.168.110.31:9494/plugins/observability-instance', | ||
| 68 | - '^/host': 'http://192.168.110.31:9494/', | ||
| 69 | - '^/hostUser': 'http://192.168.110.31:9494/' | ||
| 70 | - }, | ||
| 71 | - }, | ||
| 72 | - }; | ||
| 73 | -}); | ||