Fix namespace stats display info (#146)
### Modifications
* Obtaining namespace Statistics from Backend
* Fix broker stats display
* Fix MapperScan when spring boot start
diff --git a/front-end/src/api/namespaces.js b/front-end/src/api/namespaces.js
index 27280e3..a909699 100644
--- a/front-end/src/api/namespaces.js
+++ b/front-end/src/api/namespaces.js
@@ -25,6 +25,13 @@
})
}
+export function fetchNamespaceStats(tenant, namespace) {
+ return request({
+ url: SPRING_BASE_URL_V2 + `/namespaces/${tenant}/${namespace}/stats`,
+ method: 'get'
+ })
+}
+
export function fetchNamespacePolicies(tenantNamespace) {
return request({
url: BASE_URL_V2 + `/namespaces/${tenantNamespace}`,
diff --git a/front-end/src/views/management/brokers/broker.vue b/front-end/src/views/management/brokers/broker.vue
index 6f59657..5ae56d5 100644
--- a/front-end/src/views/management/brokers/broker.vue
+++ b/front-end/src/views/management/brokers/broker.vue
@@ -184,10 +184,10 @@
}
}
this.brokerStats.push({
- 'inBytes': throughputIn,
- 'outBytes': throughputOut,
- 'inMsg': bandwidthIn,
- 'outMsg': bandwidthOut
+ 'inBytes': throughputIn.toFixed(2),
+ 'outBytes': throughputOut.toFixed(2),
+ 'inMsg': bandwidthIn.toFixed(2),
+ 'outMsg': bandwidthOut.toFixed(2)
})
})
},
diff --git a/front-end/src/views/management/clusters/cluster.vue b/front-end/src/views/management/clusters/cluster.vue
index 3af4e1e..314e8a5 100644
--- a/front-end/src/views/management/clusters/cluster.vue
+++ b/front-end/src/views/management/clusters/cluster.vue
@@ -112,7 +112,7 @@
border
fit
highlight-current-row
- style="width: 100%;">
+ style="margin-top:10px">
<el-table-column :label="$t('ip.nameLabel')" min-width="50px" align="center">
<template slot-scope="scope">
<router-link :to="'/management/clusters/' + scope.row.cluster + '/' + scope.row.isolationPolicy + '/namespaceIsolationPolicy'" class="link-type">
@@ -422,10 +422,10 @@
}
}
brokerInfo['ownedNamespaces'] = numberNamespaces
- brokerInfo['throughputIn'] = throughputIn
- brokerInfo['throughputOut'] = throughputOut
- brokerInfo['msgRateOut'] = msgRateOut
- brokerInfo['msgRateIn'] = msgRateIn
+ brokerInfo['throughputIn'] = throughputIn.toFixed(2)
+ brokerInfo['throughputOut'] = throughputOut.toFixed(2)
+ brokerInfo['msgRateOut'] = msgRateOut.toFixed(2)
+ brokerInfo['msgRateIn'] = msgRateIn.toFixed(2)
})
this.brokersList.push(brokerInfo)
}
diff --git a/front-end/src/views/management/namespaces/namespace.vue b/front-end/src/views/management/namespaces/namespace.vue
index c95a4ad..64550af 100644
--- a/front-end/src/views/management/namespaces/namespace.vue
+++ b/front-end/src/views/management/namespaces/namespace.vue
@@ -677,7 +677,8 @@
unloadOnCluster,
clearBacklogOnCluster,
deleteNamespace,
- clearBundleBacklogOnCluster
+ clearBundleBacklogOnCluster,
+ fetchNamespaceStats
} from '@/api/namespaces'
import { putTopic, fetchTopicsStatsByPulsarManager } from '@/api/topics'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
@@ -896,7 +897,20 @@
this.activeBundleCluster = this.replicationClustersValue.length > 0 ? this.replicationClustersValue[0] : ''
},
methods: {
+ getNamespaceStats() {
+ fetchNamespaceStats(this.postForm.tenant, this.postForm.namespace).then(response => {
+ if (!response.data) return
+ this.namespaceStats = []
+ this.namespaceStats.push({
+ inMsg: response.data.inMsg,
+ outMsg: response.data.outMsg,
+ inBytes: response.data.msgThroughputIn,
+ outBytes: response.data.msgThroughputOut
+ })
+ })
+ },
getStats() {
+ this.getNamespaceStats()
this.getTopics()
},
getTopicsStats() {
diff --git a/src/main/java/io/streamnative/pulsar/manager/PulsarManagerApplication.java b/src/main/java/io/streamnative/pulsar/manager/PulsarManagerApplication.java
index b707da1..0142c9c 100644
--- a/src/main/java/io/streamnative/pulsar/manager/PulsarManagerApplication.java
+++ b/src/main/java/io/streamnative/pulsar/manager/PulsarManagerApplication.java
@@ -20,7 +20,7 @@
@SpringBootApplication
@EnableZuulProxy
-@MapperScan("com.manager.pulsar.mapper")
+@MapperScan("io.streamnative.pulsar.manager.mapper")
public class PulsarManagerApplication {
public static void main(String[] args) {
diff --git a/src/main/java/io/streamnative/pulsar/manager/controller/NamespacesController.java b/src/main/java/io/streamnative/pulsar/manager/controller/NamespacesController.java
index f013348..6faefa4 100644
--- a/src/main/java/io/streamnative/pulsar/manager/controller/NamespacesController.java
+++ b/src/main/java/io/streamnative/pulsar/manager/controller/NamespacesController.java
@@ -123,4 +123,22 @@
return ResponseEntity.ok(namespacesEntity);
}
+ @ApiOperation(value = "Query namespace stats info by tenant and namespace")
+ @ApiResponses({
+ @ApiResponse(code = 200, message = "ok"),
+ @ApiResponse(code = 500, message = "Internal server error")
+ })
+ @RequestMapping(value = "/namespaces/{tenant}/{namespace}/stats", method = RequestMethod.GET)
+ public ResponseEntity<Map<String, Object>> getNamespacesStats(
+ @ApiParam(value = "The name of tenant")
+ @Size(min = 1, max = 255)
+ @PathVariable String tenant,
+ @ApiParam(value = "The name of namespace")
+ @Size(min = 1, max = 255)
+ @PathVariable String namespace) {
+ String env = request.getHeader("environment");
+ Map<String, Object> namespaceStats = namespacesService.getNamespaceStats(tenant, namespace, env);
+ return ResponseEntity.ok(namespaceStats);
+ }
+
}
diff --git a/src/main/java/io/streamnative/pulsar/manager/dao/TopicsStatsRepositoryImpl.java b/src/main/java/io/streamnative/pulsar/manager/dao/TopicsStatsRepositoryImpl.java
index db3bc86..5802f45 100644
--- a/src/main/java/io/streamnative/pulsar/manager/dao/TopicsStatsRepositoryImpl.java
+++ b/src/main/java/io/streamnative/pulsar/manager/dao/TopicsStatsRepositoryImpl.java
@@ -56,13 +56,12 @@
public Page<TopicStatsEntity> findByNamespace(Integer pageNum,
Integer pageSize,
String environment,
- String cluster,
String tenant,
String namespace,
long timestamp) {
PageHelper.startPage(pageNum, pageSize);
Page<TopicStatsEntity> topicStatsEntities =
- topicsStatsMapper.findByNamespace(environment, cluster, tenant, namespace, timestamp);
+ topicsStatsMapper.findByNamespace(environment, tenant, namespace, timestamp);
return topicStatsEntities;
}
diff --git a/src/main/java/io/streamnative/pulsar/manager/entity/TopicsStatsRepository.java b/src/main/java/io/streamnative/pulsar/manager/entity/TopicsStatsRepository.java
index d4db0b8..aaa21ae 100644
--- a/src/main/java/io/streamnative/pulsar/manager/entity/TopicsStatsRepository.java
+++ b/src/main/java/io/streamnative/pulsar/manager/entity/TopicsStatsRepository.java
@@ -35,7 +35,6 @@
Page<TopicStatsEntity> findByNamespace(Integer pageNum,
Integer pageSize,
String environment,
- String cluster,
String tenant,
String namespace,
long timestamp);
diff --git a/src/main/java/io/streamnative/pulsar/manager/mapper/TopicsStatsMapper.java b/src/main/java/io/streamnative/pulsar/manager/mapper/TopicsStatsMapper.java
index 1d8fece..b70d466 100644
--- a/src/main/java/io/streamnative/pulsar/manager/mapper/TopicsStatsMapper.java
+++ b/src/main/java/io/streamnative/pulsar/manager/mapper/TopicsStatsMapper.java
@@ -47,11 +47,10 @@
@Select("SELECT topicStatsId,environment,cluster,tenant,namespace,bundle,persistent,topic,producerCount,subscriptionCount," +
"msgRateIn,msgThroughputIn,msgRateOut,msgThroughputOut,averageMsgSize,storageSize,timestamp FROM topicsStats " +
- "WHERE cluster=#{cluster} and environment=#{environment} and tenant=#{tenant} and namespace=#{namespace} " +
+ "WHERE environment=#{environment} and tenant=#{tenant} and namespace=#{namespace} " +
"and timestamp=#{timestamp}")
Page<TopicStatsEntity> findByNamespace(
@Param("environment") String environment,
- @Param("cluster") String cluster,
@Param("tenant") String tenant,
@Param("namespace") String namespace,
@Param("timestamp") long timestamp);
diff --git a/src/main/java/io/streamnative/pulsar/manager/service/NamespacesService.java b/src/main/java/io/streamnative/pulsar/manager/service/NamespacesService.java
index 5cbdc96..c1dea4c 100644
--- a/src/main/java/io/streamnative/pulsar/manager/service/NamespacesService.java
+++ b/src/main/java/io/streamnative/pulsar/manager/service/NamespacesService.java
@@ -13,6 +13,8 @@
*/
package io.streamnative.pulsar.manager.service;
+import com.google.common.collect.Maps;
+
import java.util.Map;
public interface NamespacesService {
@@ -20,4 +22,5 @@
Map<String, Object> getNamespaceList(
Integer pageNum, Integer pageSize, String tenant, String requestHost);
+ Map<String, Object> getNamespaceStats(String tenant, String namespace, String env);
}
\ No newline at end of file
diff --git a/src/main/java/io/streamnative/pulsar/manager/service/impl/NamespacesServiceImpl.java b/src/main/java/io/streamnative/pulsar/manager/service/impl/NamespacesServiceImpl.java
index 61c1fc3..b5ec5bf 100644
--- a/src/main/java/io/streamnative/pulsar/manager/service/impl/NamespacesServiceImpl.java
+++ b/src/main/java/io/streamnative/pulsar/manager/service/impl/NamespacesServiceImpl.java
@@ -13,9 +13,12 @@
*/
package io.streamnative.pulsar.manager.service.impl;
+import com.github.pagehelper.Page;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
+import io.streamnative.pulsar.manager.entity.TopicStatsEntity;
+import io.streamnative.pulsar.manager.entity.TopicsStatsRepository;
import io.streamnative.pulsar.manager.service.NamespacesService;
import io.streamnative.pulsar.manager.service.TopicsService;
import io.streamnative.pulsar.manager.utils.HttpUtil;
@@ -23,9 +26,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
@Service
public class NamespacesServiceImpl implements NamespacesService {
@@ -34,6 +35,9 @@
private boolean directRequestBroker;
@Autowired
+ private TopicsStatsRepository topicsStatsRepository;
+
+ @Autowired
private TopicsService topicsService;
public Map<String, Object> getNamespaceList(Integer pageNum, Integer pageSize, String tenant, String requestHost) {
@@ -65,4 +69,35 @@
return namespacesMap;
}
+ public Map<String, Object> getNamespaceStats(
+ String tenant,
+ String namespace,
+ String env) {
+ Map<String, Object> namespaceStatsMap = Maps.newHashMap();
+ Optional<TopicStatsEntity> topicStatsEntity = topicsStatsRepository.findMaxTime();
+ if (topicStatsEntity.isPresent()) {
+ double msgRateIn = 0;
+ double msgThroughputIn = 0;
+ double msgRateOut = 0;
+ double msgThroughputOut = 0;
+ TopicStatsEntity topicStats = topicStatsEntity.get();
+ Page<TopicStatsEntity> topicCountPage = topicsStatsRepository.findByNamespace(
+ 1, 1, env, tenant, namespace, topicStats.getTimestamp());
+ topicCountPage.count(true);
+ Page<TopicStatsEntity> topicStatsEntities = topicsStatsRepository.findByNamespace(
+ 1, (int) topicCountPage.getTotal(), env, tenant, namespace, topicStats.getTimestamp());
+ for (TopicStatsEntity statsEntity : topicStatsEntities.getResult()) {
+ msgRateIn += statsEntity.getMsgRateIn();
+ msgRateOut += statsEntity.getMsgRateOut();
+ msgThroughputIn += statsEntity.getMsgThroughputIn();
+ msgThroughputOut += statsEntity.getMsgThroughputOut();
+ }
+ namespaceStatsMap.put("inMsg", msgRateIn);
+ namespaceStatsMap.put("outMsg", msgRateOut);
+ namespaceStatsMap.put("msgThroughputIn", msgThroughputIn);
+ namespaceStatsMap.put("msgThroughputOut", msgThroughputOut);
+ }
+ return namespaceStatsMap;
+ }
+
}
\ No newline at end of file
diff --git a/src/test/java/io/streamnative/pulsar/manager/service/NamespacesServiceImplTest.java b/src/test/java/io/streamnative/pulsar/manager/service/NamespacesServiceImplTest.java
index e2547af..5bc2373 100644
--- a/src/test/java/io/streamnative/pulsar/manager/service/NamespacesServiceImplTest.java
+++ b/src/test/java/io/streamnative/pulsar/manager/service/NamespacesServiceImplTest.java
@@ -30,6 +30,7 @@
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
+import java.util.List;
import java.util.Map;
@RunWith(PowerMockRunner.class)
@@ -48,6 +49,9 @@
@Autowired
private NamespacesService namespacesService;
+ @Autowired
+ private BrokerStatsService brokerStatsService;
+
@Test
public void namespaceServiceImplTest() {
PowerMockito.mockStatic(HttpUtil.class);
@@ -66,4 +70,40 @@
Assert.assertFalse((Boolean) result.get("isPage"));
Assert.assertEquals(result.get("data").toString(), "[{topics=1, namespace=default}]");
}
+
+ @Test
+ public void getNamespaceStatsTest() {
+ PowerMockito.mockStatic(HttpUtil.class);
+ Map<String, String> header = Maps.newHashMap();
+ header.put("Content-Type", "application/json");
+ PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/clusters", header))
+ .thenReturn("[\"standalone\"]");
+
+ PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/brokers/standalone", header))
+ .thenReturn("[\"localhost:8080\"]");
+ PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/broker-stats/topics", header))
+ .thenReturn(BrokerStatsServiceImplTest.testData);
+ PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/clusters/standalone/failureDomains", header))
+ .thenReturn("{}");
+ PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/clusters/standalone", header))
+ .thenReturn("{\n" +
+ "\"serviceUrl\" : \"http://tengdeMBP:8080\",\n" +
+ "\"brokerServiceUrl\" : \"pulsar://tengdeMBP:6650\"\n" +
+ "}");
+ String environment = "staging";
+ String cluster = "standalone";
+ String serviceUrl = "http://localhost:8080";
+ brokerStatsService.collectStatsToDB(
+ System.currentTimeMillis() / 1000,
+ environment,
+ cluster,
+ serviceUrl
+ );
+ Map<String, Object> namespaceStats = namespacesService.getNamespaceStats(
+ environment, "public", "functions");
+ Assert.assertEquals(namespaceStats.get("outMsg"), 0.0);
+ Assert.assertEquals(namespaceStats.get("inMsg"), 0.0);
+ Assert.assertEquals(namespaceStats.get("msgThroughputIn"), 0.0);
+ Assert.assertEquals(namespaceStats.get("msgThroughputOut"), 0.0);
+ }
}