This is an automated email from the ASF dual-hosted git repository.

liuhaopeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git


The following commit(s) were added to refs/heads/main by this push:
     new 2b1da68e BIGTOP-4464: Optimize cluster/host metrics structure (#240)
2b1da68e is described below

commit 2b1da68e2526d33c8f9d0b27edb6f4941d547e16
Author: Zhiguo Wu <[email protected]>
AuthorDate: Fri Jul 11 23:17:21 2025 +0800

    BIGTOP-4464: Optimize cluster/host metrics structure (#240)
---
 .../agent/grpc/interceptor/TaskInterceptor.java    |  18 +-
 .../bigtop/manager/dao/repository/ServiceDao.java  |   2 +
 .../main/resources/mapper/mysql/ClusterMapper.xml  |   3 +-
 .../main/resources/mapper/mysql/ServiceMapper.xml  |   8 +
 .../resources/mapper/postgresql/ClusterMapper.xml  |   3 +-
 .../resources/mapper/postgresql/ServiceMapper.xml  |   8 +
 .../command/helper/ComponentStageHelper.java       |   4 +-
 .../server/controller/MetricsController.java       |  27 +-
 .../model/req/command/ServiceCommandReq.java       |   2 +-
 .../vo/ClusterMetricsVO.java}                      |  16 +-
 .../vo/HostMetricsVO.java}                         |  25 +-
 .../PrometheusData.java}                           |  14 +-
 .../manager/server/prometheus/PrometheusProxy.java | 490 ++++++++++++++++++
 .../PrometheusResponse.java}                       |  20 +-
 .../PrometheusResult.java}                         |  20 +-
 .../manager/server/proxy/PrometheusProxy.java      | 547 ---------------------
 .../manager/server/service/MetricsService.java     |   9 +-
 .../server/service/impl/ClusterServiceImpl.java    |   3 +-
 .../server/service/impl/MetricsServiceImpl.java    |  24 +-
 .../bigtop/manager/server/utils/ProxyUtils.java    | 127 -----
 .../server/controller/MetricsControllerTest.java   |  35 +-
 .../manager/server/service/ClusterServiceTest.java |   5 +-
 .../manager/server/utils/ProxyUtilsTest.java       | 217 --------
 23 files changed, 641 insertions(+), 986 deletions(-)

diff --git 
a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/interceptor/TaskInterceptor.java
 
