diff --git a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/metrics/MetricsCollector.java b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/metrics/MetricsCollector.java index 3053033a..2031a734 100644 --- a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/metrics/MetricsCollector.java +++ b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/metrics/MetricsCollector.java @@ -47,7 +47,7 @@ public class MetricsCollector { @Qualifier("diskIOMultiGauge") private MultiGauge diskIOMultiGauge; @Async - @Scheduled(cron = "*/10 * * * * ?") + @Scheduled(cron = "0,30 * * * * ?") public void collect() { // refresh agent host monitoring data scrape(); diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MonitoringController.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java similarity index 53% rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MonitoringController.java rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java index 03ad663a..15870b57 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MonitoringController.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java @@ -18,11 +18,13 @@ */ package org.apache.bigtop.manager.server.controller; -import org.apache.bigtop.manager.server.service.MonitoringService; +import org.apache.bigtop.manager.server.service.MetricsService; import org.apache.bigtop.manager.server.utils.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.databind.JsonNode; @@ -31,30 +33,31 @@ import jakarta.annotation.Resource; -@Tag(name = "Monitoring Controller") +@Tag(name = "Metrics Controller") @RestController -@RequestMapping("monitoring") -public class MonitoringController { +@RequestMapping("metrics") +public class MetricsController { @Resource - private MonitoringService monitoringService; + private MetricsService metricsService; - @Operation(summary = "agent healthy", description = "agent healthy check") - @GetMapping("agenthealthy") + @Operation(summary = "hosts healthy", description = "hosts healthy check") + @GetMapping("hostshealthy") public ResponseEntity agentHostsHealthyStatus() { - // json for response - return ResponseEntity.success(monitoringService.queryAgentsHealthyStatus()); + return ResponseEntity.success(metricsService.queryAgentsHealthyStatus()); } - @Operation(summary = "agent Info", description = "agent info query") - @GetMapping("agentinfo") - public ResponseEntity queryAgentsInfo() { - return ResponseEntity.success(monitoringService.queryAgentsInfo()); + @Operation(summary = "host info", description = "host info query") + @GetMapping("hosts/{id}") + public ResponseEntity queryAgentInfo( + @RequestParam(value = "interval", defaultValue = "1m") String interval, @PathVariable String id) { + return ResponseEntity.success(metricsService.queryAgentsInfo(Long.valueOf(id), interval)); } - @Operation(summary = "agent instant info", description = "agent instant info query") - @GetMapping("agentinstinfo") - public ResponseEntity queryAgentsInstStatus() { - return ResponseEntity.success(monitoringService.queryAgentsInstStatus()); + @Operation(summary = "cluster info", description = "cluster info query") + @GetMapping("clusters/{id}") + public ResponseEntity queryCluster( + @RequestParam(value = "interval", defaultValue = "1m") String interval, @PathVariable String id) { + return ResponseEntity.success(metricsService.queryClustersInfo(Long.valueOf(id), interval)); } } diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/proxy/PrometheusProxy.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/proxy/PrometheusProxy.java index e57f44f7..30920a27 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/proxy/PrometheusProxy.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/proxy/PrometheusProxy.java @@ -18,6 +18,12 @@ */ package org.apache.bigtop.manager.server.proxy; +import org.apache.bigtop.manager.dao.query.HostQuery; +import org.apache.bigtop.manager.server.model.vo.HostVO; +import org.apache.bigtop.manager.server.model.vo.PageVO; +import org.apache.bigtop.manager.server.service.HostService; +import org.apache.bigtop.manager.server.utils.ProxyUtils; + import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; @@ -30,12 +36,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Mono; +import jakarta.annotation.Resource; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; -import java.util.HashSet; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; -import java.util.Set; @Component public class PrometheusProxy { @@ -45,286 +52,504 @@ public class PrometheusProxy { @Value("${monitoring.agent-host-job-name}") private String agentHostJobName; + public static final String MEM_IDLE = "memIdle"; + public static final String MEM_TOTAL = "memTotal"; + public static final String DISK_IDLE = "diskFreeSpace"; + public static final String DISK_TOTAL = "diskTotalSpace"; + public static final String FILE_OPEN_DESCRIPTOR = "fileOpenDescriptor"; + public static final String FILE_TOTAL_DESCRIPTOR = "fileTotalDescriptor"; + public static final String CPU_LOAD_AVG_MIN_1 = "cpuLoadAvgMin_1"; + public static final String CPU_LOAD_AVG_MIN_5 = "cpuLoadAvgMin_5"; + public static final String CPU_LOAD_AVG_MIN_15 = "cpuLoadAvgMin_15"; + public static final String CPU_USAGE = "cpuUsage"; + public static final String PHYSICAL_CORES = "physical_cores"; + public static final String DISK_READ = "diskRead"; + public static final String DISK_WRITE = "diskWrite"; + + @Resource + private HostService hostService; + public PrometheusProxy( WebClient.Builder webClientBuilder, @Value("${monitoring.prometheus-host}") String prometheusHost) { this.webClient = webClientBuilder.baseUrl(prometheusHost).build(); } - - public JsonNode queryAgentsHealthyStatus() { + /** + * Retrieve current data + */ + public JsonNode query(String params) { Mono body = webClient .post() .uri(uriBuilder -> uriBuilder.path("/api/v1/query").build()) .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .body(BodyInserters.fromFormData("query", "up{job=\"%s\"}".formatted(agentHostJobName)) - .with("timeout", "10")) + .body(BodyInserters.fromFormData("query", params).with("timeout", "10")) .retrieve() .bodyToMono(JsonNode.class); JsonNode result = body.block(); - - ObjectMapper objectMapper = new ObjectMapper(); if (result == null || result.isEmpty() || !"success".equals(result.get("status").asText("failure"))) { - return objectMapper.createObjectNode(); + return null; } - JsonNode agents = result.get("data").get("result"); - ArrayNode agentsHealthyStatus = objectMapper.createArrayNode(); - for (JsonNode agent : agents) { - JsonNode agentStatus = agent.get("metric"); - ObjectNode temp = objectMapper.createObjectNode(); - temp.put("agentInfo", agentStatus.get("instance").asText()); - temp.put("prometheusAgentJob", agentStatus.get("job").asText()); - JsonNode status = agent.get("value"); - LocalDateTime instant = Instant.ofEpochSecond(status.get(0).asLong()) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(); - temp.put("time", instant.toString()); - temp.put("agentHealthyStatus", status.get(1).asInt() == 1 ? "running" : "down"); - agentsHealthyStatus.add(temp); + return result; + } + /** + * Retrieve data with a specified interval before the current time + */ + public JsonNode queryRange(String query, long start, long end, String step) { + Mono body = webClient + .post() + .uri(uriBuilder -> uriBuilder.path("/api/v1/query_range").build()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(BodyInserters.fromFormData("query", query) + .with("timeout", "10") + .with("start", String.valueOf(start)) + .with("end", String.valueOf(end)) + .with("step", step)) + .retrieve() + .bodyToMono(JsonNode.class); + JsonNode result = body.block(); + if (result == null + || result.isEmpty() + || !"success".equals(result.path("status").asText("failure"))) { + return null; } - return agentsHealthyStatus; + return result; } - private JsonNode queryAgents() { - JsonNode result = query("agent_host_monitoring_cpu"); + /** + * query agents healthy + */ + public JsonNode queryAgentsHealthyStatus() { + JsonNode result = query("up{job=\"%s\"}".formatted(agentHostJobName)); ObjectMapper objectMapper = new ObjectMapper(); + ArrayNode agentsHealthyStatus = objectMapper.createArrayNode(); if (result != null) { - JsonNode agentCpus = result.get("data").get("result"); - if (agentCpus.isArray() && !agentCpus.isEmpty()) { - Set iPv4addrSet = new HashSet<>(); - for (JsonNode agent : agentCpus) { - iPv4addrSet.add(agent.get("metric").get("iPv4addr").asText()); - } - ArrayNode iPv4addrArray = objectMapper.createArrayNode(); - for (String value : iPv4addrSet.toArray(new String[0])) { - iPv4addrArray.add(value); - } - return objectMapper.createObjectNode().set("iPv4addr", iPv4addrArray); // iPv4 + JsonNode agents = result.get("data").get("result"); + for (JsonNode agent : agents) { + JsonNode agentStatus = agent.get("metric"); + ObjectNode temp = objectMapper.createObjectNode(); + temp.put("agentInfo", agentStatus.get("instance").asText()); + temp.put("prometheusAgentJob", agentStatus.get("job").asText()); + JsonNode status = agent.get("value"); + LocalDateTime instant = Instant.ofEpochSecond(status.get(0).asLong()) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime(); + temp.put("time", instant.toString()); + temp.put("agentHealthyStatus", status.get(1).asInt() == 1 ? "running" : "down"); + agentsHealthyStatus.add(temp); } + return agentsHealthyStatus; } return objectMapper.createObjectNode(); } - - public JsonNode queryAgentsInfo() { + /** + * query agents info interval + */ + public JsonNode queryAgentsInfo(Long id, String interval) { ObjectMapper objectMapper = new ObjectMapper(); - ArrayNode agentsInfo = objectMapper.createArrayNode(); - JsonNode agents = queryAgents().get("iPv4addr"); // get all host - - for (JsonNode agent : agents) { - ObjectNode temp = objectMapper.createObjectNode(); - JsonNode cpuResult = queryAgentCpu(agent.asText()); - JsonNode memResult = queryAgentMemory(agent.asText()); - JsonNode diskResult = queryAgentDisk(agent.asText()); - // hostInfo - temp.put("hostname", cpuResult.get("hostname").asText()); - temp.put("iPv4addr", cpuResult.get("iPv4addr").asText()); - // temp.put("iPv6addr", cpuResult.get("iPv6addr").asText()); - temp.put("cpuInfo", cpuResult.get("cpuInfo").asText().strip()); - temp.put("time", cpuResult.get("time").asText()); - temp.put("os", cpuResult.get("os").asText()); - temp.put("architecture", cpuResult.get("architecture").asText()); - temp.put("physical_cores", cpuResult.get("physical_cores").asText()); - // MEM - temp.put("memIdle", memResult.get("memIdle").asLong()); - temp.put("memTotal", memResult.get("memTotal").asLong()); - // DISK - temp.set("diskSpace", diskResult.get("diskInfo")); - agentsInfo.add(temp); - } + String agentIpv4 = hostService.get(id).getIpv4(); + if (!Objects.equals(agentIpv4, "")) { + ObjectNode ag = objectMapper.createObjectNode(); + double[] agentsCpuUsage = new double[6]; + double[] agentsCpuLoad1 = new double[6]; + double[] agentsCpuLoad2 = new double[6]; + double[] agentsCpuLoad3 = new double[6]; + long[] agentMemIdle = new long[6]; + long[] agentMemTotal = new long[6]; + long[] agentDiskRead = new long[6]; + long[] agentDiskWrite = new long[6]; - return agentsInfo; - } + JsonNode agentCpu = retrieveAgentCpu(agentIpv4); + JsonNode agentMem = retrieveAgentMemory(agentIpv4); + JsonNode agentDisk = retrieveAgentDisk(agentIpv4); + JsonNode agentDiskIO = retrieveAgentDiskIO(agentIpv4); + JsonNode agentCpuInterval = retrieveAgentCpu(agentIpv4, interval); + JsonNode agentMemInterval = retrieveAgentMemory(agentIpv4, interval); + JsonNode agentDiskIOInterval = retrieveAgentDiskIO(agentIpv4, interval); - public JsonNode queryAgentsInstStatus() { - ObjectMapper objectMapper = new ObjectMapper(); - ArrayNode agentsInfo = objectMapper.createArrayNode(); - JsonNode agents = queryAgents().get("iPv4addr"); // get all host - - for (JsonNode agent : agents) { - JsonNode cpuResult = queryAgentCpu(agent.asText()); - JsonNode memResult = queryAgentMemory(agent.asText()); - JsonNode diskResult = queryAgentDisk(agent.asText()); - JsonNode diskIOResult = queryAgentDiskIO(agent.asText()); - ObjectNode temp = objectMapper.createObjectNode(); - - // hostInfo - temp.put("hostname", cpuResult.get("hostname").asText()); - temp.put("iPv4addr", cpuResult.get("iPv4addr").asText()); - temp.put("cpuInfo", cpuResult.get("cpuInfo").asText().strip()); - temp.put("time", cpuResult.get("time").asText()); - temp.put("cpuLoadAvgMin_1", cpuResult.get("cpuLoadAvgMin_1").asDouble()); - temp.put("cpuLoadAvgMin_5", cpuResult.get("cpuLoadAvgMin_5").asDouble()); - temp.put("cpuLoadAvgMin_15", cpuResult.get("cpuLoadAvgMin_15").asDouble()); - temp.put("cpuUsage", cpuResult.get("cpuUsage").asDouble()); - temp.put("fileTotalDescriptor", cpuResult.get("fileTotalDescriptor").asLong()); - temp.put("fileOpenDescriptor", cpuResult.get("fileOpenDescriptor").asLong()); - // MEM - temp.put("memIdle", memResult.get("memIdle").asLong()); - temp.put("memTotal", memResult.get("memTotal").asLong()); - // DISK - temp.set("diskSpace", diskResult.get("diskInfo")); - // DISK IO - temp.set("diskIO", diskIOResult.get("diskIO")); - agentsInfo.add(temp); - } + // data process + for (int i = 0; i < 6; i++) { + // CPU + agentsCpuUsage[i] = ProxyUtils.getDoubleSafely(agentCpuInterval, CPU_USAGE, i); + agentsCpuLoad1[i] = ProxyUtils.getDoubleSafely(agentCpuInterval, CPU_LOAD_AVG_MIN_1, i); + agentsCpuLoad2[i] = ProxyUtils.getDoubleSafely(agentCpuInterval, CPU_LOAD_AVG_MIN_5, i); + agentsCpuLoad3[i] = ProxyUtils.getDoubleSafely(agentCpuInterval, CPU_LOAD_AVG_MIN_15, i); + + // MEM + agentMemIdle[i] = ProxyUtils.getLongSafely(agentMemInterval, MEM_IDLE, i); + agentMemTotal[i] = ProxyUtils.getLongSafely(agentMemInterval, MEM_TOTAL, i); + + // DISK IO + agentDiskRead[i] = ProxyUtils.getLongSafely(agentDiskIOInterval, DISK_READ, i); + agentDiskWrite[i] = ProxyUtils.getLongSafely(agentDiskIOInterval, DISK_WRITE, i); + } - return agentsInfo; + // cur + ag.put("cpuUsageCur", String.format("%.6f", agentCpu.get(CPU_USAGE).asDouble())); + ag.put( + "memoryUsageCur", + String.format( + "%.6f", + (double) (agentMem.get(MEM_TOTAL).asLong() + - agentMem.get(MEM_IDLE).asLong()) + / agentMem.get(MEM_TOTAL).asLong())); + ag.put( + "diskUsageCur", + String.format( + "%.6f", + (double) (agentDisk.get(DISK_TOTAL).asLong() + - agentDisk.get(DISK_IDLE).asLong()) + / agentDisk.get(DISK_TOTAL).asLong())); + ag.put( + "fileDescriptorUsage", + String.format( + "%.6f", + (double) agentCpu.get(FILE_OPEN_DESCRIPTOR).asLong() + / agentCpu.get(FILE_TOTAL_DESCRIPTOR).asLong())); + ag.put("diskReadCur", agentDiskIO.get(DISK_READ).asLong()); + ag.put("diskWriteCur", agentDiskIO.get(DISK_WRITE).asLong()); + + // interval + ag.set("cpuUsage", ProxyUtils.array2node(agentsCpuUsage)); + ag.set("systemLoad1", ProxyUtils.array2node(agentsCpuLoad1)); + ag.set("systemLoad2", ProxyUtils.array2node(agentsCpuLoad2)); + ag.set("systemLoad3", ProxyUtils.array2node(agentsCpuLoad3)); + ag.set("memoryUsage", ProxyUtils.array2node(agentMemIdle, agentMemTotal)); + ag.set("diskRead", ProxyUtils.array2node(agentDiskRead)); + ag.set("diskWrite", ProxyUtils.array2node(agentDiskWrite)); + + return ag; + } + return objectMapper.createObjectNode(); } + /** + * query clusters info interval + */ + public JsonNode queryClustersInfo(Long clusterId, String interval) { + HostQuery hostQuery = new HostQuery(); + hostQuery.setClusterId(clusterId); + PageVO hostPage = hostService.list(hostQuery); // query host list + List hostList = hostPage.getContent(); + int agentsNum = Math.toIntExact(hostPage.getTotal()); // change to agentsNum + ObjectMapper objectMapper = new ObjectMapper(); + if (agentsNum > 0) { + int totalPhysicalCores = 0; + long totalMemSpace = 0L, totalMemIdle = 0L; + double instantCpuUsage = 0.0; + double[][] agentsCpuUsage = new double[agentsNum][6]; + double[][] agentsCpuLoad1 = new double[agentsNum][6]; + double[][] agentsCpuLoad2 = new double[agentsNum][6]; + double[][] agentsCpuLoad3 = new double[agentsNum][6]; + long[][] agentMemIdle = new long[agentsNum][6]; + long[][] agentMemTotal = new long[agentsNum][6]; - public JsonNode query(String params) { - Mono body = webClient - .post() - .uri("/api/v1/query") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .body(BodyInserters.fromFormData("query", params).with("timeout", "10")) - .retrieve() - .bodyToMono(JsonNode.class); - JsonNode result = body.block(); - if (result == null - || result.isEmpty() - || !"success".equals(result.get("status").asText("failure"))) { - return null; + int agentIndex = 0; + ObjectNode clusterInfo = objectMapper.createObjectNode(); + for (HostVO hostVO : hostList) { + String agentIpv4 = hostVO.getIpv4(); + JsonNode agentCpu = retrieveAgentCpu(agentIpv4); + instantCpuUsage += agentCpu.get("cpuUsage").asDouble() + * agentCpu.get(PHYSICAL_CORES).asInt(); + JsonNode agentMem = retrieveAgentMemory(agentIpv4); + totalMemIdle += agentMem.get("memIdle").asLong(); + totalMemSpace += agentMem.get(("memTotal")).asLong(); + JsonNode agentCpuStep = retrieveAgentCpu(agentIpv4, interval); + JsonNode agentMemStep = retrieveAgentMemory(agentIpv4, interval); + int agentPhysicalCores = agentCpu.get(PHYSICAL_CORES).asInt(); + totalPhysicalCores += agentPhysicalCores; + + for (int i = 0; i < 6; i++) { + // CPU + agentsCpuUsage[agentIndex][i] = + ProxyUtils.getDoubleSafely(agentCpuStep, CPU_USAGE, i) * agentPhysicalCores; + agentsCpuLoad1[agentIndex][i] = + ProxyUtils.getDoubleSafely(agentCpuStep, CPU_LOAD_AVG_MIN_1, i) * agentPhysicalCores; + agentsCpuLoad2[agentIndex][i] = + ProxyUtils.getDoubleSafely(agentCpuStep, CPU_LOAD_AVG_MIN_5, i) * agentPhysicalCores; + agentsCpuLoad3[agentIndex][i] = + ProxyUtils.getDoubleSafely(agentCpuStep, CPU_LOAD_AVG_MIN_15, i) * agentPhysicalCores; + + // MEM + agentMemIdle[agentIndex][i] = ProxyUtils.getLongSafely(agentMemStep, MEM_IDLE, i); + agentMemTotal[agentIndex][i] = ProxyUtils.getLongSafely(agentMemStep, MEM_TOTAL, i); + } + + agentIndex++; // loop of agents + } + // cur + clusterInfo.put("cpuUsageCur", String.format("%.6f", instantCpuUsage / totalPhysicalCores)); + clusterInfo.put( + "memoryUsageCur", String.format("%.6f", (double) (totalMemSpace - totalMemIdle) / totalMemSpace)); + + // interval + clusterInfo.set("cpuUsage", ProxyUtils.array2node(agentsCpuUsage, totalPhysicalCores, agentsNum)); + clusterInfo.set("systemLoad1", ProxyUtils.array2node(agentsCpuLoad1, totalPhysicalCores, agentsNum)); + clusterInfo.set("systemLoad2", ProxyUtils.array2node(agentsCpuLoad2, totalPhysicalCores, agentsNum)); + clusterInfo.set("systemLoad3", ProxyUtils.array2node(agentsCpuLoad3, totalPhysicalCores, agentsNum)); + clusterInfo.set("memoryUsage", ProxyUtils.array2node(agentMemIdle, agentMemTotal, agentsNum)); + + return clusterInfo; } - return result; + return objectMapper.createObjectNode(); } - public JsonNode queryAgentCpu(String iPv4addr) { + /** + * retrieve cpu + */ + public JsonNode retrieveAgentCpu(String iPv4addr) { String params = String.format("agent_host_monitoring_cpu{iPv4addr=\"%s\"}", iPv4addr); JsonNode result = query(params); ObjectMapper objectMapper = new ObjectMapper(); if (result != null) { JsonNode agentCpus = result.get("data").get("result"); if (agentCpus.isArray() && !agentCpus.isEmpty()) { + // metric JsonNode agentCpuMetric = agentCpus.get(0).get("metric"); - JsonNode agentCpuValue = agentCpus.get(0).get("value"); ObjectNode agentInfo = objectMapper.createObjectNode(); agentInfo.put("hostname", agentCpuMetric.get("hostname").asText()); agentInfo.put("cpuInfo", agentCpuMetric.get("cpu_info").asText()); agentInfo.put("iPv4addr", agentCpuMetric.get("iPv4addr").asText()); - // temp.put("iPv6addr", agentCpuMetric.get("iPv6addr").asText()); agentInfo.put("os", agentCpuMetric.get("os").asText()); agentInfo.put("architecture", agentCpuMetric.get("arch").asText()); + agentInfo.put(PHYSICAL_CORES, agentCpuMetric.get(PHYSICAL_CORES).asText()); agentInfo.put( - "physical_cores", agentCpuMetric.get("physical_cores").asText()); + FILE_OPEN_DESCRIPTOR, + agentCpuMetric.get(FILE_OPEN_DESCRIPTOR).asLong()); agentInfo.put( - "fileOpenDescriptor", - agentCpuMetric.get("fileOpenDescriptor").asLong()); - agentInfo.put( - "fileTotalDescriptor", - agentCpuMetric.get("fileTotalDescriptor").asLong()); - LocalDateTime instant = Instant.ofEpochSecond( - agentCpuValue.get(0).asLong()) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(); - agentInfo.put("time", instant.toString()); + FILE_TOTAL_DESCRIPTOR, + agentCpuMetric.get(FILE_TOTAL_DESCRIPTOR).asLong()); + + // value for (JsonNode agent : agentCpus) { agentInfo.put( agent.get("metric").get("cpuUsage").asText(), - agent.get("value").get(1).asDouble()); // cpu metric + agent.get("value").get(1).asDouble()); } return agentInfo; } } return objectMapper.createObjectNode(); } - - public JsonNode queryAgentMemory(String iPv4addr) { + /** + * retrieve cpu interval + */ + public JsonNode retrieveAgentCpu(String iPv4addr, String interval) { + String params = String.format("agent_host_monitoring_cpu{iPv4addr=\"%s\"}", iPv4addr); + ArrayList timeStampsList = ProxyUtils.getTimeStampsList(ProxyUtils.processInternal(interval)); + JsonNode result = queryRange( + params, + timeStampsList.get(timeStampsList.size() - 1), + timeStampsList.get(0), + ProxyUtils.Number2Param(ProxyUtils.processInternal(interval))); // end start ObjectMapper objectMapper = new ObjectMapper(); + if (result != null) { + JsonNode agentCpu = result.get("data").get("result"); + if (agentCpu.isArray() && !agentCpu.isEmpty()) { + ObjectNode agentCpuInfo = objectMapper.createObjectNode(); + // metric + JsonNode agentCpuMetrics = agentCpu.get(0).get("metric"); + agentCpuInfo.put("hostname", agentCpuMetrics.get("hostname").asText()); + agentCpuInfo.put("cpuInfo", agentCpuMetrics.get("cpu_info").asText()); + agentCpuInfo.put("iPv4addr", agentCpuMetrics.get("iPv4addr").asText()); + agentCpuInfo.put("os", agentCpuMetrics.get("os").asText()); + agentCpuInfo.put("architecture", agentCpuMetrics.get("arch").asText()); + agentCpuInfo.put( + PHYSICAL_CORES, agentCpuMetrics.get(PHYSICAL_CORES).asInt()); + agentCpuInfo.put( + FILE_OPEN_DESCRIPTOR, + agentCpuMetrics.get(FILE_OPEN_DESCRIPTOR).asLong()); + agentCpuInfo.put( + FILE_TOTAL_DESCRIPTOR, + agentCpuMetrics.get(FILE_TOTAL_DESCRIPTOR).asLong()); + + // value + for (JsonNode cpuType : agentCpu) { + JsonNode agentCpuValues = cpuType.get("values"); + ArrayNode cpuValues = objectMapper.createArrayNode(); + for (JsonNode stepValue : agentCpuValues) { + cpuValues.add(stepValue.get(1).asDouble()); + } + agentCpuInfo.set(cpuType.get("metric").get("cpuUsage").asText(), cpuValues); + } + return agentCpuInfo; + } + } + return objectMapper.createObjectNode(); + } + + /** + * retrieve memory + */ + public JsonNode retrieveAgentMemory(String iPv4addr) { String query = String.format("agent_host_monitoring_mem{iPv4addr=\"%s\"}", iPv4addr); JsonNode result = query(query); + ObjectMapper objectMapper = new ObjectMapper(); if (result != null) { JsonNode agentsMem = result.get("data").get("result"); if (agentsMem.isArray() && !agentsMem.isEmpty()) { - JsonNode agentMemValue = agentsMem.get(0).get("value"); + ObjectNode agentsMemInfo = objectMapper.createObjectNode(); + // metric JsonNode agentMemMetric = agentsMem.get(0).get("metric"); - ObjectNode agentsInfo = objectMapper.createObjectNode(); - agentsInfo.put("hostname", agentMemMetric.get("hostname").asText()); - agentsInfo.put("iPv4addr", agentMemMetric.get("iPv4addr").asText()); - LocalDateTime instant = Instant.ofEpochSecond( - agentMemValue.get(0).asLong()) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(); - agentsInfo.put("time", instant.toString()); + agentsMemInfo.put("hostname", agentMemMetric.get("hostname").asText()); + agentsMemInfo.put("iPv4addr", agentMemMetric.get("iPv4addr").asText()); for (JsonNode agent : agentsMem) { - agentsInfo.put( + agentsMemInfo.put( agent.get("metric").get("memUsage").asText(), agent.get("value").get(1).asLong()); // mem metric } - return agentsInfo; + return agentsMemInfo; } } return objectMapper.createObjectNode(); } - - public JsonNode queryAgentDisk(String iPv4addr) { + /** + * retrieve memory interval + */ + public JsonNode retrieveAgentMemory(String iPv4addr, String interval) { + String params = String.format("agent_host_monitoring_mem{iPv4addr=\"%s\"}", iPv4addr); + ArrayList timeStampsList = ProxyUtils.getTimeStampsList(ProxyUtils.processInternal(interval)); + JsonNode result = queryRange( + params, + timeStampsList.get(timeStampsList.size() - 1), + timeStampsList.get(0), + ProxyUtils.Number2Param(ProxyUtils.processInternal(interval))); ObjectMapper objectMapper = new ObjectMapper(); + if (result != null) { + JsonNode agentMem = result.get("data").get("result"); + if (agentMem.isArray() && !agentMem.isEmpty()) { + ObjectNode agentMemInfo = objectMapper.createObjectNode(); + // metric + JsonNode agentMemMetrics = agentMem.get(0).get("metric"); + agentMemInfo.put("hostname", agentMemMetrics.get("hostname").asText()); + agentMemInfo.put("iPv4addr", agentMemMetrics.get("iPv4addr").asText()); + + // value + for (JsonNode stepAgent : agentMem) { + JsonNode agentMemValues = stepAgent.get("values"); + ArrayNode memValues = objectMapper.createArrayNode(); + for (JsonNode value : agentMemValues) { + memValues.add(value.get(1).asDouble()); + } + agentMemInfo.set(stepAgent.get("metric").get("memUsage").asText(), memValues); + } + return agentMemInfo; + } + } + return objectMapper.createObjectNode(); + } + + /** + * retrieve diskInfo + */ + public JsonNode retrieveAgentDisk(String iPv4addr) { String params = String.format("agent_host_monitoring_disk{iPv4addr=\"%s\"}", iPv4addr); JsonNode result = query(params); + ObjectMapper objectMapper = new ObjectMapper(); if (result != null) { JsonNode agentDisksResult = result.get("data").get("result"); if (agentDisksResult.isArray() && !agentDisksResult.isEmpty()) { - JsonNode agentDisksMetric = agentDisksResult.get(0).get("metric"); - JsonNode agentDisksValue = agentDisksResult.get(0).get("value"); ObjectNode agentDiskInfo = objectMapper.createObjectNode(); + // metric + JsonNode agentDisksMetric = agentDisksResult.get(0).get("metric"); agentDiskInfo.put("hostname", agentDisksMetric.get("hostname").asText()); agentDiskInfo.put("iPv4addr", agentDisksMetric.get("iPv4addr").asText()); - LocalDateTime instant = Instant.ofEpochSecond( - agentDisksValue.get(0).asLong()) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(); - agentDiskInfo.put("time", instant.toString()); - - ArrayNode tempDiskInfo = objectMapper.createArrayNode(); - for (JsonNode agent : agentDisksResult) { - JsonNode agentDisk = agent.get("metric"); - ObjectNode temp = objectMapper.createObjectNode(); - temp.put("diskName", agentDisk.get("diskUsage").asText()); - temp.put("diskUsage", agentDisk.get("diskUsage").asText()); - temp.put("diskValue", agent.get("value").get(1).asLong()); - tempDiskInfo.add(temp); + + // value + Long diskTotalSpace = 0L, diskFreeSpace = 0L; + for (JsonNode disk : agentDisksResult) { + if (Objects.equals(disk.get("metric").get("diskUsage").asText(), DISK_IDLE)) { + diskFreeSpace += disk.get("value").get(1).asLong(); + } else { + diskTotalSpace += disk.get("value").get(1).asLong(); + } } - agentDiskInfo.set("diskInfo", tempDiskInfo); + agentDiskInfo.put(DISK_TOTAL, diskTotalSpace); + agentDiskInfo.put(DISK_IDLE, diskFreeSpace); return agentDiskInfo; } } return objectMapper.createObjectNode(); } - public JsonNode queryAgentDiskIO(String iPv4addr) { - ObjectMapper objectMapper = new ObjectMapper(); + /** + * retrieve diskIO + */ + public JsonNode retrieveAgentDiskIO(String iPv4addr) { String params = String.format("agent_host_monitoring_diskIO{iPv4addr=\"%s\"}", iPv4addr); JsonNode result = query(params); + ObjectMapper objectMapper = new ObjectMapper(); if (result != null) { JsonNode agentDisksResult = result.get("data").get("result"); if (agentDisksResult.isArray() && !agentDisksResult.isEmpty()) { - JsonNode agentDisksValue = agentDisksResult.get(0).get("value"); + ObjectNode agentDiskIOInfo = objectMapper.createObjectNode(); + // metric JsonNode agentDisksMetric = agentDisksResult.get(0).get("metric"); + agentDiskIOInfo + .put("hostname", agentDisksMetric.get("hostname").asText()) + .put("iPv4addr", agentDisksMetric.get("iPv4addr").asText()); + + // value + long diskWrite = 0L; + long diskRead = 0L; + for (JsonNode disk : agentDisksResult) { + if (Objects.equals(disk.get("metric").get("diskIO").asText(), DISK_WRITE)) { + diskWrite += disk.get("value").get(1).asLong(); + } else { + diskRead += disk.get("value").get(1).asLong(); + } + } + agentDiskIOInfo.put(DISK_WRITE, diskWrite); + agentDiskIOInfo.put(DISK_READ, diskRead); + return agentDiskIOInfo; + } + } + return objectMapper.createObjectNode(); + } + + /** + * retrieve diskIO interval + */ + public JsonNode retrieveAgentDiskIO(String iPv4addr, String interval) { + String params = String.format("agent_host_monitoring_diskIO{iPv4addr=\"%s\"}", iPv4addr); + ArrayList timeStampsList = ProxyUtils.getTimeStampsList(ProxyUtils.processInternal(interval)); + JsonNode result = queryRange( + params, + timeStampsList.get(timeStampsList.size() - 1), + timeStampsList.get(0), + ProxyUtils.Number2Param(ProxyUtils.processInternal(interval))); + ObjectMapper objectMapper = new ObjectMapper(); + if (result != null) { + JsonNode agentDisksResult = result.get("data").get("result"); + if (agentDisksResult.isArray() && !agentDisksResult.isEmpty()) { ObjectNode agentDiskIOInfo = objectMapper.createObjectNode(); + // metric + JsonNode agentDisksMetric = agentDisksResult.get(0).get("metric"); agentDiskIOInfo .put("hostname", agentDisksMetric.get("hostname").asText()) .put("iPv4addr", agentDisksMetric.get("iPv4addr").asText()); - LocalDateTime instant = Instant.ofEpochSecond( - agentDisksValue.get(0).asLong()) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(); - agentDiskIOInfo.put("time", instant.toString()); - - ArrayNode tempDiskInfo = objectMapper.createArrayNode(); - for (JsonNode agent : agentDisksResult) { - JsonNode agentDisk = agent.get("metric"); - ObjectNode temp = objectMapper.createObjectNode(); - temp.put( - "physicalDiskName", - agentDisk.get("physicalDiskName").asText()); - temp.put("physicalDiskUsage", agentDisk.get("diskIO").asText()); - if (Objects.equals(agentDisk.get("diskIO").asText(), "physicalDiskWrite")) { - temp.put("physicalDiskWrite", agent.get("value").get(1).asLong()); + + // value + long[] diskWrite = new long[6]; + long[] diskRead = new long[6]; + for (JsonNode disk : agentDisksResult) { + if (Objects.equals(disk.get("metric").get("diskIO").asText(), DISK_WRITE)) { + for (int i = 0; i < 6; i++) { + JsonNode listNode = disk.get("values"); + if (listNode != null && listNode.isArray() && i < listNode.size()) + diskWrite[i] += listNode.get(i).get(1).asLong(); + else diskWrite[i] += 0L; + } } else { - temp.put("physicalDiskRead", agent.get("value").get(1).asLong()); + for (int i = 0; i < 6; i++) { + JsonNode listNode = disk.get("values"); + if (listNode != null && listNode.isArray() && i < listNode.size()) + diskRead[i] += listNode.get(i).get(1).asLong(); + else diskRead[i] += 0L; + } } - tempDiskInfo.add(temp); } - agentDiskIOInfo.set("diskIO", tempDiskInfo); + agentDiskIOInfo.set(DISK_WRITE, ProxyUtils.array2node(diskWrite)); + agentDiskIOInfo.set(DISK_READ, ProxyUtils.array2node(diskRead)); return agentDiskIOInfo; } } diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MonitoringService.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java similarity index 86% rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MonitoringService.java rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java index ce6f82d4..23327b17 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MonitoringService.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java @@ -20,11 +20,11 @@ import com.fasterxml.jackson.databind.JsonNode; -public interface MonitoringService { +public interface MetricsService { JsonNode queryAgentsHealthyStatus(); - JsonNode queryAgentsInfo(); + JsonNode queryAgentsInfo(Long id, String interval); - JsonNode queryAgentsInstStatus(); + JsonNode queryClustersInfo(Long clusterId, String interval); } diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MonitoringServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java similarity index 77% rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MonitoringServiceImpl.java rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java index 38dde151..dff7728a 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MonitoringServiceImpl.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java @@ -19,7 +19,7 @@ package org.apache.bigtop.manager.server.service.impl; import org.apache.bigtop.manager.server.proxy.PrometheusProxy; -import org.apache.bigtop.manager.server.service.MonitoringService; +import org.apache.bigtop.manager.server.service.MetricsService; import org.springframework.stereotype.Service; @@ -30,7 +30,7 @@ @Slf4j @Service -public class MonitoringServiceImpl implements MonitoringService { +public class MetricsServiceImpl implements MetricsService { @Resource private PrometheusProxy prometheusProxy; @@ -41,12 +41,12 @@ public JsonNode queryAgentsHealthyStatus() { } @Override - public JsonNode queryAgentsInfo() { - return prometheusProxy.queryAgentsInfo(); + public JsonNode queryAgentsInfo(Long id, String interval) { + return prometheusProxy.queryAgentsInfo(id, interval); } @Override - public JsonNode queryAgentsInstStatus() { - return prometheusProxy.queryAgentsInstStatus(); + public JsonNode queryClustersInfo(Long clusterId, String interval) { + return prometheusProxy.queryClustersInfo(clusterId, interval); } } diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/ProxyUtils.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/ProxyUtils.java new file mode 100644 index 00000000..46b95d40 --- /dev/null +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/ProxyUtils.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.bigtop.manager.server.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; + +public class ProxyUtils { + public static double getDoubleSafely(JsonNode parentNode, String key, int index) { + JsonNode listNode = parentNode.get(key); + if (listNode != null && listNode.isArray() && index < listNode.size()) + return listNode.get(index).asDouble(); + return 0.0; + } + + public static Long getLongSafely(JsonNode parentNode, String key, int index) { + JsonNode listNode = parentNode.get(key); + if (listNode != null && listNode.isArray() && index < listNode.size()) + return listNode.get(index).asLong(); + return 0L; + } + + public static JsonNode array2node(double[][] array, int cores, int num) { + ObjectMapper mapper = new ObjectMapper(); + double[] cache = new double[6]; + for (int i = 0; i < num; i++) for (int j = 0; j < 6; j++) cache[j] += array[i][j]; + ArrayNode node = mapper.createArrayNode(); + for (int j = 0; j < 6; j++) node.add(String.format("%.6f", cache[j] / cores)); + return node; + } + + public static JsonNode array2node(double[] array) { + ArrayNode node = new ObjectMapper().createArrayNode(); + for (int j = 0; j < 6; j++) node.add(String.format("%.6f", array[j])); + return node; + } + + public static JsonNode array2node(long[] array) { + ArrayNode node = new ObjectMapper().createArrayNode(); + for (int j = 0; j < 6; j++) node.add(array[j]); + return node; + } + + public static JsonNode array2node(long[] array1, long[] array2) { + ArrayNode node = new ObjectMapper().createArrayNode(); + for (int j = 0; j < 6; j++) + if (array2[j] <= 0) node.add(String.format("%.6f", 0.0)); + else node.add(String.format("%.6f", (double) (array2[j] - array1[j]) / array2[j])); + return node; + } + + public static JsonNode array2node(long[][] array1, long[][] array2, int num) { + ObjectMapper mapper = new ObjectMapper(); + long[] cache1 = new long[6]; + long[] cache2 = new long[6]; + for (int i = 0; i < num; i++) { + for (int j = 0; j < 6; j++) { + cache1[j] += array1[i][j]; + cache2[j] += array2[i][j]; + } + } + ArrayNode node = mapper.createArrayNode(); + // The data is sorted with earlier dates coming first and later dates following. + for (int j = 0; j < 6; j++) + if (cache2[j] <= 0) node.add(String.format("%.6f", 0.0)); + else node.add(String.format("%.6f", (double) (cache2[j] - cache1[j]) / cache2[j])); + return node; + } + + public static ArrayList getTimeStampsList(int step) { + // format + String currentTimeStr = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); + String currentDateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime currentDateTime = LocalDateTime.parse(currentDateStr + " " + currentTimeStr, formatter); + int roundedMinute = (currentDateTime.getMinute() / step) * step; + LocalDateTime roundedCurrentDateTime = + currentDateTime.withMinute(roundedMinute).withSecond(0).withNano(0); + // get 8 point + ArrayList timestamps = new ArrayList<>(); + ZoneId zid = ZoneId.systemDefault(); + for (int i = 0; i < 7; i++) { + LocalDateTime pastTime = roundedCurrentDateTime.minus(Duration.ofMinutes((long) step * i)); + long timestamp = pastTime.atZone(zid).toInstant().toEpochMilli() / 1000L; + timestamps.add(timestamp); + } + return timestamps; + } + + public static String Number2Param(int step) { + return String.format("%sm", step); + } + + public static int processInternal(String internal) { + int inter = Integer.parseInt(internal.substring(0, internal.length() - 1)); + if (internal.endsWith("m")) return inter * 60; + else if (internal.endsWith("h")) { + return inter * 60 * 60; + } + return inter; + } +} diff --git a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MonitoringControllerTest.java b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MetricsControllerTest.java similarity index 82% rename from bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MonitoringControllerTest.java rename to bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MetricsControllerTest.java index cc391a17..6e760c9b 100644 --- a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MonitoringControllerTest.java +++ b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MetricsControllerTest.java @@ -18,7 +18,7 @@ */ package org.apache.bigtop.manager.server.controller; -import org.apache.bigtop.manager.server.service.MonitoringService; +import org.apache.bigtop.manager.server.service.MetricsService; import org.apache.bigtop.manager.server.utils.MessageSourceUtils; import org.apache.bigtop.manager.server.utils.ResponseEntity; @@ -42,13 +42,13 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -class MonitoringControllerTest { +class MetricsControllerTest { @Mock - private MonitoringService monitoringService; + private MetricsService metricsService; @InjectMocks - private MonitoringController monitoringController; + private MetricsController metricsController; private MockedStatic mockedMessageSourceUtils; @@ -66,9 +66,9 @@ void tearDown() { @Test void agentHostsHealthyStatusReturnsSuccess() { JsonNode mockResponse = new ObjectMapper().createObjectNode(); - when(monitoringService.queryAgentsHealthyStatus()).thenReturn(mockResponse); + when(metricsService.queryAgentsHealthyStatus()).thenReturn(mockResponse); - ResponseEntity response = monitoringController.agentHostsHealthyStatus(); + ResponseEntity response = metricsController.agentHostsHealthyStatus(); assertTrue(response.isSuccess()); assertEquals(mockResponse, response.getData()); @@ -76,9 +76,9 @@ void agentHostsHealthyStatusReturnsSuccess() { @Test void agentHostsHealthyStatusReturnsEmptyResponse() { - when(monitoringService.queryAgentsHealthyStatus()).thenReturn(null); + when(metricsService.queryAgentsHealthyStatus()).thenReturn(null); - ResponseEntity response = monitoringController.agentHostsHealthyStatus(); + ResponseEntity response = metricsController.agentHostsHealthyStatus(); assertTrue(response.isSuccess()); assertNull(response.getData());