Refactor service page with v6
diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 28819b2..c415afe 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -1,13 +1,11 @@
import fs from 'fs';
import { delay } from 'roadhog-api-doc';
-import { getTopology, getGlobalTopology, getServiceTopology } from './mock/topology';
-import { getAllApplication, getApplication } from './mock/application';
-import { searchServer, getServer } from './mock/server';
+import { getGlobalTopology, getServiceTopology } from './mock/topology';
import { Alarms, getNoticeAlarm, AlarmTrend } from './mock/alarm';
import { TraceBrief, Trace } from './mock/trace'
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import { graphql } from 'graphql';
-import { ClusterBrief, getAllServices, searchEndpoint } from './mock/metadata';
+import { ClusterBrief, getServiceInstances, getAllServices, searchEndpoint } from './mock/metadata';
import { IntValues, Thermodynamic } from './mock/metric';
import { getTopN } from './mock/aggregation';
@@ -17,6 +15,7 @@
Query: {
getTopN,
getAllServices,
+ getServiceInstances,
getGlobalTopology,
getServiceTopology,
searchEndpoint,
@@ -54,11 +53,6 @@
const { query: source, variables: variableValues } = req.body;
graphql({ schema, source, variableValues }).then((result) => res.send(result));
},
- 'POST /api/topology': getTopology,
- 'POST /api/application/options': getAllApplication,
- 'POST /api/application': getApplication,
- 'POST /api/server/search': searchServer,
- 'POST /api/server': getServer,
'POST /api/notice': getNoticeAlarm,
'POST /api/login/account': (req, res) => {
const { password, userName } = req.body;
diff --git a/mock/aggregation.js b/mock/aggregation.js
index e03c16a..3047ce3 100644
--- a/mock/aggregation.js
+++ b/mock/aggregation.js
@@ -24,6 +24,8 @@
array = mockjs.mock({ 'array|10': [{ 'id|+1': 1, name: '@url', 'value|200-1000': 1 }]});
} else if (args.condition.filterScope === 'SERVICE') {
array = mockjs.mock({ 'array|10': [{ 'id|+1': 1, name: '@name', 'value|100-10000': 1 }]});
+ } else if (args.condition.filterScope === 'SERVICE_INSTANCE') {
+ array = mockjs.mock({ 'array|10': [{ 'id|+1': 1, name: '@name', 'value|100-10000': 1 }]});
}
return array.array;
},
diff --git a/mock/metadata.js b/mock/metadata.js
index 12fe2c3..4fdf8d4 100644
--- a/mock/metadata.js
+++ b/mock/metadata.js
@@ -24,8 +24,35 @@
'numOfDatabase|1-100': 1,
'numOfCache|1-100': 1,
'numOfMQ|1-100': 1,
- })
- ,
+ }),
+ getServiceInstances: () => {
+ const data = mockjs.mock({
+ 'id|1-10': [{
+ 'id|+1': 3,
+ name: '@natural(4, 20)',
+ attributes: [
+ {
+ name: 'os',
+ value: 'LINUX',
+ },
+ {
+ name: 'host',
+ value: 'WORKSAPCE-@name',
+ },
+ {
+ name: 'pid',
+ value: '@natural(4, 20)',
+ },
+ {
+ name: 'ipv4',
+ value: '@ip',
+ },
+ ],
+ 'language|1': ['JAVA', 'RUBY', 'DOTNET'],
+ }], // eslint-disable-line
+ });
+ return data.id;
+ },
getAllServices: () => {
const data = mockjs.mock({
'serviceId|20-50': [{ 'id|+1': 3, name: function() { return `service-${this.id}`; } }], // eslint-disable-line
diff --git a/mock/topology.js b/mock/topology.js
index fd1fe86..7a82c64 100644
--- a/mock/topology.js
+++ b/mock/topology.js
@@ -26,15 +26,17 @@
'id|+1': 100,
name: '@url',
'type|1': ['DUBBO', 'USER', 'SPRINGMVC'],
+ isReal: true,
},
],
});
const centerNodes = mockjs.mock({
nodes: [
{
- 'id|+1': 1,
+ 'id|+1': 10,
name: '@url',
'type|1': ['DUBBO', 'tomcat', 'SPRINGMVC'],
+ isReal: true,
},
],
});
@@ -44,6 +46,7 @@
'id|+1': 200,
name: '@url',
'type|1': ['Oracle', 'MYSQL', 'REDIS'],
+ isReal: false,
},
],
});
@@ -51,18 +54,16 @@
const nodes = upNodes.nodes.concat(centerNodes.nodes, downNodes.nodes);
const calls = upNodes.nodes.map(node => (mockjs.mock({
source: node.id,
- target: 1,
- 'isAlert|1': true,
+ target: 10,
'callType|1': ['rpc', 'http', 'dubbo'],
'cpm|0-1000': 1,
}))).concat(downNodes.nodes.map(node => (mockjs.mock({
- source: 1,
+ source: 10,
target: node.id,
- 'isAlert|1': true,
'callType|1': ['rpc', 'http', 'dubbo'],
'cpm|0-2000': 1,
}))));
- calls.push({ source: '-175', target: 1, isAlert: false, callType: 'GRPC', cpm: 0, avgResponseTime: 52 });
+ calls.push({ source: '-175', target: 10, callType: 'GRPC', cpm: 0 });
return {
nodes,
calls,
diff --git a/src/common/menu.js b/src/common/menu.js
index bc98328..eb64c7c 100644
--- a/src/common/menu.js
+++ b/src/common/menu.js
@@ -31,8 +31,8 @@
name: 'Topology',
path: 'topology',
}, {
- name: 'Application',
- path: 'application',
+ name: 'Service',
+ path: 'service',
}, {
name: 'Endpoint',
path: 'endpoint',
diff --git a/src/common/router.js b/src/common/router.js
index db30edd..6cbbf87 100644
--- a/src/common/router.js
+++ b/src/common/router.js
@@ -97,8 +97,8 @@
'/monitor/topology': {
component: dynamicWrapper(app, ['topology'], () => import('../routes/Topology/Topology')),
},
- '/monitor/application': {
- component: dynamicWrapper(app, ['application'], () => import('../routes/Application/Application')),
+ '/monitor/service': {
+ component: dynamicWrapper(app, ['service'], () => import('../routes/Service/Service')),
},
'/monitor/endpoint': {
component: dynamicWrapper(app, ['endpoint'], () => import('../routes/Endpoint/Endpoint')),
diff --git a/src/components/ServerLitePanel/index.js b/src/components/ServerLitePanel/index.js
deleted file mode 100644
index a3d896c..0000000
--- a/src/components/ServerLitePanel/index.js
+++ /dev/null
@@ -1,100 +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
- *
- * 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.
- */
-
-
-import React, { PureComponent } from 'react';
-import { Row, Col, Card, Select, Icon } from 'antd';
-import {
- ChartCard, MiniArea, MiniBar,
-} from "../Charts";
-import DescriptionList from "../DescriptionList";
-import { axis } from '../../utils/time';
-import { avgTimeSeries, getServerId } from '../../utils/utils';
-
-const { Option } = Select;
-const { Description } = DescriptionList;
-
-export default class ServerLitePanel extends PureComponent {
- bytesToMB = list => list.map(_ => parseFloat((_ / (1024 ** 2)).toFixed(2)))
-
- render() {
- const { serverList, duration, data, onSelectServer, onMoreServer } = this.props;
- if (serverList.length < 1) {
- return null;
- }
- const { serverInfo, getServerResponseTimeTrend, getServerThroughputTrend } = data;
- if (!serverInfo.key) {
- onSelectServer(serverList[0].key, serverList[0]);
- }
- return (
- <div>
- <Row gutter={0}>
- <Col span={24}>
- <Select
- size="small"
- value={serverInfo.key}
- onChange={value => onSelectServer(value, serverList.find(_ => _.key === value))}
- style={{ width: '100%' }}
- >
- {serverList.map(_ => <Option key={_.key} value={_.key}>{getServerId(_)}</Option>)}
- </Select>
- </Col>
- <Col span={24}>
- <Card bordered={false} bodyStyle={{ padding: 5 }}>
- <DescriptionList col={1} gutter={0} size="small">
- <Description term="Host">{serverInfo.host}</Description>
- <Description term="OS">{serverInfo.osName}</Description>
- </DescriptionList>
- </Card>
- </Col>
- <Col span={24}>
- <ChartCard
- title="Avg Throughput"
- total={`${avgTimeSeries(getServerThroughputTrend.trendList)} cpm`}
- contentHeight={46}
- bordered={false}
- bodyStyle={{ padding: 5 }}
- >
- <MiniBar
- data={axis(duration, getServerThroughputTrend.trendList)}
- color="#975FE4"
- />
- </ChartCard>
- </Col>
- <Col span={24}>
- <ChartCard
- title="Avg Response Time"
- total={`${avgTimeSeries(getServerResponseTimeTrend.trendList)} ms`}
- contentHeight={46}
- bordered={false}
- bodyStyle={{ padding: 5 }}
- >
- {getServerResponseTimeTrend.trendList.length > 0 ? (
- <MiniArea
- animate={false}
- color="#87cefa"
- data={axis(duration, getServerResponseTimeTrend.trendList)}
- />
- ) : (<span style={{ display: 'none' }} />)}
- </ChartCard>
- </Col>
- </Row>
- {serverInfo.key ? <a style={{ float: 'right' }} onClick={onMoreServer}> More Server Details<Icon type="ellipsis" /> </a> : null}
- </div>
- );
- }
-}
diff --git a/src/components/ServiceInstanceLitePanel/index.js b/src/components/ServiceInstanceLitePanel/index.js
new file mode 100644
index 0000000..dbe64ee
--- /dev/null
+++ b/src/components/ServiceInstanceLitePanel/index.js
@@ -0,0 +1,101 @@
+/**
+ * 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.
+ */
+
+
+import React, { PureComponent } from 'react';
+import { Row, Col, Card, Select, Icon } from 'antd';
+import {
+ ChartCard, MiniArea, MiniBar,
+} from "../Charts";
+import DescriptionList from "../DescriptionList";
+import { axisY } from '../../utils/time';
+import { avgTS, getAttributes, getServiceInstanceId } from '../../utils/utils';
+
+const { Option } = Select;
+const { Description } = DescriptionList;
+
+export default class ServiceInstanceLitePanel extends PureComponent {
+ bytesToMB = list => list.map(_ => parseFloat((_ / (1024 ** 2)).toFixed(2)))
+
+ render() {
+ const { serviceInstanceList, duration, data, onSelectServiceInstance, onMoreServiceInstance } = this.props;
+ if (serviceInstanceList.length < 1) {
+ return null;
+ }
+ const { serviceInstanceInfo, getServiceInstanceResponseTimeTrend, getServiceInstanceThroughputTrend } = data;
+ if (!serviceInstanceInfo.key) {
+ onSelectServiceInstance(serviceInstanceList[0].key, serviceInstanceList[0]);
+ }
+ const { attributes } = serviceInstanceInfo;
+ return (
+ <div>
+ <Row gutter={0}>
+ <Col span={24}>
+ <Select
+ size="small"
+ value={serviceInstanceInfo.key}
+ onChange={value => onSelectServiceInstance(value, serviceInstanceList.find(_ => _.key === value))}
+ style={{ width: '100%' }}
+ >
+ {serviceInstanceList.map(_ => <Option key={_.key} value={_.key}>{getServiceInstanceId(_)}</Option>)}
+ </Select>
+ </Col>
+ <Col span={24}>
+ <Card bordered={false} bodyStyle={{ padding: 5 }}>
+ <DescriptionList col={1} gutter={0} size="small">
+ <Description term="Host">{getAttributes(attributes, 'host')}</Description>
+ <Description term="OS">{getAttributes(attributes, 'os')}</Description>
+ </DescriptionList>
+ </Card>
+ </Col>
+ <Col span={24}>
+ <ChartCard
+ title="Avg Throughput"
+ total={`${avgTS(getServiceInstanceThroughputTrend.values)} cpm`}
+ contentHeight={46}
+ bordered={false}
+ bodyStyle={{ padding: 5 }}
+ >
+ <MiniBar
+ data={axisY(duration, getServiceInstanceThroughputTrend.values)}
+ color="#975FE4"
+ />
+ </ChartCard>
+ </Col>
+ <Col span={24}>
+ <ChartCard
+ title="Avg Response Time"
+ total={`${avgTS(getServiceInstanceResponseTimeTrend.values)} ms`}
+ contentHeight={46}
+ bordered={false}
+ bodyStyle={{ padding: 5 }}
+ >
+ {getServiceInstanceResponseTimeTrend.values.length > 0 ? (
+ <MiniArea
+ animate={false}
+ color="#87cefa"
+ data={axisY(duration, getServiceInstanceResponseTimeTrend.values)}
+ />
+ ) : (<span style={{ display: 'none' }} />)}
+ </ChartCard>
+ </Col>
+ </Row>
+ {serviceInstanceInfo.key ? <a style={{ float: 'right' }} onClick={onMoreServiceInstance}> More Server Details<Icon type="ellipsis" /> </a> : null}
+ </div>
+ );
+ }
+}
diff --git a/src/models/application.js b/src/models/application.js
deleted file mode 100644
index cd40b39..0000000
--- a/src/models/application.js
+++ /dev/null
@@ -1,238 +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
- *
- * 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.
- */
-
-
-import { generateModal } from '../utils/models';
-import { query as queryService } from '../services/graphql';
-
-const optionsQuery = `
- query ApplicationOption($duration: Duration!) {
- applicationId: getAllApplication(duration: $duration) {
- key: id
- label: name
- }
- }
-`;
-
-const dataQuery = `
- query Application($applicationId: ID!, $duration: Duration!) {
- getSlowService(applicationId: $applicationId, duration: $duration, topN: 10) {
- service {
- key: id
- label: name
- applicationId
- applicationName
- }
- value: avgResponseTime
- }
- getServerThroughput(applicationId: $applicationId, duration: $duration, topN: 999999) {
- key: id
- osName
- host
- pid
- ipv4
- value: cpm
- }
- getApplicationTopology(applicationId: $applicationId, duration: $duration) {
- nodes {
- id
- name
- type
- ... on ApplicationNode {
- sla
- cpm
- avgResponseTime
- apdex
- isAlarm
- numOfServer
- numOfServerAlarm
- numOfServiceAlarm
- }
- }
- calls {
- source
- target
- isAlert
- callType
- cpm
- avgResponseTime
- }
- }
- }
-`;
-
-const serverQuery = `
-query Application($serverId: ID!, $duration: Duration!) {
- getServerResponseTimeTrend(serverId: $serverId, duration: $duration) {
- trendList
- }
- getServerThroughputTrend(serverId: $serverId, duration: $duration) {
- trendList
- }
- getCPUTrend(serverId: $serverId, duration: $duration) {
- cost
- }
- getGCTrend(serverId: $serverId, duration: $duration) {
- youngGCCount
- oldGCount
- youngGCTime
- oldGCTime
- }
- getMemoryTrend(serverId: $serverId, duration: $duration) {
- heap
- maxHeap
- noheap
- maxNoheap
- }
-}
-`;
-
-export default generateModal({
- namespace: 'application',
- state: {
- allApplication: [],
- getSlowService: [],
- getServerThroughput: [],
- getApplicationTopology: {
- nodes: [],
- calls: [],
- },
- showServer: false,
- serverInfo: {},
- getServerResponseTimeTrend: {
- trendList: [],
- },
- getServerThroughputTrend: {
- trendList: [],
- },
- getCPUTrend: {
- cost: [],
- },
- getMemoryTrend: {
- heap: [],
- maxHeap: [],
- noheap: [],
- maxNoheap: [],
- },
- getGCTrend: {
- youngGCCount: [],
- oldGCount: [],
- youngGCTime: [],
- oldGCTime: [],
- },
- },
- optionsQuery,
- dataQuery,
- effects: {
- *fetchServer({ payload }, { call, put }) {
- const { variables, serverInfo } = payload;
- const response = yield call(queryService, 'server', { variables, query: serverQuery });
- if (!response.data) {
- return;
- }
- yield put({
- type: 'saveServer',
- payload: response.data,
- serverInfo,
- });
- },
- },
- reducers: {
- saveApplication(preState, { payload }) {
- const { data } = preState;
- return {
- ...preState,
- data: {
- ...data,
- ...payload,
- serverInfo: {},
- getServerResponseTimeTrend: {
- trendList: [],
- },
- getServerThroughputTrend: {
- trendList: [],
- },
- getCPUTrend: {
- cost: [],
- },
- getMemoryTrend: {
- heap: [],
- maxHeap: [],
- noheap: [],
- maxNoheap: [],
- },
- getGCTrend: {
- youngGCCount: [],
- oldGCount: [],
- youngGCTime: [],
- oldGCTime: [],
- },
- },
- };
- },
- saveServer(preState, { payload, serverInfo }) {
- const { data } = preState;
- return {
- ...preState,
- data: {
- ...data,
- serverInfo,
- ...payload,
- },
- };
- },
- showServer(preState) {
- const { data } = preState;
- return {
- ...preState,
- data: {
- ...data,
- showServer: true,
- },
- };
- },
- hideServer(preState) {
- const { data } = preState;
- return {
- ...preState,
- data: {
- ...data,
- showServer: false,
- },
- };
- },
- },
- subscriptions: {
- setup({ history, dispatch }) {
- return history.listen(({ pathname, state }) => {
- if (pathname === '/monitor/application' && state) {
- dispatch({
- type: 'saveVariables',
- payload: {
- values: {
- applicationId: `${state.key}`,
- },
- labels: {
- applicationId: state.label,
- },
- },
- });
- }
- });
- },
- },
-});
diff --git a/src/models/service.js b/src/models/service.js
new file mode 100644
index 0000000..6cb391b
--- /dev/null
+++ b/src/models/service.js
@@ -0,0 +1,333 @@
+/**
+ * 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.
+ */
+
+
+import { base } from '../utils/models';
+import { exec } from '../services/graphql';
+
+const optionsQuery = `
+ query ServiceOption($duration: Duration!) {
+ serviceId: getAllServices(duration: $duration) {
+ key: id
+ label: name
+ }
+ }
+`;
+
+const dataQuery = `
+ query Service($serviceId: ID!, $duration: Duration!) {
+ getSlowEndpoint: getTopN(duration: $duration, condition: {
+ name: "slowEndpoint",
+ topN: 10,
+ order: DES,
+ filterScope: ENDPOINT,
+ filterId: $serviceId
+ }) {
+ key: id
+ label: name
+ value
+ }
+ getServiceInstanceThroughput: getTopN(duration: $duration, condition: {
+ name: "serviceInstanceThroughtput",
+ topN: 10,
+ order: DES,
+ filterScope: SERVICE_INSTANCE,
+ filterId: $serviceId
+ }) {
+ key: id
+ label: name
+ value
+ }
+ getServiceInstances(duration: $duration, id: $serviceId) {
+ key: id
+ name
+ attributes {
+ name
+ value
+ }
+ language
+ }
+ getServiceTopology(serviceId: $serviceId, duration: $duration) {
+ nodes {
+ id
+ name
+ type
+ isReal
+ }
+ calls {
+ source
+ target
+ callType
+ cpm
+ }
+ }
+ }
+`;
+
+const serviceInstanceQuery = `
+query ServiceInstance($serviceInstanceId: ID!, $duration: Duration!) {
+ getServiceInstanceResponseTimeTrend: getLinearIntValues(metric: {
+ name: "serviceInstanceResponseTimeTrend"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ getServiceInstanceThroughputTrend: getLinearIntValues(metric: {
+ name: "serviceInstanceThroughputTrend"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ getCPUTrend: getLinearIntValues(metric: {
+ name: "CPUTrend"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ youngGCCount: getLinearIntValues(metric: {
+ name: "youngGCCount"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ oldGCCount: getLinearIntValues(metric: {
+ name: "oldGCCount"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ youngGCTime: getLinearIntValues(metric: {
+ name: "youngGCTime"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ oldGCTime: getLinearIntValues(metric: {
+ name: "oldGCTime"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ heap: getLinearIntValues(metric: {
+ name: "heap"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ maxHeap: getLinearIntValues(metric: {
+ name: "maxHeap"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ noheap: getLinearIntValues(metric: {
+ name: "noheap"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+ maxNoheap: getLinearIntValues(metric: {
+ name: "maxNoheap"
+ id: $serviceInstanceId
+ }, duration: $duration) {
+ values {
+ value
+ }
+ }
+}
+`;
+
+export default base({
+ namespace: 'service',
+ state: {
+ allService: [],
+ getSlowEndpoint: [],
+ getServiceInstanceThroughput: [],
+ getServiceTopology: {
+ nodes: [],
+ calls: [],
+ },
+ getServiceInstances: [],
+ showServiceInstance: false,
+ serviceInstanceInfo: {},
+ getServiceInstanceResponseTimeTrend: {
+ values: [],
+ },
+ getServiceInstanceThroughputTrend: {
+ values: [],
+ },
+ getCPUTrend: {
+ values: [],
+ },
+ heap: {
+ values: [],
+ },
+ maxHeap: {
+ values: [],
+ },
+ noheap: {
+ values: [],
+ },
+ maxNoheap: {
+ values: [],
+ },
+ youngGCCount: {
+ values: [],
+ },
+ oldGCCount: {
+ values: [],
+ },
+ youngGCTime: {
+ values: [],
+ },
+ oldGCTime: {
+ values: [],
+ },
+ },
+ optionsQuery,
+ dataQuery,
+ effects: {
+ *fetchServiceInstance({ payload }, { call, put }) {
+ const { variables, serviceInstanceInfo } = payload;
+ const response = yield call(exec, { variables, query: serviceInstanceQuery });
+ if (!response.data) {
+ return;
+ }
+ yield put({
+ type: 'saveServiceInstance',
+ payload: response.data,
+ serviceInstanceInfo,
+ });
+ },
+ },
+ reducers: {
+ saveService(preState, { payload }) {
+ const { data } = preState;
+ return {
+ ...preState,
+ data: {
+ ...data,
+ ...payload,
+ serviceInstanceInfo: {},
+ getServiceInstanceResponseTimeTrend: {
+ values: [],
+ },
+ getServiceInstanceThroughputTrend: {
+ values: [],
+ },
+ getCPUTrend: {
+ values: [],
+ },
+ heap: {
+ values: [],
+ },
+ maxHeap: {
+ values: [],
+ },
+ noheap: {
+ values: [],
+ },
+ maxNoheap: {
+ values: [],
+ },
+ youngGCCount: {
+ values: [],
+ },
+ oldGCCount: {
+ values: [],
+ },
+ youngGCTime: {
+ values: [],
+ },
+ oldGCTime: {
+ values: [],
+ },
+ },
+ };
+ },
+ saveServiceInstance(preState, { payload, serviceInstanceInfo }) {
+ const { data } = preState;
+ return {
+ ...preState,
+ data: {
+ ...data,
+ serviceInstanceInfo,
+ ...payload,
+ },
+ };
+ },
+ showServiceInstance(preState) {
+ const { data } = preState;
+ return {
+ ...preState,
+ data: {
+ ...data,
+ showServiceInstance: true,
+ },
+ };
+ },
+ hideServiceInstance(preState) {
+ const { data } = preState;
+ return {
+ ...preState,
+ data: {
+ ...data,
+ showServiceInstance: false,
+ },
+ };
+ },
+ },
+ subscriptions: {
+ setup({ history, dispatch }) {
+ return history.listen(({ pathname, state }) => {
+ if (pathname === '/monitor/service' && state) {
+ dispatch({
+ type: 'saveVariables',
+ payload: {
+ values: {
+ serviceId: `${state.key}`,
+ },
+ labels: {
+ serviceId: state.label,
+ },
+ },
+ });
+ }
+ });
+ },
+ },
+});
diff --git a/src/routes/Application/Application.js b/src/routes/Application/Application.js
deleted file mode 100644
index 5281f54..0000000
--- a/src/routes/Application/Application.js
+++ /dev/null
@@ -1,257 +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
- *
- * 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.
- */
-
-
-import React, { PureComponent } from 'react';
-import { connect } from 'dva';
-import { Row, Col, Select, Card, Form, Breadcrumb } from 'antd';
-import Server from './Server';
-import { AppTopology } from '../../components/Topology';
-import { Panel } from '../../components/Page';
-import RankList from '../../components/RankList';
-import ServerLitePanel from '../../components/ServerLitePanel';
-import { getServerId, redirect } from '../../utils/utils';
-
-const { Option } = Select;
-const { Item: FormItem } = Form;
-
-const middleColResponsiveProps = {
- xs: 24,
- sm: 24,
- md: 12,
- lg: 12,
- xl: 12,
- style: { marginTop: 8 },
-};
-
-@connect(state => ({
- application: state.application,
- duration: state.global.duration,
- globalVariables: state.global.globalVariables,
-}))
-@Form.create({
- mapPropsToFields(props) {
- const { variables: { values, labels } } = props.application;
- return {
- applicationId: Form.createFormField({
- value: { key: values.applicationId ? values.applicationId : '', label: labels.applicationId ? labels.applicationId : '' },
- }),
- };
- },
-})
-export default class Application extends PureComponent {
- componentDidMount() {
- this.props.dispatch({
- type: 'application/initOptions',
- payload: { variables: this.props.globalVariables },
- });
- }
-
- componentWillUpdate(nextProps) {
- if (nextProps.globalVariables.duration === this.props.globalVariables.duration) {
- return;
- }
- this.props.dispatch({
- type: 'application/initOptions',
- payload: { variables: nextProps.globalVariables },
- });
- }
-
- handleSelect = (selected) => {
- this.props.dispatch({
- type: 'application/saveVariables',
- payload: {
- values: { applicationId: selected.key },
- labels: { applicationId: selected.label },
- },
- });
- }
-
- handleChange = (variables) => {
- const { data: { serverInfo, showServer } } = this.props.application;
- if (showServer) {
- this.handleSelectServer(serverInfo.key, serverInfo);
- } else {
- this.props.dispatch({
- type: 'application/fetchData',
- payload: { variables, reducer: 'saveApplication' },
- });
- }
- }
-
- handleGoApplication = () => {
- this.props.dispatch({
- type: 'application/hideServer',
- });
- }
-
- handleGoServer = () => {
- this.props.dispatch({
- type: 'application/showServer',
- });
- }
-
- handleSelectServer = (serverId, serverInfo) => {
- const { globalVariables: { duration } } = this.props;
- this.props.dispatch({
- type: 'application/fetchServer',
- payload: { variables: { duration, serverId }, serverInfo },
- });
- }
-
- renderApp = () => {
- const { getFieldDecorator } = this.props.form;
- const { variables: { values, options }, data } = this.props.application;
- return (
- <div>
- <Form layout="inline">
- <FormItem>
- {getFieldDecorator('applicationId')(
- <Select
- showSearch
- optionFilterProp="children"
- style={{ width: 200 }}
- placeholder="Select a application"
- labelInValue
- onSelect={this.handleSelect.bind(this)}
- >
- {options.applicationId && options.applicationId.map(app =>
- <Option key={app.key} value={app.key}>{app.label}</Option>)}
- </Select>
- )}
- </FormItem>
- </Form>
- <Panel
- variables={values}
- globalVariables={this.props.globalVariables}
- onChange={this.handleChange}
- >
- <Row gutter={0}>
- <Col {...{ ...middleColResponsiveProps, xl: 16, lg: 12, md: 24 }}>
- <Card
- title="Application Map"
- bordered={false}
- bodyStyle={{ padding: 0 }}
- >
- <AppTopology
- elements={data.getApplicationTopology}
- height={335}
- layout={{
- name: 'dagre',
- rankDir: 'LR',
- minLen: 4,
- }}
- />
- </Card>
- </Col>
- <Col {...{ ...middleColResponsiveProps, xl: 8, lg: 12, md: 24 }}>
- <Card
- bordered={false}
- bodyStyle={{ padding: '10px 10px', height: 391 }}
- >
- <ServerLitePanel
- data={data}
- serverList={data.getServerThroughput}
- duration={this.props.duration}
- onSelectServer={this.handleSelectServer}
- onMoreServer={this.handleGoServer}
- />
- </Card>
- </Col>
- </Row>
- <Row gutter={8}>
- <Col {...{ ...middleColResponsiveProps, xl: 12, lg: 12, md: 24 }}>
- <Card
- title="Running Server"
- bordered={false}
- bodyStyle={{ padding: 5 }}
- >
- <RankList
- data={data.getServerThroughput}
- renderLabel={getServerId}
- renderValue={_ => `${_.value} cpm`}
- renderBadge={_ => ([
- {
- key: 'host',
- label: 'Host',
- value: _.host,
- },
- {
- key: 'os',
- label: 'OS',
- value: _.osName,
- },
- ])}
- color="#965fe466"
- />
- </Card>
- </Col>
- <Col {...{ ...middleColResponsiveProps, xl: 12, lg: 12, md: 24 }}>
- <Card
- title="Slow Service"
- bordered={false}
- bodyStyle={{ padding: '0px 10px' }}
- >
- <RankList
- data={data.getSlowService.map(_ => ({ ..._.service, value: _.value }))}
- renderValue={_ => `${_.value} ms`}
- onClick={(key, item) => redirect(this.props.history, '/monitor/service', { key,
- label: item.label,
- applicationId: item.applicationId,
- applicationName: item.applicationName })}
- />
- </Card>
- </Col>
- </Row>
- </Panel>
- </div>
- );
- }
-
- render() {
- const { application, duration } = this.props;
- const { variables, data } = application;
- const { showServer, serverInfo } = data;
- return (
- <Row type="flex" justify="start">
- {showServer ? (
- <Col span={showServer ? 24 : 0}>
- <Breadcrumb>
- <Breadcrumb.Item>
- Application
- </Breadcrumb.Item>
- <Breadcrumb.Item>
- <a onClick={this.handleGoApplication}>{variables.labels.applicationId}</a>
- </Breadcrumb.Item>
- <Breadcrumb.Item>{getServerId(serverInfo)}</Breadcrumb.Item>
- </Breadcrumb>
- <Panel
- variables={variables.values}
- globalVariables={this.props.globalVariables}
- onChange={this.handleChange}
- >
- <Server data={data} duration={duration} />
- </Panel>
- </Col>
- ) : null}
- <Col span={showServer ? 0 : 24}>
- {this.renderApp()}
- </Col>
- </Row>
- );
- }
-}
diff --git a/src/routes/Service/Service.js b/src/routes/Service/Service.js
new file mode 100644
index 0000000..07985b9
--- /dev/null
+++ b/src/routes/Service/Service.js
@@ -0,0 +1,244 @@
+/**
+ * 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.
+ */
+
+
+import React, { PureComponent } from 'react';
+import { connect } from 'dva';
+import { Row, Col, Select, Card, Form, Breadcrumb } from 'antd';
+import { AppTopology } from 'components/Topology';
+import { Panel } from 'components/Page';
+import RankList from 'components/RankList';
+import ServiceInstanceLitePanel from 'components/ServiceInstanceLitePanel';
+import ServiceInstance from './ServiceInstance';
+import { getServiceInstanceId, redirect } from '../../utils/utils';
+
+const { Option } = Select;
+const { Item: FormItem } = Form;
+
+const middleColResponsiveProps = {
+ xs: 24,
+ sm: 24,
+ md: 12,
+ lg: 12,
+ xl: 12,
+ style: { marginTop: 8 },
+};
+
+@connect(state => ({
+ service: state.service,
+ duration: state.global.duration,
+ globalVariables: state.global.globalVariables,
+}))
+@Form.create({
+ mapPropsToFields(props) {
+ const { variables: { values, labels } } = props.service;
+ return {
+ serviceId: Form.createFormField({
+ value: { key: values.serviceId ? values.serviceId : '', label: labels.serviceId ? labels.serviceId : '' },
+ }),
+ };
+ },
+})
+export default class Service extends PureComponent {
+ componentDidMount() {
+ this.props.dispatch({
+ type: 'service/initOptions',
+ payload: { variables: this.props.globalVariables },
+ });
+ }
+
+ componentWillUpdate(nextProps) {
+ if (nextProps.globalVariables.duration === this.props.globalVariables.duration) {
+ return;
+ }
+ this.props.dispatch({
+ type: 'service/initOptions',
+ payload: { variables: nextProps.globalVariables },
+ });
+ }
+
+ handleSelect = (selected) => {
+ this.props.dispatch({
+ type: 'service/saveVariables',
+ payload: {
+ values: { serviceId: selected.key },
+ labels: { serviceId: selected.label },
+ },
+ });
+ }
+
+ handleChange = (variables) => {
+ const { data: { serviceInstanceInfo, showServiceInstance } } = this.props.service;
+ if (showServiceInstance) {
+ this.handleSelectServiceInstance(serviceInstanceInfo.key, serviceInstanceInfo);
+ } else {
+ this.props.dispatch({
+ type: 'service/fetchData',
+ payload: { variables, reducer: 'saveService' },
+ });
+ }
+ }
+
+ handleGoService = () => {
+ this.props.dispatch({
+ type: 'service/hideServiceInstance',
+ });
+ }
+
+ handleGoServiceInstance = () => {
+ this.props.dispatch({
+ type: 'service/showServiceInstance',
+ });
+ }
+
+ handleSelectServiceInstance = (serviceInstanceId, serviceInstanceInfo) => {
+ const { globalVariables: { duration } } = this.props;
+ this.props.dispatch({
+ type: 'service/fetchServiceInstance',
+ payload: { variables: { duration, serviceInstanceId }, serviceInstanceInfo },
+ });
+ }
+
+ renderApp = () => {
+ const { getFieldDecorator } = this.props.form;
+ const { variables: { values, options, labels }, data } = this.props.service;
+ return (
+ <div>
+ <Form layout="inline">
+ <FormItem>
+ {getFieldDecorator('serviceId')(
+ <Select
+ showSearch
+ optionFilterProp="children"
+ style={{ width: 200 }}
+ placeholder="Select a service"
+ labelInValue
+ onSelect={this.handleSelect.bind(this)}
+ >
+ {options.serviceId && options.serviceId.map(service =>
+ <Option key={service.key} value={service.key}>{service.label}</Option>)}
+ </Select>
+ )}
+ </FormItem>
+ </Form>
+ <Panel
+ variables={values}
+ globalVariables={this.props.globalVariables}
+ onChange={this.handleChange}
+ >
+ <Row gutter={0}>
+ <Col {...{ ...middleColResponsiveProps, xl: 16, lg: 12, md: 24 }}>
+ <Card
+ title="Service Map"
+ bordered={false}
+ bodyStyle={{ padding: 0 }}
+ >
+ <AppTopology
+ elements={data.getServiceTopology}
+ height={335}
+ layout={{
+ name: 'dagre',
+ rankDir: 'LR',
+ minLen: 4,
+ }}
+ />
+ </Card>
+ </Col>
+ <Col {...{ ...middleColResponsiveProps, xl: 8, lg: 12, md: 24 }}>
+ <Card
+ bordered={false}
+ bodyStyle={{ padding: '10px 10px', height: 391 }}
+ >
+ <ServiceInstanceLitePanel
+ data={data}
+ serviceInstanceList={data.getServiceInstances}
+ duration={this.props.duration}
+ onSelectServiceInstance={this.handleSelectServiceInstance}
+ onMoreServiceInstance={this.handleGoServiceInstance}
+ />
+ </Card>
+ </Col>
+ </Row>
+ <Row gutter={8}>
+ <Col {...{ ...middleColResponsiveProps, xl: 12, lg: 12, md: 24 }}>
+ <Card
+ title="Running ServiceInstance"
+ bordered={false}
+ bodyStyle={{ padding: 5 }}
+ >
+ <RankList
+ data={data.getServiceInstanceThroughput}
+ renderValue={_ => `${_.value} cpm`}
+ color="#965fe466"
+ />
+ </Card>
+ </Col>
+ <Col {...{ ...middleColResponsiveProps, xl: 12, lg: 12, md: 24 }}>
+ <Card
+ title="Slow Endpoint"
+ bordered={false}
+ bodyStyle={{ padding: '0px 10px' }}
+ >
+ <RankList
+ data={data.getSlowEndpoint}
+ renderValue={_ => `${_.value} ms`}
+ onClick={(key, item) => redirect(this.props.history, '/monitor/endpoint', { key,
+ label: item.label,
+ serviceId: values.serviceId,
+ serviceName: labels.serviceId })}
+ />
+ </Card>
+ </Col>
+ </Row>
+ </Panel>
+ </div>
+ );
+ }
+
+ render() {
+ const { service, duration } = this.props;
+ const { variables, data } = service;
+ const { showServiceInstance, serviceInstanceInfo } = data;
+ return (
+ <Row type="flex" justify="start">
+ {showServiceInstance ? (
+ <Col span={showServiceInstance ? 24 : 0}>
+ <Breadcrumb>
+ <Breadcrumb.Item>
+ Service
+ </Breadcrumb.Item>
+ <Breadcrumb.Item>
+ <a onClick={this.handleGoService}>{variables.labels.serviceId}</a>
+ </Breadcrumb.Item>
+ <Breadcrumb.Item>{getServiceInstanceId(serviceInstanceInfo)}</Breadcrumb.Item>
+ </Breadcrumb>
+ <Panel
+ variables={variables.values}
+ globalVariables={this.props.globalVariables}
+ onChange={this.handleChange}
+ >
+ <ServiceInstance data={data} duration={duration} />
+ </Panel>
+ </Col>
+ ) : null}
+ <Col span={showServiceInstance ? 0 : 24}>
+ {this.renderApp()}
+ </Col>
+ </Row>
+ );
+ }
+}
diff --git a/src/routes/Application/Application.less b/src/routes/Service/Service.less
similarity index 100%
rename from src/routes/Application/Application.less
rename to src/routes/Service/Service.less
diff --git a/src/routes/Application/Server.js b/src/routes/Service/ServiceInstance.js
similarity index 63%
rename from src/routes/Application/Server.js
rename to src/routes/Service/ServiceInstance.js
index f3945ce..fa1cdd2 100644
--- a/src/routes/Application/Server.js
+++ b/src/routes/Service/ServiceInstance.js
@@ -20,31 +20,32 @@
import { Row, Col, Card, Tag } from 'antd';
import {
ChartCard, MiniArea, MiniBar, Line, Area, StackBar,
-} from '../../components/Charts';
-import DescriptionList from '../../components/DescriptionList';
-import { axis } from '../../utils/time';
-import { avgTimeSeries } from '../../utils/utils';
+} from 'components/Charts';
+import DescriptionList from 'components/DescriptionList';
+import { axisY } from '../../utils/time';
+import { avgTS, getAttributes } from '../../utils/utils';
const { Description } = DescriptionList;
-export default class Server extends PureComponent {
- bytesToMB = list => list.map(_ => parseFloat((_ / (1024 ** 2)).toFixed(2)))
+export default class ServiceInstance extends PureComponent {
+ bytesToMB = list => list.map(_ => ({ value: parseFloat((_.value / (1024 ** 2)).toFixed(2))}))
render() {
const { duration, data } = this.props;
- const { serverInfo, getServerResponseTimeTrend, getServerThroughputTrend,
- getCPUTrend, getMemoryTrend, getGCTrend } = data;
+ const { serviceInstanceInfo, getServiceInstanceResponseTimeTrend, getServiceInstanceThroughputTrend,
+ getCPUTrend, heap, maxHeap, noheap, maxNoheap, youngGCCount, oldGCCount, youngGCTime, oldGCTime } = data;
+ const { attributes } = serviceInstanceInfo;
return (
<div>
<Row gutter={8}>
<Col xs={24} sm={24} md={24} lg={6} xl={6} style={{ marginTop: 8 }}>
<Card style={{ marginTop: 8 }} bordered={false}>
<DescriptionList col={1} layout="vertical">
- <Description term="Host">{serverInfo.host}</Description>
- <Description term="IPv4">{serverInfo.ipv4 ? serverInfo.ipv4.join() : ''}</Description>
- <Description term="Pid">{serverInfo.pid}</Description>
- <Description term="OS">{serverInfo.osName}</Description>
+ <Description term="Host">{getAttributes(attributes, 'host')}</Description>
+ <Description term="IPv4">{getAttributes(attributes, 'ipv4')}</Description>
+ <Description term="Pid">{getAttributes(attributes, 'pid')}</Description>
+ <Description term="OS">{getAttributes(attributes, 'os')}</Description>
</DescriptionList>
</Card>
</Col>
@@ -53,24 +54,24 @@
<Col xs={24} sm={24} md={24} lg={12} xl={12} style={{ marginTop: 8 }}>
<ChartCard
title="Avg Throughput"
- total={`${avgTimeSeries(getServerThroughputTrend.trendList)} cpm`}
+ total={`${avgTS(getServiceInstanceThroughputTrend.values)} cpm`}
contentHeight={46}
>
<MiniBar
color="#975FE4"
- data={axis(duration, getServerThroughputTrend.trendList)}
+ data={axisY(duration, getServiceInstanceThroughputTrend.values)}
/>
</ChartCard>
</Col>
<Col xs={24} sm={24} md={24} lg={12} xl={12} style={{ marginTop: 8 }}>
<ChartCard
title="Avg Response Time"
- total={`${avgTimeSeries(getServerResponseTimeTrend.trendList)} ms`}
+ total={`${avgTS(getServiceInstanceResponseTimeTrend.values)} ms`}
contentHeight={46}
>
- {getServerResponseTimeTrend.trendList.length > 0 ? (
+ {getServiceInstanceResponseTimeTrend.values.length > 0 ? (
<MiniArea
- data={axis(duration, getServerResponseTimeTrend.trendList)}
+ data={axisY(duration, getServiceInstanceResponseTimeTrend.values)}
/>
) : (<span style={{ display: 'none' }} />)}
</ChartCard>
@@ -83,7 +84,7 @@
contentHeight={150}
>
<Line
- data={axis(duration, getCPUTrend.cost)}
+ data={axisY(duration, getCPUTrend.values)}
/>
</ChartCard>
</Col>
@@ -95,8 +96,8 @@
contentHeight={150}
>
<Area
- data={axis(duration, this.bytesToMB(getMemoryTrend.heap), ({ x, y }) => ({ x, y, type: 'value' }))
- .concat(axis(duration, this.bytesToMB(getMemoryTrend.maxHeap), ({ x, y }) => ({ x, y, type: 'free' })))}
+ data={axisY(duration, this.bytesToMB(heap.values), ({ x, y }) => ({ x, y, type: 'value' }))
+ .concat(axisY(duration, this.bytesToMB(maxHeap.values), ({ x, y }) => ({ x, y, type: 'free' })))}
/>
</ChartCard>
</Col>
@@ -106,8 +107,8 @@
contentHeight={150}
>
<Area
- data={axis(duration, this.bytesToMB(getMemoryTrend.noheap), ({ x, y }) => ({ x, y, type: 'value' }))
- .concat(axis(duration, this.bytesToMB(getMemoryTrend.maxNoheap), ({ x, y }) => ({ x, y, type: 'free' })))}
+ data={axisY(duration, this.bytesToMB(noheap.values), ({ x, y }) => ({ x, y, type: 'value' }))
+ .concat(axisY(duration, this.bytesToMB(maxNoheap.values), ({ x, y }) => ({ x, y, type: 'free' })))}
/>
</ChartCard>
</Col>
@@ -122,14 +123,14 @@
<div style={{ marginBottom: 10 }}>
<span style={{ marginRight: 10 }}>Young GC</span>
<Tag color="#66b5ff">
- {getGCTrend.youngGCCount.reduce((sum, v) => sum + v)}
+ {youngGCCount.values.map(_ => _.value).reduce((sum, v) => sum + v)}
</Tag>
<span>collections</span>
</div>
<div>
<span style={{ marginRight: 10 }}>Old GC</span>
<Tag color="#ffb566">
- {getGCTrend.oldGCount.reduce((sum, v) => sum + v)}
+ {oldGCCount.values.map(_ => _.value).reduce((sum, v) => sum + v)}
</Tag>
<span>collections</span>
</div>
@@ -137,8 +138,8 @@
}
>
<StackBar
- data={axis(duration, getGCTrend.youngGCTime, ({ x, y }) => ({ x, y, type: 'youngGCTime' }))
- .concat(axis(duration, getGCTrend.oldGCTime, ({ x, y }) => ({ x, y, type: 'oldGCTime' })))}
+ data={axisY(duration, youngGCTime.values, ({ x, y }) => ({ x, y, type: 'youngGCTime' }))
+ .concat(axisY(duration, oldGCTime.values, ({ x, y }) => ({ x, y, type: 'oldGCTime' })))}
/>
</ChartCard>
</Col>
diff --git a/src/utils/utils.js b/src/utils/utils.js
index d6c4e3b..130dd1c 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -114,12 +114,25 @@
return reg.test(path);
}
-export function getServerId(serverInfo) {
- let { host } = serverInfo;
- if (serverInfo.ipv4 && serverInfo.ipv4.length > 0) {
- [host] = serverInfo.ipv4;
+export function getServiceInstanceId(serviceInstanceInfo) {
+ const { attributes } = serviceInstanceInfo;
+ if (!attributes || attributes.length < 1) {
+ return '';
}
- return `${serverInfo.pid}@${host}`;
+ let host = getAttributes(attributes, 'host');
+ const ipv4 = getAttributes(attributes, 'ipv4');
+ if (ipv4 && ipv4.length > 0) {
+ [host] = ipv4;
+ }
+ return `${getAttributes(attributes, 'pid')}@${host}`;
+}
+
+export function getAttributes(attributes, name) {
+ if (!attributes || attributes.length < 1) {
+ return '';
+ }
+ const a = attributes.find(_ => _.name === name);
+ return a ? a.value : '';
}
export function redirect(history, pathname, param) {