b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/interceptor/TaskInterceptor.java
index 43f382ed..6d741433 100644
--- 
a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/interceptor/TaskInterceptor.java
+++ 
b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/interceptor/TaskInterceptor.java
@@ -43,11 +43,15 @@ public class TaskInterceptor implements ServerInterceptor {
     public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
             ServerCall<ReqT, RespT> call, Metadata headers, 
ServerCallHandler<ReqT, RespT> next) {
         return new 
ForwardingServerCallListener.SimpleForwardingServerCallListener<>(next.startCall(call,
 headers)) {
+
+            private boolean taskRequest = false;
+
             @Override
             public void onMessage(ReqT message) {
                 super.onMessage(message);
+                taskRequest = isTaskRequest(message);
 
-                if (isTaskRequest(message)) {
+                if (taskRequest) {
                     try {
                         Method method = 
message.getClass().getDeclaredMethod("getTaskId");
                         Long taskId = (Long) method.invoke(message);
@@ -69,16 +73,20 @@ public class TaskInterceptor implements ServerInterceptor {
             public void onCancel() {
                 super.onCancel();
 
-                Caches.RUNNING_TASK = null;
-                MDC.clear();
+                if (taskRequest) {
+                    Caches.RUNNING_TASK = null;
+                    MDC.clear();
+                }
             }
 
             @Override
             public void onComplete() {
                 super.onComplete();
 
-                Caches.RUNNING_TASK = null;
-                MDC.clear();
+                if (taskRequest) {
+                    Caches.RUNNING_TASK = null;
+                    MDC.clear();
+                }
             }
 
             @Override
diff --git 
a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ServiceDao.java
 
b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ServiceDao.java
index 06a26808..accbdd40 100644
--- 
a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ServiceDao.java
+++ 
b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ServiceDao.java
@@ -30,6 +30,8 @@ public interface ServiceDao extends BaseDao<ServicePO> {
 
     List<ServicePO> findByQuery(@Param("query") ServiceQuery query);
 
+    int countByClusterId(@Param("clusterId") Long clusterId);
+
     List<ServicePO> findByClusterId(@Param("clusterId") Long clusterId);
 
     ServicePO findByClusterIdAndName(@Param("clusterId") Long clusterId, 
@Param("name") String name);
diff --git 
a/bigtop-manager-dao/src/main/resources/mapper/mysql/ClusterMapper.xml 
b/bigtop-manager-dao/src/main/resources/mapper/mysql/ClusterMapper.xml
index df0035bc..80774122 100644
--- a/bigtop-manager-dao/src/main/resources/mapper/mysql/ClusterMapper.xml
+++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/ClusterMapper.xml
@@ -36,11 +36,10 @@
             <property name="alias" value="c"/>
         </include>, u.nickname as create_user,
         count(h.id) as total_host, sum(h.available_processors) as 
total_processor,
-        sum(h.total_memory_size) as total_memory, sum(h.total_disk) as 
total_disk, count(s.id) as total_service
+        sum(h.total_memory_size) as total_memory, sum(h.total_disk) as 
total_disk
         from
         cluster c left join user u on c.create_by = u.id
         left join host h on c.id = h.cluster_id
-        left join service s on c.id = s.cluster_id
         where c.id = #{id}
         limit 1
     </select>
diff --git 
a/bigtop-manager-dao/src/main/resources/mapper/mysql/ServiceMapper.xml 
b/bigtop-manager-dao/src/main/resources/mapper/mysql/ServiceMapper.xml
index f1179956..7753c85c 100644
--- a/bigtop-manager-dao/src/main/resources/mapper/mysql/ServiceMapper.xml
+++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/ServiceMapper.xml
@@ -52,6 +52,14 @@
         </where>
     </select>
 
+    <select id="countByClusterId" parameterType="java.lang.Long" 
resultType="int">
+        select
+        count(*)
+        from service
+        where
+        cluster_id = #{clusterId}
+    </select>
+
     <select id="findByClusterId" parameterType="java.lang.Long" 
resultType="org.apache.bigtop.manager.dao.po.ServicePO">
         select
         <include refid="baseColumns" />
diff --git 
a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ClusterMapper.xml 
b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ClusterMapper.xml
index 54986b93..09c277f5 100644
--- a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ClusterMapper.xml
+++ b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ClusterMapper.xml
@@ -36,11 +36,10 @@
             <property name="alias" value="c"/>
         </include>, u.nickname as create_user,
         count(h.id) as total_host, sum(h.available_processors) as 
total_processor,
-        sum(h.total_memory_size) as total_memory, sum(h.total_disk) as 
total_disk, count(s.id) as total_service
+        sum(h.total_memory_size) as total_memory, sum(h.total_disk) as 
total_disk
         from
         cluster c left join "user" u on c.create_by = u.id
         left join host h on c.id = h.cluster_id
-        left join service s on c.id = s.cluster_id
         where c.id = #{id}
         group by c.id, u.nickname
         limit 1
diff --git 
a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ServiceMapper.xml 
b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ServiceMapper.xml
index df383204..e86f6e67 100644
--- a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ServiceMapper.xml
+++ b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ServiceMapper.xml
@@ -52,6 +52,14 @@
         </where>
     </select>
 
+    <select id="countByClusterId" parameterType="java.lang.Long" 
resultType="int">
+        select
+        count(*)
+        from service
+        where
+        cluster_id = #{clusterId}
+    </select>
+
     <select id="findByClusterId" parameterType="java.lang.Long" 
resultType="org.apache.bigtop.manager.dao.po.ServicePO">
         select
         <include refid="baseColumns" />
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
index 49cddd16..ea4bb43a 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
@@ -99,13 +99,13 @@ public class ComponentStageHelper {
                     stages.add(new ComponentConfigureStage(stageContext));
                     break;
                 case INIT:
-                    stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                    stageContext = createStageContext(componentName, 
List.of(hostnames.get(0)), commandDTO);
                     stages.add(new ComponentInitStage(stageContext));
                     break;
                 case PREPARE:
                     // Prepare phase runs after component started, client 
component shouldn't create this.
                     if (!StackUtils.isClientComponent(componentName)) {
-                        stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                        stageContext = createStageContext(componentName, 
List.of(hostnames.get(0)), commandDTO);
                         stages.add(new ComponentPrepareStage(stageContext));
                     }
                     break;
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java
index 15870b57..65fb6a1e 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/MetricsController.java
@@ -18,6 +18,8 @@
  */
 package org.apache.bigtop.manager.server.controller;
 
+import org.apache.bigtop.manager.server.model.vo.ClusterMetricsVO;
+import org.apache.bigtop.manager.server.model.vo.HostMetricsVO;
 import org.apache.bigtop.manager.server.service.MetricsService;
 import org.apache.bigtop.manager.server.utils.ResponseEntity;
 
@@ -27,7 +29,6 @@ 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;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
@@ -35,29 +36,23 @@ import jakarta.annotation.Resource;
 
 @Tag(name = "Metrics Controller")
 @RestController
-@RequestMapping("metrics")
+@RequestMapping("/metrics")
 public class MetricsController {
 
     @Resource
     private MetricsService metricsService;
 
-    @Operation(summary = "hosts healthy", description = "hosts healthy check")
-    @GetMapping("hostshealthy")
-    public ResponseEntity<JsonNode> agentHostsHealthyStatus() {
-        return 
ResponseEntity.success(metricsService.queryAgentsHealthyStatus());
-    }
-
     @Operation(summary = "host info", description = "host info query")
-    @GetMapping("hosts/{id}")
-    public ResponseEntity<JsonNode> queryAgentInfo(
-            @RequestParam(value = "interval", defaultValue = "1m") String 
interval, @PathVariable String id) {
-        return 
ResponseEntity.success(metricsService.queryAgentsInfo(Long.valueOf(id), 
interval));
+    @GetMapping("/hosts/{id}")
+    public ResponseEntity<HostMetricsVO> queryAgentInfo(
+            @RequestParam(value = "interval", defaultValue = "1m") String 
interval, @PathVariable Long id) {
+        return ResponseEntity.success(metricsService.queryAgentsInfo(id, 
interval));
     }
 
     @Operation(summary = "cluster info", description = "cluster info query")
-    @GetMapping("clusters/{id}")
-    public ResponseEntity<JsonNode> queryCluster(
-            @RequestParam(value = "interval", defaultValue = "1m") String 
interval, @PathVariable String id) {
-        return 
ResponseEntity.success(metricsService.queryClustersInfo(Long.valueOf(id), 
interval));
+    @GetMapping("/clusters/{id}")
+    public ResponseEntity<ClusterMetricsVO> queryCluster(
+            @RequestParam(value = "interval", defaultValue = "1m") String 
interval, @PathVariable Long id) {
+        return ResponseEntity.success(metricsService.queryClustersInfo(id, 
interval));
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
index 14c73043..0df9ea78 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
@@ -36,7 +36,7 @@ public class ServiceCommandReq {
     @NotNull @Schema(description = "Service name", example = "zookeeper")
     private String serviceName;
 
-    @NotNull @Schema(description = "Whether the service is already installed", 
example = "false")
+    @Schema(description = "Whether the service is already installed", example 
= "false")
     private Boolean installed;
 
     @NotEmpty(groups = 
{CommandGroupSequenceProvider.ServiceInstallCommandGroup.class})
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ClusterMetricsVO.java
similarity index 72%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ClusterMetricsVO.java
index 23327b17..a597849d 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ClusterMetricsVO.java
@@ -16,15 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.service;
+package org.apache.bigtop.manager.server.model.vo;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
 
-public interface MetricsService {
+import java.util.List;
 
-    JsonNode queryAgentsHealthyStatus();
+@Data
+public class ClusterMetricsVO {
 
-    JsonNode queryAgentsInfo(Long id, String interval);
+    private String cpuUsageCur;
+    private String memoryUsageCur;
 
-    JsonNode queryClustersInfo(Long clusterId, String interval);
+    private List<String> timestamps;
+    private List<String> cpuUsage;
+    private List<String> memoryUsage;
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/HostMetricsVO.java
similarity index 56%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/HostMetricsVO.java
index 23327b17..b52b09f6 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/HostMetricsVO.java
@@ -16,15 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.service;
+package org.apache.bigtop.manager.server.model.vo;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
 
-public interface MetricsService {
+import java.util.List;
 
-    JsonNode queryAgentsHealthyStatus();
+@Data
+public class HostMetricsVO {
 
-    JsonNode queryAgentsInfo(Long id, String interval);
+    private String cpuUsageCur;
+    private String memoryUsageCur;
+    private String diskUsageCur;
+    private String fileDescriptorUsage;
+    private String diskReadCur;
+    private String diskWriteCur;
 
-    JsonNode queryClustersInfo(Long clusterId, String interval);
+    private List<String> timestamps;
+    private List<String> cpuUsage;
+    private List<String> systemLoad1;
+    private List<String> systemLoad5;
+    private List<String> systemLoad15;
+    private List<String> memoryUsage;
+    private List<String> diskRead;
+    private List<String> diskWrite;
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusData.java
similarity index 73%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusData.java
index 23327b17..33a499eb 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusData.java
@@ -16,15 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.service;
+package org.apache.bigtop.manager.server.prometheus;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
 
-public interface MetricsService {
+import java.util.List;
 
-    JsonNode queryAgentsHealthyStatus();
+@Data
+public class PrometheusData {
 
-    JsonNode queryAgentsInfo(Long id, String interval);
+    // "matrix" | "vector" | "scalar" | "string",
+    private String resultType;
 
-    JsonNode queryClustersInfo(Long clusterId, String interval);
+    private List<PrometheusResult> result;
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusProxy.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusProxy.java
new file mode 100644
index 00000000..07984207
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusProxy.java
@@ -0,0 +1,490 @@
+/*
+ * 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.prometheus;
+
+import org.apache.bigtop.manager.server.model.vo.ClusterMetricsVO;
+import org.apache.bigtop.manager.server.model.vo.HostMetricsVO;
+
+import org.springframework.http.MediaType;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+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;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public class PrometheusProxy {
+
+    private final WebClient webClient;
+
+    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";
+
+    private static final ThreadLocal<List<String>> timestampCache = 
ThreadLocal.withInitial(ArrayList::new);
+
+    public PrometheusProxy(String prometheusHost, Integer prometheusPort) {
+        this.webClient = WebClient.builder()
+                .baseUrl("http://"; + prometheusHost + ":" + prometheusPort)
+                .build();
+    }
+
+    public PrometheusResponse query(String params) {
+        return webClient
+                .post()
+                .uri(uriBuilder -> uriBuilder.path("/api/v1/query").build())
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .body(BodyInserters.fromFormData("query", 
params).with("timeout", "10"))
+                .retrieve()
+                .bodyToMono(PrometheusResponse.class)
+                .block();
+    }
+
+    public PrometheusResponse queryRange(String query, String start, String 
end, String step) {
+        return 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", start)
+                        .with("end", end)
+                        .with("step", step))
+                .retrieve()
+                .bodyToMono(PrometheusResponse.class)
+                .block();
+    }
+
+    public HostMetricsVO queryAgentsInfo(String agentIpv4, String interval) {
+        timestampCache.set(getTimestampsList(processInternal(interval)));
+
+        HostMetricsVO res = new HostMetricsVO();
+        if (!agentIpv4.isBlank()) {
+            // Instant metrics
+            Map<String, BigDecimal> agentCpu = retrieveAgentCpu(agentIpv4);
+            Map<String, BigDecimal> agentMem = retrieveAgentMemory(agentIpv4);
+            Map<String, BigDecimal> agentDisk = retrieveAgentDisk(agentIpv4);
+            Map<String, BigDecimal> agentDiskIO = 
retrieveAgentDiskIO(agentIpv4);
+
+            // Use physical cores to check if the metrics is starting collect
+            if (!agentCpu.containsKey(PHYSICAL_CORES)) {
+                return res;
+            }
+
+            res.setCpuUsageCur(
+                    agentCpu.get(CPU_USAGE).multiply(new 
BigDecimal("100")).toString());
+            
res.setMemoryUsageCur((agentMem.get(MEM_TOTAL).subtract(agentMem.get(MEM_IDLE)))
+                    .divide(agentMem.get(MEM_TOTAL), 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal("100"))
+                    .toString());
+            res.setDiskUsageCur(agentDisk
+                    .get(DISK_TOTAL)
+                    .subtract(agentDisk.get(DISK_IDLE))
+                    .divide(agentDisk.get(DISK_TOTAL), 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal("100"))
+                    .toString());
+            res.setFileDescriptorUsage(agentCpu.get(FILE_OPEN_DESCRIPTOR)
+                    .divide(agentCpu.get(FILE_TOTAL_DESCRIPTOR), 4, 
RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal("100"))
+                    .toString());
+            res.setDiskReadCur(agentDiskIO.get(DISK_READ).toString());
+            res.setDiskWriteCur(agentDiskIO.get(DISK_WRITE).toString());
+
+            // Range metrics
+            Map<String, List<BigDecimal>> agentCpuInterval = 
retrieveAgentCpu(agentIpv4, interval);
+            Map<String, List<BigDecimal>> agentMemInterval = 
retrieveAgentMemory(agentIpv4, interval);
+            Map<String, List<BigDecimal>> agentDiskIOInterval = 
retrieveAgentDiskIO(agentIpv4, interval);
+
+            res.setCpuUsage(convertList(agentCpuInterval.get(CPU_USAGE), 100));
+            
res.setSystemLoad1(convertList(agentCpuInterval.get(CPU_LOAD_AVG_MIN_1)));
+            
res.setSystemLoad5(convertList(agentCpuInterval.get(CPU_LOAD_AVG_MIN_5)));
+            
res.setSystemLoad15(convertList(agentCpuInterval.get(CPU_LOAD_AVG_MIN_15)));
+            res.setMemoryUsage(convertList(agentMemInterval.get("memUsage"), 
100));
+            res.setDiskRead(convertList(agentDiskIOInterval.get(DISK_READ)));
+            res.setDiskWrite(convertList(agentDiskIOInterval.get(DISK_WRITE)));
+        }
+
+        res.setTimestamps(timestampCache.get());
+        timestampCache.remove();
+        return res;
+    }
+
+    public ClusterMetricsVO queryClustersInfo(List<String> agentIpv4s, String 
interval) {
+        timestampCache.set(getTimestampsList(processInternal(interval)));
+
+        ClusterMetricsVO res = new ClusterMetricsVO();
+        if (!agentIpv4s.isEmpty()) {
+            BigDecimal totalPhysicalCores = new BigDecimal("0.0");
+            BigDecimal totalMemSpace = new BigDecimal("0.0");
+
+            BigDecimal usedPhysicalCores = new BigDecimal("0.0");
+            BigDecimal totalMemIdle = new BigDecimal("0.0");
+
+            List<BigDecimal> timeUsedCores = getEmptyList();
+            List<BigDecimal> timeMemIdle = getEmptyList();
+
+            for (String agentIpv4 : agentIpv4s) {
+                // Instant Metrics
+                Map<String, BigDecimal> agentCpu = retrieveAgentCpu(agentIpv4);
+                Map<String, BigDecimal> agentMem = 
retrieveAgentMemory(agentIpv4);
+
+                // Use physical cores to check if the metrics is starting 
collect
+                if (!agentCpu.containsKey(PHYSICAL_CORES)) {
+                    return res;
+                }
+
+                BigDecimal cpuUsage = agentCpu.get(CPU_USAGE);
+                BigDecimal physicalCores = agentCpu.get(PHYSICAL_CORES);
+                BigDecimal usedCores = cpuUsage.multiply(physicalCores);
+                BigDecimal memIdle = agentMem.get(MEM_IDLE);
+                BigDecimal memTotal = agentMem.get(MEM_TOTAL);
+
+                totalPhysicalCores = totalPhysicalCores.add(physicalCores);
+                usedPhysicalCores = usedPhysicalCores.add(usedCores);
+                totalMemIdle = totalMemIdle.add(memIdle);
+                totalMemSpace = totalMemSpace.add(memTotal);
+
+                // Range Metrics
+                List<BigDecimal> cpuUsageInterval =
+                        retrieveAgentCpu(agentIpv4, interval).get(CPU_USAGE);
+                for (int i = 0; i < cpuUsageInterval.size(); i++) {
+                    BigDecimal c = cpuUsageInterval.get(i);
+                    if (c != null) {
+                        c = c.multiply(physicalCores);
+                        BigDecimal b = timeUsedCores.get(i);
+                        if (b == null) {
+                            b = new BigDecimal("0.0");
+                        }
+
+                        timeUsedCores.set(i, c.add(b));
+                    }
+                }
+
+                List<BigDecimal> memIdleInterval =
+                        retrieveAgentMemory(agentIpv4, interval).get(MEM_IDLE);
+                for (int i = 0; i < memIdleInterval.size(); i++) {
+                    BigDecimal m = memIdleInterval.get(i);
+                    if (m != null) {
+                        BigDecimal b = timeMemIdle.get(i);
+                        if (b == null) {
+                            b = new BigDecimal("0.0");
+                        }
+
+                        timeMemIdle.set(i, m.add(b));
+                    }
+                }
+            }
+
+            // Instant Metrics
+            res.setCpuUsageCur(usedPhysicalCores
+                    .divide(totalPhysicalCores, 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal("100"))
+                    .toString());
+            res.setMemoryUsageCur(totalMemSpace
+                    .subtract(totalMemIdle)
+                    .divide(totalMemSpace, 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal("100"))
+                    .toString());
+
+            // Range Metrics
+            List<BigDecimal> cpuUsageList = getEmptyList();
+            List<BigDecimal> memUsageList = getEmptyList();
+
+            for (int i = 0; i < timeUsedCores.size(); i++) {
+                BigDecimal usedCores = timeUsedCores.get(i);
+                if (usedCores != null) {
+                    usedCores = usedCores.divide(totalPhysicalCores, 4, 
RoundingMode.HALF_UP);
+                    cpuUsageList.set(i, usedCores);
+                }
+            }
+
+            for (int i = 0; i < timeMemIdle.size(); i++) {
+                BigDecimal memIdle = timeMemIdle.get(i);
+                if (memIdle != null) {
+                    memIdle = 
totalMemSpace.subtract(memIdle).divide(totalMemSpace, 4, RoundingMode.HALF_UP);
+                    memUsageList.set(i, memIdle);
+                }
+            }
+
+            res.setCpuUsage(convertList(cpuUsageList, 100));
+            res.setMemoryUsage(convertList(memUsageList, 100));
+        }
+
+        res.setTimestamps(timestampCache.get());
+        timestampCache.remove();
+        return res;
+    }
+
+    public Map<String, BigDecimal> retrieveAgentCpu(String iPv4addr) {
+        Map<String, BigDecimal> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_cpu{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = query(params);
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("cpuUsage");
+            map.put(key, new BigDecimal(result.getValue().get(1)));
+        }
+
+        // Get common metrics
+        if (!CollectionUtils.isEmpty(response.getData().getResult())) {
+            Map<String, String> metric = 
response.getData().getResult().get(0).getMetric();
+            map.put(PHYSICAL_CORES, new 
BigDecimal(metric.get(PHYSICAL_CORES)));
+            map.put(FILE_OPEN_DESCRIPTOR, new 
BigDecimal(metric.get(FILE_OPEN_DESCRIPTOR)));
+            map.put(FILE_TOTAL_DESCRIPTOR, new 
BigDecimal(metric.get(FILE_TOTAL_DESCRIPTOR)));
+        }
+
+        return map;
+    }
+
+    public Map<String, List<BigDecimal>> retrieveAgentCpu(String iPv4addr, 
String interval) {
+        List<String> timestamps = timestampCache.get();
+        Map<String, List<BigDecimal>> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_cpu{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = queryRange(
+                params,
+                timestamps.get(0),
+                timestamps.get(timestamps.size() - 1),
+                number2Param(processInternal(interval)));
+
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("cpuUsage");
+            List<BigDecimal> list = map.computeIfAbsent(key, k -> 
getEmptyList());
+            for (List<String> value : result.getValues()) {
+                String timestamp = value.get(0);
+                int index = timestamps.indexOf(timestamp);
+                list.set(index, new BigDecimal(value.get(1)));
+            }
+        }
+
+        return map;
+    }
+
+    public Map<String, BigDecimal> retrieveAgentMemory(String iPv4addr) {
+        Map<String, BigDecimal> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_mem{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = query(params);
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("memUsage");
+            map.put(key, new BigDecimal(result.getValue().get(1)));
+        }
+
+        return map;
+    }
+
+    public Map<String, List<BigDecimal>> retrieveAgentMemory(String iPv4addr, 
String interval) {
+        List<String> timestamps = timestampCache.get();
+        Map<String, List<BigDecimal>> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_mem{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = queryRange(
+                params,
+                timestamps.get(0),
+                timestamps.get(timestamps.size() - 1),
+                number2Param(processInternal(interval)));
+
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("memUsage");
+            List<BigDecimal> list = map.computeIfAbsent(key, k -> 
getEmptyList());
+            for (List<String> value : result.getValues()) {
+                String timestamp = value.get(0);
+                int index = timestamps.indexOf(timestamp);
+                list.set(index, new BigDecimal(value.get(1)));
+            }
+        }
+
+        List<BigDecimal> memTotalList = map.get(MEM_TOTAL) == null ? 
getEmptyList() : map.get(MEM_TOTAL);
+        List<BigDecimal> memIdleList = map.get(MEM_IDLE) == null ? 
getEmptyList() : map.get(MEM_IDLE);
+        List<BigDecimal> memUsageList = getEmptyList();
+
+        for (int i = 0; i < memTotalList.size(); i++) {
+            BigDecimal memTotal = memTotalList.get(i);
+            BigDecimal memIdle = memIdleList.get(i);
+            if (memTotal != null && memIdle != null) {
+                BigDecimal memUsage = 
memTotal.subtract(memIdle).divide(memTotal, 4, RoundingMode.HALF_UP);
+                memUsageList.set(i, memUsage);
+            }
+        }
+
+        map.put("memUsage", memUsageList);
+        return map;
+    }
+
+    public Map<String, BigDecimal> retrieveAgentDisk(String iPv4addr) {
+        Map<String, BigDecimal> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_disk{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = query(params);
+        BigDecimal diskTotalSpace = new BigDecimal("0.0");
+        BigDecimal diskFreeSpace = new BigDecimal("0.0");
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("diskUsage");
+            if (Objects.equals(key, DISK_IDLE)) {
+                diskFreeSpace =
+                        diskFreeSpace.add(new 
BigDecimal(result.getValue().get(1)));
+            } else {
+                diskTotalSpace =
+                        diskTotalSpace.add(new 
BigDecimal(result.getValue().get(1)));
+            }
+        }
+
+        map.put(DISK_IDLE, diskFreeSpace);
+        map.put(DISK_TOTAL, diskTotalSpace);
+        return map;
+    }
+
+    public Map<String, BigDecimal> retrieveAgentDiskIO(String iPv4addr) {
+        Map<String, BigDecimal> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_diskIO{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = query(params);
+        BigDecimal diskWrite = new BigDecimal("0.0");
+        BigDecimal diskRead = new BigDecimal("0.0");
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("diskIO");
+            if (Objects.equals(key, DISK_WRITE)) {
+                diskWrite = diskWrite.add(new 
BigDecimal(result.getValue().get(1)));
+            } else {
+                diskRead = diskRead.add(new 
BigDecimal(result.getValue().get(1)));
+            }
+        }
+
+        map.put(DISK_WRITE, diskWrite);
+        map.put(DISK_READ, diskRead);
+        return map;
+    }
+
+    public Map<String, List<BigDecimal>> retrieveAgentDiskIO(String iPv4addr, 
String interval) {
+        List<String> timestamps = timestampCache.get();
+        Map<String, List<BigDecimal>> map = new HashMap<>();
+        String params = 
String.format("agent_host_monitoring_diskIO{iPv4addr=\"%s\"}", iPv4addr);
+        PrometheusResponse response = queryRange(
+                params,
+                timestamps.get(0),
+                timestamps.get(timestamps.size() - 1),
+                number2Param(processInternal(interval)));
+
+        List<BigDecimal> diskWriteList = getEmptyList();
+        List<BigDecimal> diskReadList = getEmptyList();
+
+        for (PrometheusResult result : response.getData().getResult()) {
+            String key = result.getMetric().get("diskIO");
+            for (List<String> value : result.getValues()) {
+                String timestamp = value.get(0);
+                int index = timestamps.indexOf(timestamp);
+                if (Objects.equals(key, DISK_WRITE)) {
+                    BigDecimal w = diskWriteList.get(index);
+                    if (w == null) {
+                        w = new BigDecimal("0.0");
+                    }
+
+                    w = w.add(new BigDecimal(value.get(1)));
+                    diskWriteList.set(index, w);
+                } else {
+                    BigDecimal r = diskReadList.get(index);
+                    if (r == null) {
+                        r = new BigDecimal("0.0");
+                    }
+
+                    r = r.add(new BigDecimal(value.get(1)));
+                    diskReadList.set(index, r);
+                }
+            }
+        }
+
+        map.put(DISK_WRITE, diskWriteList);
+        map.put(DISK_READ, diskReadList);
+        return map;
+    }
+
+    private List<String> convertList(List<BigDecimal> list) {
+        return convertList(list, 1);
+    }
+
+    private List<String> convertList(List<BigDecimal> list, Integer multiply) {
+        List<String> resultList = getEmptyList();
+        if (list == null) {
+            Collections.fill(resultList, "");
+        } else {
+            for (int i = 0; i < list.size(); i++) {
+                BigDecimal value = list.get(i);
+                if (value != null) {
+                    resultList.set(i, value.multiply(new 
BigDecimal(multiply)).toString());
+                } else {
+                    resultList.set(i, "");
+                }
+            }
+        }
+
+        return resultList;
+    }
+
+    private static List<String> 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);
+        // get 8 point
+        List<String> timestamps = new ArrayList<>();
+        ZoneId zid = ZoneId.systemDefault();
+        for (int i = 6; i >= 0; i--) {
+            LocalDateTime pastTime = 
currentDateTime.minus(Duration.ofSeconds((long) step * i));
+            long timestamp = pastTime.atZone(zid).toInstant().toEpochMilli() / 
1000L;
+            timestamps.add(String.valueOf(timestamp));
+        }
+
+        return timestamps;
+    }
+
+    private String number2Param(int step) {
+        return String.format("%ss", step);
+    }
+
+    private 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;
+    }
+
+    private <T> List<T> getEmptyList() {
+        int size = timestampCache.get().size();
+        return new ArrayList<>(Collections.nCopies(size, null));
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusResponse.java
similarity index 64%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusResponse.java
index 23327b17..ae17e144 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusResponse.java
@@ -16,15 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.service;
+package org.apache.bigtop.manager.server.prometheus;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
 
-public interface MetricsService {
+/**
+ * <a 
href="https://prometheus.io/docs/prometheus/latest/querying/api/";>Prometheus 
HTTP API</a>
+ */
+@Data
+public class PrometheusResponse {
+
+    // "success" | "error"
+    private String status;
 
-    JsonNode queryAgentsHealthyStatus();
+    private PrometheusData data;
 
-    JsonNode queryAgentsInfo(Long id, String interval);
+    // Only set if status is "error". The data field may still hold additional 
data.
+    private String errorType;
 
-    JsonNode queryClustersInfo(Long clusterId, String interval);
+    private String error;
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusResult.java
similarity index 63%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusResult.java
index 23327b17..f39b14d3 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/prometheus/PrometheusResult.java
@@ -16,15 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.service;
+package org.apache.bigtop.manager.server.prometheus;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
 
-public interface MetricsService {
+import java.util.List;
+import java.util.Map;
 
-    JsonNode queryAgentsHealthyStatus();
+@Data
+public class PrometheusResult {
 
-    JsonNode queryAgentsInfo(Long id, String interval);
+    private Map<String, String> metric;
 
-    JsonNode queryClustersInfo(Long clusterId, String interval);
+    // For resultType "vector" only
+    // Contains a single value of [timestamp, value]
+    private List<String> value;
+
+    // For resultType "matrix" only
+    // Contains a list of values, each value is a list of [timestamp, value]
+    private List<List<String>> values;
 }
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
deleted file mode 100644
index 78e1b284..00000000
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/proxy/PrometheusProxy.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * 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.proxy;
-
-import org.apache.bigtop.manager.server.utils.ProxyUtils;
-
-import org.springframework.http.MediaType;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.WebClient;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import reactor.core.publisher.Mono;
-
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-public class PrometheusProxy {
-
-    private final WebClient webClient;
-
-    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";
-
-    public PrometheusProxy(String prometheusHost, Integer prometheusPort) {
-        this.webClient = WebClient.builder()
-                .baseUrl("http://"; + prometheusHost + ":" + prometheusPort)
-                .build();
-    }
-    /**
-     * Retrieve current data
-     */
-    public JsonNode query(String params) {
-        Mono<JsonNode> body = webClient
-                .post()
-                .uri(uriBuilder -> uriBuilder.path("/api/v1/query").build())
-                .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;
-        }
-        return result;
-    }
-    /**
-     * Retrieve data with a specified interval before the current time
-     */
-    public JsonNode queryRange(String query, long start, long end, String 
step) {
-        Mono<JsonNode> 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 result;
-    }
-
-    /**
-     * query agents healthy
-     */
-    public JsonNode queryAgentsHealthyStatus() {
-        JsonNode result = query("up{job=\"%s\"}".formatted("bm-agent-host"));
-        ObjectMapper objectMapper = new ObjectMapper();
-        ArrayNode agentsHealthyStatus = objectMapper.createArrayNode();
-        if (result != null) {
-            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();
-    }
-    /**
-     * query agents info interval
-     */
-    public JsonNode queryAgentsInfo(String agentIpv4, String interval) {
-        ObjectMapper objectMapper = new ObjectMapper();
-        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];
-
-            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);
-
-            // 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);
-            }
-
-            // 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(List<String> agentIpv4s, String 
interval) {
-        int agentsNum = agentIpv4s.size(); // 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];
-
-            int agentIndex = 0;
-            ObjectNode clusterInfo = objectMapper.createObjectNode();
-            for (String agentIpv4 : agentIpv4s) {
-                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 objectMapper.createObjectNode();
-    }
-
-    /**
-     * 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");
-                ObjectNode agentInfo = objectMapper.createObjectNode();
-                agentInfo.put("hostname", 
agentCpuMetric.get("hostname").asText());
-                agentInfo.put(
-                        "cpuInfo",
-                        agentCpuMetric.get("cpu_info") == null
-                                ? ""
-                                : agentCpuMetric.get("cpu_info").asText());
-                agentInfo.put("iPv4addr", 
agentCpuMetric.get("iPv4addr").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(
-                        FILE_OPEN_DESCRIPTOR,
-                        agentCpuMetric.get(FILE_OPEN_DESCRIPTOR).asLong());
-                agentInfo.put(
-                        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());
-                }
-                return agentInfo;
-            }
-        }
-        return objectMapper.createObjectNode();
-    }
-    /**
-     * retrieve cpu interval
-     */
-    public JsonNode retrieveAgentCpu(String iPv4addr, String interval) {
-        String params = 
String.format("agent_host_monitoring_cpu{iPv4addr=\"%s\"}", iPv4addr);
-        ArrayList<Long> 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",
-                        agentCpuInfo.get("cpu_info") == null
-                                ? ""
-                                : agentCpuInfo.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()) {
-                ObjectNode agentsMemInfo = objectMapper.createObjectNode();
-                // metric
-                JsonNode agentMemMetric = agentsMem.get(0).get("metric");
-                agentsMemInfo.put("hostname", 
agentMemMetric.get("hostname").asText());
-                agentsMemInfo.put("iPv4addr", 
agentMemMetric.get("iPv4addr").asText());
-                for (JsonNode agent : agentsMem) {
-                    agentsMemInfo.put(
-                            agent.get("metric").get("memUsage").asText(),
-                            agent.get("value").get(1).asLong()); // mem metric
-                }
-                return agentsMemInfo;
-            }
-        }
-        return objectMapper.createObjectNode();
-    }
-    /**
-     * retrieve memory interval
-     */
-    public JsonNode retrieveAgentMemory(String iPv4addr, String interval) {
-        String params = 
String.format("agent_host_monitoring_mem{iPv4addr=\"%s\"}", iPv4addr);
-        ArrayList<Long> 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()) {
-                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());
-
-                // 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.put(DISK_TOTAL, diskTotalSpace);
-                agentDiskInfo.put(DISK_IDLE, diskFreeSpace);
-                return agentDiskInfo;
-            }
-        }
-        return objectMapper.createObjectNode();
-    }
-
-    /**
-     * 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()) {
-                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<Long> 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());
-
-                // 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 {
-                        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;
-                        }
-                    }
-                }
-                agentDiskIOInfo.set(DISK_WRITE, 
ProxyUtils.array2node(diskWrite));
-                agentDiskIOInfo.set(DISK_READ, 
ProxyUtils.array2node(diskRead));
-                return agentDiskIOInfo;
-            }
-        }
-        return objectMapper.createObjectNode();
-    }
-}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
index 23327b17..8e25da1a 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/MetricsService.java
@@ -18,13 +18,12 @@
  */
 package org.apache.bigtop.manager.server.service;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import org.apache.bigtop.manager.server.model.vo.ClusterMetricsVO;
+import org.apache.bigtop.manager.server.model.vo.HostMetricsVO;
 
 public interface MetricsService {
 
-    JsonNode queryAgentsHealthyStatus();
+    HostMetricsVO queryAgentsInfo(Long id, String interval);
 
-    JsonNode queryAgentsInfo(Long id, String interval);
-
-    JsonNode queryClustersInfo(Long clusterId, String interval);
+    ClusterMetricsVO queryClustersInfo(Long clusterId, String interval);
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
index 25f2bae3..e5e62fa0 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
@@ -62,11 +62,12 @@ public class ClusterServiceImpl implements ClusterService {
     @Override
     public ClusterVO get(Long id) {
         ClusterPO clusterPO = clusterDao.findDetailsById(id);
-
         if (clusterPO == null) {
             throw new ApiException(ApiExceptionEnum.CLUSTER_NOT_FOUND);
         }
 
+        int serviceNum = serviceDao.countByClusterId(id);
+        clusterPO.setTotalService((long) serviceNum);
         return ClusterConverter.INSTANCE.fromPO2VO(clusterPO);
     }
 
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java
index c34721a7..10519aef 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/MetricsServiceImpl.java
@@ -28,13 +28,13 @@ import 
org.apache.bigtop.manager.dao.repository.ServiceConfigDao;
 import org.apache.bigtop.manager.server.model.converter.ServiceConfigConverter;
 import org.apache.bigtop.manager.server.model.dto.PropertyDTO;
 import org.apache.bigtop.manager.server.model.dto.ServiceConfigDTO;
-import org.apache.bigtop.manager.server.proxy.PrometheusProxy;
+import org.apache.bigtop.manager.server.model.vo.ClusterMetricsVO;
+import org.apache.bigtop.manager.server.model.vo.HostMetricsVO;
+import org.apache.bigtop.manager.server.prometheus.PrometheusProxy;
 import org.apache.bigtop.manager.server.service.MetricsService;
 
 import org.springframework.stereotype.Service;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.extern.slf4j.Slf4j;
 
 import jakarta.annotation.Resource;
@@ -54,20 +54,10 @@ public class MetricsServiceImpl implements MetricsService {
     private ServiceConfigDao serviceConfigDao;
 
     @Override
-    public JsonNode queryAgentsHealthyStatus() {
+    public HostMetricsVO queryAgentsInfo(Long id, String interval) {
         PrometheusProxy proxy = getProxy();
         if (proxy == null) {
-            return new ObjectMapper().createObjectNode();
-        }
-
-        return proxy.queryAgentsHealthyStatus();
-    }
-
-    @Override
-    public JsonNode queryAgentsInfo(Long id, String interval) {
-        PrometheusProxy proxy = getProxy();
-        if (proxy == null) {
-            return new ObjectMapper().createObjectNode();
+            return new HostMetricsVO();
         }
 
         String ipv4 = hostDao.findById(id).getIpv4();
@@ -75,10 +65,10 @@ public class MetricsServiceImpl implements MetricsService {
     }
 
     @Override
-    public JsonNode queryClustersInfo(Long clusterId, String interval) {
+    public ClusterMetricsVO queryClustersInfo(Long clusterId, String interval) 
{
         PrometheusProxy proxy = getProxy();
         if (proxy == null) {
-            return new ObjectMapper().createObjectNode();
+            return new ClusterMetricsVO();
         }
 
         List<String> ipv4s = hostDao.findAllByClusterId(clusterId).stream()
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
deleted file mode 100644
index 46b95d40..00000000
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/ProxyUtils.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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<Long> 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<Long> 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/MetricsControllerTest.java
 
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MetricsControllerTest.java
index 6e760c9b..b99d30ab 100644
--- 
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MetricsControllerTest.java
+++ 
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/MetricsControllerTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.bigtop.manager.server.controller;
 
+import org.apache.bigtop.manager.server.model.vo.ClusterMetricsVO;
+import org.apache.bigtop.manager.server.model.vo.HostMetricsVO;
 import org.apache.bigtop.manager.server.service.MetricsService;
 import org.apache.bigtop.manager.server.utils.MessageSourceUtils;
 import org.apache.bigtop.manager.server.utils.ResponseEntity;
@@ -32,11 +34,7 @@ import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
@@ -64,23 +62,36 @@ class MetricsControllerTest {
     }
 
     @Test
-    void agentHostsHealthyStatusReturnsSuccess() {
-        JsonNode mockResponse = new ObjectMapper().createObjectNode();
-        
when(metricsService.queryAgentsHealthyStatus()).thenReturn(mockResponse);
+    void testQueryAgentInfo() {
+        Long hostId = 1L;
+        String interval = "1m";
+        HostMetricsVO mockResponse = new HostMetricsVO();
+        mockResponse.setCpuUsageCur("50%");
+        mockResponse.setMemoryUsageCur("70%");
+
+        when(metricsService.queryAgentsInfo(hostId, 
interval)).thenReturn(mockResponse);
 
-        ResponseEntity<JsonNode> response = 
metricsController.agentHostsHealthyStatus();
+        ResponseEntity<HostMetricsVO> response = 
metricsController.queryAgentInfo(interval, hostId);
 
+        assertEquals("Mocked message", response.getMessage());
         assertTrue(response.isSuccess());
         assertEquals(mockResponse, response.getData());
     }
 
     @Test
-    void agentHostsHealthyStatusReturnsEmptyResponse() {
-        when(metricsService.queryAgentsHealthyStatus()).thenReturn(null);
+    void testQueryClusterInfo() {
+        Long clusterId = 1L;
+        String interval = "1m";
+        ClusterMetricsVO mockResponse = new ClusterMetricsVO();
+        mockResponse.setCpuUsageCur("60%");
+        mockResponse.setMemoryUsageCur("80%");
 
-        ResponseEntity<JsonNode> response = 
metricsController.agentHostsHealthyStatus();
+        when(metricsService.queryClustersInfo(clusterId, 
interval)).thenReturn(mockResponse);
 
+        ResponseEntity<ClusterMetricsVO> response = 
metricsController.queryCluster(interval, clusterId);
+
+        assertEquals("Mocked message", response.getMessage());
         assertTrue(response.isSuccess());
-        assertNull(response.getData());
+        assertEquals(mockResponse, response.getData());
     }
 }
diff --git 
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/service/ClusterServiceTest.java
 
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/service/ClusterServiceTest.java
index 6bd070dd..573cb9bd 100644
--- 
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/service/ClusterServiceTest.java
+++ 
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/service/ClusterServiceTest.java
@@ -21,7 +21,7 @@ package org.apache.bigtop.manager.server.service;
 
 import org.apache.bigtop.manager.dao.po.ClusterPO;
 import org.apache.bigtop.manager.dao.repository.ClusterDao;
-import org.apache.bigtop.manager.dao.repository.RepoDao;
+import org.apache.bigtop.manager.dao.repository.ServiceDao;
 import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
 import org.apache.bigtop.manager.server.exception.ApiException;
 import org.apache.bigtop.manager.server.model.dto.ClusterDTO;
@@ -49,7 +49,7 @@ public class ClusterServiceTest {
     private ClusterDao clusterDao;
 
     @Mock
-    private RepoDao repoDao;
+    private ServiceDao serviceDao;
 
     @InjectMocks
     private ClusterService clusterService = new ClusterServiceImpl();
@@ -73,6 +73,7 @@ public class ClusterServiceTest {
                 assertThrows(ApiException.class, () -> 
clusterService.get(1L)).getEx());
 
         when(clusterDao.findDetailsById(any())).thenReturn(clusterPO);
+        when(serviceDao.countByClusterId(any())).thenReturn(1);
         assert clusterService.get(1L).getName().equals(CLUSTER_NAME);
 
         ClusterDTO clusterDTO = new ClusterDTO();
diff --git 
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/utils/ProxyUtilsTest.java
 
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/utils/ProxyUtilsTest.java
deleted file mode 100644
index aa39edd3..00000000
--- 
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/utils/ProxyUtilsTest.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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 org.junit.jupiter.api.Test;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import java.util.ArrayList;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-public class ProxyUtilsTest {
-
-    @Test
-    // Test getDoubleSafely with normal case
-    public void testGetDoubleSafelyHappyPath() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        String jsonString = "{\"values\":[1.1, 2.2, 3.3]}";
-        JsonNode parentNode = mapper.readTree(jsonString);
-        assertEquals(2.2, ProxyUtils.getDoubleSafely(parentNode, "values", 1));
-    }
-
-    @Test
-    // Test getDoubleSafely with null node case
-    public void testGetDoubleSafelyNullNode() {
-        ObjectMapper mapper = new ObjectMapper();
-        JsonNode parentNode = mapper.createObjectNode();
-        assertEquals(0.0, ProxyUtils.getDoubleSafely(parentNode, "values", 1));
-    }
-
-    @Test
-    // Test getDoubleSafely with non-array node case
-    public void testGetDoubleSafelyNotArrayNode() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        String jsonString = "{\"values\":1.1}";
-        JsonNode parentNode = mapper.readTree(jsonString);
-        assertEquals(0.0, ProxyUtils.getDoubleSafely(parentNode, "values", 1));
-    }
-
-    @Test
-    // Test getDoubleSafely with index out of bounds case
-    public void testGetDoubleSafelyIndexOutOfBound() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        String jsonString = "{\"values\":[1.1, 2.2, 3.3]}";
-        JsonNode parentNode = mapper.readTree(jsonString);
-        assertEquals(0.0, ProxyUtils.getDoubleSafely(parentNode, "values", 5));
-    }
-
-    @Test
-    // Test getLongSafely with normal case
-    public void testGetLongSafelyHappyPath() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        String jsonString = "{\"values\":[1, 2, 3]}";
-        JsonNode parentNode = mapper.readTree(jsonString);
-        assertEquals(2L, ProxyUtils.getLongSafely(parentNode, "values", 1));
-    }
-
-    @Test
-    // Test getLongSafely with null node case
-    public void testGetLongSafelyNullNode() {
-        ObjectMapper mapper = new ObjectMapper();
-        JsonNode parentNode = mapper.createObjectNode();
-        assertEquals(0L, ProxyUtils.getLongSafely(parentNode, "values", 1));
-    }
-
-    @Test
-    // Test getLongSafely with non-array node case
-    public void testGetLongSafelyNotArrayNode() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        String jsonString = "{\"values\":1}";
-        JsonNode parentNode = mapper.readTree(jsonString);
-        assertEquals(0L, ProxyUtils.getLongSafely(parentNode, "values", 1));
-    }
-
-    @Test
-    // Test getLongSafely with index out of bounds case
-    public void testGetLongSafelyIndexOutOfBound() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        String jsonString = "{\"values\":[1, 2, 3]}";
-        JsonNode parentNode = mapper.readTree(jsonString);
-        assertEquals(0L, ProxyUtils.getLongSafely(parentNode, "values", 5));
-    }
-
-    @Test
-    // Test array2node(double[] array) with normal case
-    public void testArray2NodeDoubleArrayHappyPath() {
-        double[] array = {1.123456789, 2.23456789, 3.3456789, 4.456789, 
5.56789, 6.6789};
-        JsonNode node = ProxyUtils.array2node(array);
-        assertEquals("1.123457", node.get(0).asText());
-        assertEquals("2.234568", node.get(1).asText());
-        assertEquals("3.345679", node.get(2).asText());
-        assertEquals("4.456789", node.get(3).asText());
-        assertEquals("5.567890", node.get(4).asText());
-        assertEquals("6.678900", node.get(5).asText());
-    }
-
-    @Test
-    // Test array2node(long[] array) with normal case
-    public void testArray2NodeLongArrayHappyPath() {
-        long[] array = {1, 2, 3, 4, 5, 6};
-        JsonNode node = ProxyUtils.array2node(array);
-        assertEquals(1L, node.get(0).asLong());
-        assertEquals(2L, node.get(1).asLong());
-        assertEquals(3L, node.get(2).asLong());
-        assertEquals(4L, node.get(3).asLong());
-        assertEquals(5L, node.get(4).asLong());
-        assertEquals(6L, node.get(5).asLong());
-    }
-
-    @Test
-    // Test array2node(long[] array1, long[] array2) with normal case
-    public void testArray2NodeTwoLongArraysHappyPath() {
-        long[] array1 = {1, 2, 3, 4, 5, 6};
-        long[] array2 = {2, 4, 6, 8, 10, 12};
-        JsonNode node = ProxyUtils.array2node(array1, array2);
-        assertEquals("0.500000", node.get(0).asText());
-        assertEquals("0.500000", node.get(1).asText());
-        assertEquals("0.500000", node.get(2).asText());
-        assertEquals("0.500000", node.get(3).asText());
-        assertEquals("0.500000", node.get(4).asText());
-        assertEquals("0.500000", node.get(5).asText());
-    }
-
-    @Test
-    // Test array2node(long[] array1, long[] array2) with array2 containing 
zero case
-    public void testArray2NodeTwoLongArraysWithZero() {
-        long[] array1 = {1, 2, 3, 4, 5, 6};
-        long[] array2 = {0, 4, 0, 8, 10, 0};
-        JsonNode node = ProxyUtils.array2node(array1, array2);
-        assertEquals("0.000000", node.get(0).asText());
-        assertEquals("0.500000", node.get(1).asText());
-        assertEquals("0.000000", node.get(2).asText());
-        assertEquals("0.500000", node.get(3).asText());
-        assertEquals("0.500000", node.get(4).asText());
-        assertEquals("0.000000", node.get(5).asText());
-    }
-
-    @Test
-    // Test array2node(long[][] array1, long[][] array2, int num) with normal 
case
-    public void testArray2NodeTwoLong2DArraysHappyPath() {
-        long[][] array1 = {{1, 2, 3, 4, 5, 6}, {2, 3, 4, 5, 6, 7}};
-        long[][] array2 = {{2, 4, 6, 8, 10, 12}, {3, 5, 6, 8, 10, 12}};
-        JsonNode node = ProxyUtils.array2node(array1, array2, 2);
-        assertEquals("0.400000", node.get(0).asText());
-        assertEquals("0.444444", node.get(1).asText());
-        assertEquals("0.416667", node.get(2).asText());
-        assertEquals("0.437500", node.get(3).asText());
-        assertEquals("0.450000", node.get(4).asText());
-        assertEquals("0.458333", node.get(5).asText());
-    }
-
-    @Test
-    // Test array2node(long[][] array1, long[][] array2, int num) with array2 
containing zero case
-    public void testArray2NodeTwoLong2DArraysWithZero() {
-        long[][] array1 = {{1, 2, 3, 4, 5, 6}, {2, 3, 4, 5, 6, 7}};
-        long[][] array2 = {{2, 4, 0, 8, 10, 0}, {3, 5, 0, 8, 10, 0}};
-        JsonNode node = ProxyUtils.array2node(array1, array2, 2);
-        assertEquals("0.400000", node.get(0).asText());
-        assertEquals("0.444444", node.get(1).asText());
-        assertEquals("0.000000", node.get(2).asText());
-        assertEquals("0.437500", node.get(3).asText());
-        assertEquals("0.450000", node.get(4).asText());
-        assertEquals("0.000000", node.get(5).asText());
-    }
-
-    @Test
-    // Test getTimeStampsList with normal case
-    public void testGetTimeStampsListHappyPath() {
-        ArrayList<Long> timestamps = ProxyUtils.getTimeStampsList(10);
-        assertEquals(7, timestamps.size());
-        // Here we cannot precisely assert the value of each timestamp as they 
depend on the current time, but we can
-        // assert the number of timestamps
-    }
-
-    @Test
-    // Test Number2Param with normal case
-    public void testNumber2ParamHappyPath() {
-        assertEquals("10m", ProxyUtils.Number2Param(10));
-    }
-
-    @Test
-    // Test processInternal with normal case
-    public void testProcessInternalHappyPath() {
-        assertEquals(600, ProxyUtils.processInternal("10m"));
-        assertEquals(3600, ProxyUtils.processInternal("1h"));
-        assertEquals(120, ProxyUtils.processInternal("2m"));
-    }
-
-    @Test
-    // Test processInternal with illegal input case
-    public void testProcessInternalIllegalInput() {
-        Exception exception = assertThrows(NumberFormatException.class, () -> {
-            ProxyUtils.processInternal("abc");
-        });
-        assertNotNull(exception);
-    }
-}


Reply via email to