You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by il...@apache.org on 2019/09/19 08:27:34 UTC
[dubbo-admin] branch develop updated: Feature#23 (#437)
This is an automated email from the ASF dual-hosted git repository.
iluo pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git
The following commit(s) were added to refs/heads/develop by this push:
new 368d9dd Feature#23 (#437)
368d9dd is described below
commit 368d9dd17ea61b759fabb0e0c0f7bd5f08c092d7
Author: 孙不服 <su...@163.com>
AuthorDate: Thu Sep 19 16:27:29 2019 +0800
Feature#23 (#437)
* ace 行号栏 z-index 过高 #358
* Add a graph to display the call relationship of all applications #23
* code style
---
.../admin/controller/MetricsCollectController.java | 12 +-
.../apache/dubbo/admin/model/dto/RelationDTO.java | 216 +++++++++++++++++++++
.../apache/dubbo/admin/service/MetricsService.java | 24 +++
.../admin/service/impl/MetricsServiceImpl.java | 119 ++++++++++++
dubbo-admin-ui/src/api/menu.js | 12 +-
.../src/components/metrics/ServiceRelation.vue | 118 +++++++++++
dubbo-admin-ui/src/lang/en.js | 3 +
dubbo-admin-ui/src/lang/zh.js | 3 +
dubbo-admin-ui/src/router/index.js | 8 +-
9 files changed, 510 insertions(+), 5 deletions(-)
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MetricsCollectController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MetricsCollectController.java
index 9dfc43c..9c061a2 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MetricsCollectController.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MetricsCollectController.java
@@ -24,7 +24,9 @@ import org.apache.dubbo.admin.common.util.Tool;
import org.apache.dubbo.admin.model.domain.Consumer;
import org.apache.dubbo.admin.model.domain.Provider;
import org.apache.dubbo.admin.model.dto.MetricDTO;
+import org.apache.dubbo.admin.model.dto.RelationDTO;
import org.apache.dubbo.admin.service.ConsumerService;
+import org.apache.dubbo.admin.service.MetricsService;
import org.apache.dubbo.admin.service.ProviderService;
import org.apache.dubbo.admin.service.impl.MetrcisCollectServiceImpl;
import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
@@ -41,8 +43,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
-
@RestController
@RequestMapping("/api/{env}/metrics")
public class MetricsCollectController {
@@ -53,6 +53,9 @@ public class MetricsCollectController {
@Autowired
private ConsumerService consumerService;
+ @Autowired
+ private MetricsService metricsService;
+
@RequestMapping(method = RequestMethod.POST)
public String metricsCollect(@RequestParam String group, @PathVariable String env) {
MetrcisCollectServiceImpl service = new MetrcisCollectServiceImpl();
@@ -61,6 +64,11 @@ public class MetricsCollectController {
return service.invoke(group).toString();
}
+ @RequestMapping(value = "/relation", method = RequestMethod.GET)
+ public RelationDTO getApplicationRelation(){
+ return metricsService.getApplicationRelation();
+ }
+
private String getOnePortMessage(String group, String ip, String port, String protocol) {
MetrcisCollectServiceImpl metrcisCollectService = new MetrcisCollectServiceImpl();
metrcisCollectService.setUrl(protocol + "://" + ip + ":" + port +"?scope=remote&cache=true");
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/RelationDTO.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/RelationDTO.java
new file mode 100644
index 0000000..90edcf1
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/RelationDTO.java
@@ -0,0 +1,216 @@
+/*
+ * 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
+ *
+ * http://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.dubbo.admin.model.dto;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * relation about node for relation graph
+ */
+public class RelationDTO {
+
+ private List<Categories> categories;
+ private List<Node> nodes;
+ private List<Link> links;
+
+ public static final Categories CONSUMER_CATEGORIES = new RelationDTO.Categories(0, "consumer", "consumer");;
+ public static final Categories PROVIDER_CATEGORIES = new RelationDTO.Categories(1, "provider", "provider");
+ public static final Categories CONSUMER_AND_PROVIDER_CATEGORIES = new RelationDTO.Categories(2, "consumer and provider", "consumer and provider");
+
+ public static final List<RelationDTO.Categories> CATEGORIES_LIST = Arrays.asList(CONSUMER_CATEGORIES, PROVIDER_CATEGORIES, CONSUMER_AND_PROVIDER_CATEGORIES);
+
+ public RelationDTO() {
+ }
+
+ public RelationDTO(List<Node> nodes, List<Link> links) {
+ this.categories = CATEGORIES_LIST;
+ this.nodes = nodes;
+ this.links = links;
+ }
+
+ public static class Categories {
+ private Integer index;
+ private String name;
+ private String base;
+
+ public Categories() {
+ }
+
+ public Categories(Integer index, String name, String base) {
+ this.index = index;
+ this.name = name;
+ this.base = base;
+ }
+
+ public Integer getIndex() {
+ return index;
+ }
+
+ public void setIndex(Integer index) {
+ this.index = index;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getBase() {
+ return base;
+ }
+
+ public void setBase(String base) {
+ this.base = base;
+ }
+ }
+
+ public static class Node {
+
+ private Integer index;
+ private String name;
+ private int category;
+
+ public Node() {
+ }
+
+ public Node(Integer index, String name, int category) {
+ this.index = index;
+ this.name = name;
+ this.category = category;
+ }
+
+ public Integer getIndex() {
+ return index;
+ }
+
+ public void setIndex(Integer index) {
+ this.index = index;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getCategory() {
+ return category;
+ }
+
+ public void setCategory(int category) {
+ this.category = category;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Node node = (Node) o;
+ return category == node.category &&
+ index.equals(node.index) &&
+ name.equals(node.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(index, name, category);
+ }
+ }
+
+ public static class Link {
+
+ private int source;
+ private int target;
+
+ public Link() {
+ }
+
+ public Link(int source, int target) {
+ this.source = source;
+ this.target = target;
+ }
+
+ public int getSource() {
+ return source;
+ }
+
+ public void setSource(int source) {
+ this.source = source;
+ }
+
+ public int getTarget() {
+ return target;
+ }
+
+ public void setTarget(int target) {
+ this.target = target;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Link link = (Link) o;
+ return source == link.source &&
+ target == link.target;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(source, target);
+ }
+
+ @Override
+ public String toString() {
+ return "Link{" +
+ "source=" + source +
+ ", target=" + target +
+ '}';
+ }
+ }
+
+ public List<Categories> getCategories() {
+ return categories;
+ }
+
+ public void setCategories(List<Categories> categories) {
+ this.categories = categories;
+ }
+
+ public List<Node> getNodes() {
+ return nodes;
+ }
+
+ public void setNodes(List<Node> nodes) {
+ this.nodes = nodes;
+ }
+
+ public List<Link> getLinks() {
+ return links;
+ }
+
+ public void setLinks(List<Link> links) {
+ this.links = links;
+ }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/MetricsService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/MetricsService.java
new file mode 100644
index 0000000..6da25e0
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/MetricsService.java
@@ -0,0 +1,24 @@
+/*
+ * 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
+ *
+ * http://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.dubbo.admin.service;
+
+import org.apache.dubbo.admin.model.dto.RelationDTO;
+
+public interface MetricsService {
+
+ RelationDTO getApplicationRelation();
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/MetricsServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/MetricsServiceImpl.java
new file mode 100644
index 0000000..dee5f9f
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/MetricsServiceImpl.java
@@ -0,0 +1,119 @@
+/*
+ * 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
+ *
+ * http://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.dubbo.admin.service.impl;
+
+import org.apache.dubbo.admin.model.domain.Consumer;
+import org.apache.dubbo.admin.model.domain.Provider;
+import org.apache.dubbo.admin.model.dto.RelationDTO;
+import org.apache.dubbo.admin.service.ConsumerService;
+import org.apache.dubbo.admin.service.MetricsService;
+import org.apache.dubbo.admin.service.ProviderService;
+
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component
+public class MetricsServiceImpl implements MetricsService {
+
+ @Autowired
+ private ConsumerService consumerService;
+ @Autowired
+ private ProviderService providerService;
+
+ @Override
+ public RelationDTO getApplicationRelation() {
+
+ List<Consumer> consumerList = consumerService.findAll();
+ List<Provider> providerList = providerService.findAll();
+
+ int index = 0;
+ // collect all service
+ Set<String> serviceSet = new HashSet<>();
+
+ // collect consumer's nodes map <application, node>
+ Map<String, RelationDTO.Node> consumerNodeMap = new HashMap<>();
+ // collect consumer's service and applications map <service, set<application>>
+ Map<String, Set<String>> consumerServiceApplicationMap = new HashMap<>();
+ for (Consumer consumer : consumerList) {
+ String application = consumer.getApplication();
+ if (!consumerNodeMap.keySet().contains(application)) {
+ RelationDTO.Node node = new RelationDTO.Node(index, application, RelationDTO.CONSUMER_CATEGORIES.getIndex());
+ consumerNodeMap.put(application, node);
+ index++;
+ }
+ String service = consumer.getService();
+ serviceSet.add(service);
+ consumerServiceApplicationMap.computeIfAbsent(service, s -> new HashSet<>());
+ consumerServiceApplicationMap.get(service).add(application);
+ }
+ // collect provider's nodes
+ Map<String, RelationDTO.Node> providerNodeMap = new HashMap<>();
+ // collect provider's service and applications map <service, set<application>>
+ Map<String, Set<String>> providerServiceApplicationMap = new HashMap<>();
+ for (Provider provider : providerList) {
+ String application = provider.getApplication();
+ if (!providerNodeMap.keySet().contains(application)) {
+ RelationDTO.Node node = new RelationDTO.Node(index, application, RelationDTO.PROVIDER_CATEGORIES.getIndex());
+ providerNodeMap.put(application, node);
+ index++;
+ }
+ String service = provider.getService();
+ serviceSet.add(service);
+ providerServiceApplicationMap.computeIfAbsent(service, s -> new HashSet<>());
+ providerServiceApplicationMap.get(service).add(application);
+ }
+ // merge provider's nodes and consumer's nodes
+ Map<String, RelationDTO.Node> nodeMap = new HashMap<>(consumerNodeMap);
+ for (Map.Entry<String, RelationDTO.Node> entry : providerNodeMap.entrySet()) {
+ if (nodeMap.get(entry.getKey()) != null) {
+ nodeMap.get(entry.getKey()).setCategory(RelationDTO.CONSUMER_AND_PROVIDER_CATEGORIES.getIndex());
+ } else {
+ nodeMap.put(entry.getKey(), entry.getValue());
+ }
+ }
+ // build link by same service
+ Set<RelationDTO.Link> linkSet = new HashSet<>();
+ for (String service : serviceSet) {
+ Set<String> consumerApplicationSet = consumerServiceApplicationMap.get(service);
+ Set<String> providerApplicationSet = providerServiceApplicationMap.get(service);
+ if (CollectionUtils.isNotEmpty(consumerApplicationSet) && CollectionUtils.isNotEmpty(providerApplicationSet)) {
+ for (String providerApplication : providerApplicationSet) {
+ for (String consumerApplication : consumerApplicationSet) {
+ if (nodeMap.get(consumerApplication) != null && nodeMap.get(providerApplication) != null) {
+ Integer consumerIndex = nodeMap.get(consumerApplication).getIndex();
+ Integer providerIndex = nodeMap.get(providerApplication).getIndex();
+ linkSet.add(new RelationDTO.Link(consumerIndex, providerIndex));
+ }
+ }
+ }
+ }
+ }
+ // sort node by index
+ List<RelationDTO.Node> nodeList = nodeMap.values().stream().sorted(Comparator.comparingInt(RelationDTO.Node::getIndex)).collect(Collectors.toList());
+ return new RelationDTO(nodeList, new ArrayList<>(linkSet));
+ }
+}
diff --git a/dubbo-admin-ui/src/api/menu.js b/dubbo-admin-ui/src/api/menu.js
index fba2a05..3403f64 100644
--- a/dubbo-admin-ui/src/api/menu.js
+++ b/dubbo-admin-ui/src/api/menu.js
@@ -23,7 +23,7 @@ const Menu = [
group: 'governance',
items: [
{ title: 'routingRule', path: '/governance/routingRule' },
- {title: 'tagRule', path: '/governance/tagRule', badge: 'new'},
+ { title: 'tagRule', path: '/governance/tagRule', badge: 'new' },
{ title: 'accessControl', path: '/governance/access' },
{ title: 'dynamicConfig', path: '/governance/config' },
{ title: 'weightAdjust', path: '/governance/weight' },
@@ -32,7 +32,15 @@ const Menu = [
},
{ title: 'serviceTest', path: '/test', icon: 'code' },
{ title: 'serviceMock', path: '/mock', icon: 'build', badge: 'feature' },
- { title: 'metrics', path: '/metrics', icon: 'show_chart', badge: 'feature' },
+ {
+ title: 'serviceMetrics',
+ path: 'metrics',
+ icon: 'show_chart',
+ items: [
+ { title: 'serviceMetrics', path: '/metrics/index', badge: 'feature' },
+ { title: 'serviceRelation', path: '/metrics/relation', badge: 'new' }
+ ]
+ },
{ title: 'configManage', path: '/management', icon: 'build' }
]
diff --git a/dubbo-admin-ui/src/components/metrics/ServiceRelation.vue b/dubbo-admin-ui/src/components/metrics/ServiceRelation.vue
new file mode 100644
index 0000000..55dee6c
--- /dev/null
+++ b/dubbo-admin-ui/src/components/metrics/ServiceRelation.vue
@@ -0,0 +1,118 @@
+<!--
+ - 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
+ -
+ - http://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.
+ -->
+
+<template>
+ <v-container grid-list-xl fluid >
+ <v-layout row wrap>
+ <v-flex lg12>
+ <breadcrumb title="serviceRelation" :items="breads"></breadcrumb>
+ </v-flex>
+ </v-layout>
+
+ <v-flex lg12>
+ <v-card>
+ <div id="chartContent" style="width:100%;height:500%;"/>
+ </v-card>
+ </v-flex>
+
+ </v-container>
+
+</template>
+<script>
+ import Breadcrumb from '@/components/public/Breadcrumb'
+ import axios from 'axios'
+ export default {
+ components: {
+ Breadcrumb,
+ axios
+ },
+ data: () => ({
+ baseURL: '/api/dev',
+ success: null,
+ breads: [
+ {
+ text: 'serviceMetrics',
+ href: ''
+ },
+ {
+ text: 'serviceRelation',
+ href: ''
+ }
+ ],
+ responseData: null
+ }),
+ methods: {
+ initData: function () {
+ // eslint-disable-next-line no-undef
+ this.chartContent = echarts.init(document.getElementById('chartContent'))
+ this.chartContent.showLoading()
+ axios.get(this.baseURL + '/metrics/relation')
+ .then(response => {
+ if (response && response.status === 200) {
+ this.success = true
+ this.responseData = response.data
+ this.responseData.type = 'force'
+ this.initChart(this.responseData)
+ }
+ })
+ .catch(error => {
+ this.success = false
+ this.responseData = error.response.data
+ })
+ },
+ initChart: function (data) {
+ this.chartContent.hideLoading()
+
+ const option = {
+ legend: {
+ top: 'bottom',
+ data: data.categories.map(i => i.name)
+ },
+ series: [{
+ type: 'graph',
+ layout: 'force',
+ animation: false,
+ label: {
+ normal: {
+ show: true,
+ position: 'right'
+ }
+ },
+ draggable: true,
+ data: data.nodes.map(function (node, idx) {
+ node.id = idx
+ return node
+ }),
+ categories: this.responseData.categories,
+ force: {
+ edgeLength: 100,
+ repulsion: 10
+ },
+ edges: data.links,
+ edgeSymbol: ['', 'arrow'],
+ edgeSymbolSize: 7
+ }]
+ }
+ this.chartContent.setOption(option)
+ }
+ },
+ mounted: function () {
+ this.initData()
+ }
+
+ }
+</script>
diff --git a/dubbo-admin-ui/src/lang/en.js b/dubbo-admin-ui/src/lang/en.js
index adc826b..d8f44ef 100644
--- a/dubbo-admin-ui/src/lang/en.js
+++ b/dubbo-admin-ui/src/lang/en.js
@@ -26,7 +26,10 @@ export default {
loadBalance: 'Load Balance',
serviceTest: 'Service Test',
serviceMock: 'Service Mock',
+ serviceMetrics: 'Service Metrics',
+ serviceRelation: 'Service Relation',
metrics: 'Metrics',
+ relation: 'Relation',
group: 'Group',
serviceInfo: 'Service Info',
providers: 'Providers',
diff --git a/dubbo-admin-ui/src/lang/zh.js b/dubbo-admin-ui/src/lang/zh.js
index e1abcc5..d13f7b6 100644
--- a/dubbo-admin-ui/src/lang/zh.js
+++ b/dubbo-admin-ui/src/lang/zh.js
@@ -18,6 +18,8 @@ export default {
service: '服务',
serviceSearch: '服务查询',
serviceGovernance: '服务治理',
+ serviceMetrics: '服务统计',
+ serviceRelation: '服务关系',
routingRule: '条件路由',
tagRule: '标签路由',
dynamicConfig: '动态配置',
@@ -29,6 +31,7 @@ export default {
providers: '提供者',
consumers: '消费者',
metrics: '统计',
+ relation: '关系',
group: '组',
version: '版本',
app: '应用',
diff --git a/dubbo-admin-ui/src/router/index.js b/dubbo-admin-ui/src/router/index.js
index 35f8a90..4b1d318 100644
--- a/dubbo-admin-ui/src/router/index.js
+++ b/dubbo-admin-ui/src/router/index.js
@@ -29,6 +29,7 @@ import Overrides from '@/components/governance/Overrides'
import ServiceTest from '@/components/test/ServiceTest'
import ServiceMock from '@/components/test/ServiceMock'
import ServiceMetrics from '@/components/metrics/ServiceMetrics'
+import ServiceRelation from '@/components/metrics/ServiceRelation'
import Management from '@/components/Management'
Vue.use(Router)
@@ -90,11 +91,16 @@ export default new Router({
component: ServiceMock
},
{
- path: '/metrics',
+ path: '/metrics/index',
name: 'ServiceMetrics',
component: ServiceMetrics
},
{
+ path: '/metrics/relation',
+ name: 'ServiceRelation',
+ component: ServiceRelation
+ },
+ {
path: '/management',
name: 'Management',
component: Management